#if !defined(__BUTTONEDIT_H_)
#define __BUTTONEDIT_H_
#pragma once
#include "messagehook.h"
#define BEM_BASE 0x0210
#define BEM_BROWSE BEM_BASE + 0
namespace codeproject
{
template<class TEdit = CEdit>
class CButtonEditImplCCtrlT : public CWindowImpl<CButtonEditImplCCtrlT, TEdit>
{
public:
typedef CButtonEditImplCCtrlT thisClass;
typedef CWindowImpl<CButtonEditImplCCtrlT, TEdit> baseClass;
BEGIN_MSG_MAP(thisClass)
MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
MESSAGE_HANDLER(WM_SIZE, OnSize)
MESSAGE_HANDLER(EM_SETMARGINS, OnSetMargins)
MESSAGE_HANDLER(EM_SETRECT, OnSetRect)
MESSAGE_HANDLER(EM_SETRECTNP, OnSetRectNP)
COMMAND_CODE_HANDLER(BN_CLICKED, OnButtonNotifyClicked)
END_MSG_MAP()
protected:
CButton m_wndInButton;
RECT m_rcButton;
BOOL m_bHideButton;
UINT m_nButtonWidht;
class XButtonFocusManagerHook : public CMessageHook<XButtonFocusManagerHook>
{
public:
XButtonFocusManagerHook() : CMessageHook<XButtonFocusManagerHook>(TRUE)
{
}
protected:
virtual BOOL ProcessWindowMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT &lResult)
{
BOOL bHandled = FALSE;
switch(uMsg)
{
case WM_SETFOCUS:
case WM_KILLFOCUS:
bHandled = TRUE;
lResult = DefWindowProc(uMsg, wParam, lParam);
if(::GetParent(GetHwnd()) != (HWND)wParam)
::SendMessage(::GetParent(GetHwnd()), uMsg, wParam, lParam);
break;
}
return bHandled;
}
};
public:
// c'tor
CButtonEditImplCCtrlT() : m_bHideButton(FALSE), m_nButtonWidht(3 * ::GetSystemMetrics(SM_CXVSCROLL) / 2)
{
}
// d'tor
virtual ~CButtonEditImplCCtrlT()
{
}
// properties
void HideButton(BOOL bHide)
{
if(!IsWindow())
{
m_bHideButton = bHide;
return;
}
if(bHide)
{
if(!m_bHideButton)
{
// remove the space for the button
UINT nDefRMargin = HIWORD((DWORD)DefWindowProc(EM_GETMARGINS, 0, 0L));
DefWindowProc(EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, nDefRMargin - m_nButtonWidht));
}
}
else
{
if(m_bHideButton)
{
// reserve the space for the button
UINT nDefRMargin = HIWORD((DWORD)DefWindowProc(EM_GETMARGINS, 0, 0L));
DefWindowProc(EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, nDefRMargin + m_nButtonWidht));
}
if(!m_wndInButton.IsWindow())
{
m_wndInButton.Create(m_hWnd, &rcDefault, NULL, WS_CHILD | BS_PUSHBUTTON | BS_NOTIFY);
ATLASSERT(m_wndInButton.IsWindow());
m_wndInButton.SetFont((HFONT)::SendMessage(GetParent(), WM_GETFONT, 0, 0L));
m_wndInButton.SetWindowText(_T("..."));
XButtonFocusManagerHook *pHook = new XButtonFocusManagerHook;
pHook->Hook(m_wndInButton);
}
}
m_bHideButton = bHide;
UpdateButton();
}
// operations
HWND Create(HWND hwndParent, RECT& rcPos, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
{
ATLASSERT(NULL == m_hWnd);
CEdit wndEditTemp;
HWND hWnd = wndEditTemp.Create(hwndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
wndEditTemp.Detach();
// HWND hWnd = baseClass::Create(hwndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
if(hWnd)
SubclassWindow(hWnd);
return hWnd;
}
BOOL SubclassWindow(HWND hWnd)
{
if(!m_bHideButton)
{
// reserve the space for the button
UINT nDefRMargin = HIWORD((DWORD)::SendMessage(hWnd, EM_GETMARGINS, 0, 0L));
::SendMessage(hWnd, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, nDefRMargin + m_nButtonWidht));
}
BOOL bRet = baseClass::SubclassWindow(hWnd);
LONG lStyle = GetStyle();
SetWindowLong(GWL_STYLE, lStyle | WS_CLIPCHILDREN);
if(!m_bHideButton && !m_wndInButton.IsWindow())
{
const DWORD dwStyle = WS_CHILD | BS_PUSHBUTTON | BS_NOTIFY;
m_wndInButton.Create(m_hWnd, &rcDefault, NULL, m_bHideButton ? dwStyle : dwStyle | WS_VISIBLE);
ATLASSERT(m_wndInButton.IsWindow());
m_wndInButton.SetFont((HFONT)::SendMessage(GetParent(), WM_GETFONT, 0, 0L));
m_wndInButton.SetWindowText(_T("..."));
XButtonFocusManagerHook *pHook = new XButtonFocusManagerHook;
pHook->Hook(m_wndInButton);
}
UpdateButton();
return bRet;
}
HWND UnsubclassWindow(BOOL bForce = FALSE)
{
if(m_wndInButton.IsWindow())
m_wndInButton.DestroyWindow();
HWND hWnd = baseClass::UnsubclassWindow(bForce);
if(!m_bHideButton)
{
// remove the space for the button
UINT nDefRMargin = HIWORD((DWORD)::SendMessage(hWnd, EM_GETMARGINS, 0, 0L));
::SendMessage(hWnd, EM_SETMARGINS, EC_RIGHTMARGIN, MAKELONG(0, nDefRMargin - m_nButtonWidht));
::InvalidateRect(hWnd, &m_rcButton, TRUE);
}
return hWnd;
}
// Implementations
protected:
LRESULT OnButtonNotifyClicked(WORD wNotifyCode, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
wNotifyCode;
ATLASSERT(BN_CLICKED == wNotifyCode);
::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
return 0;
}
LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &/*bHandled*/)
{
ATLASSERT(WM_NCHITTEST == uMsg);
LRESULT lRes = DefWindowProc(uMsg, wParam, lParam);
if(!m_bHideButton && HTCLIENT == lRes)
{
POINT ptHit = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
ScreenToClient(&ptHit);
if(::PtInRect(&m_rcButton, ptHit))
return HTTRANSPARENT;
}
return lRes;
}
LRESULT OnSize(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL &bHandled)
{
uMsg;
ATLASSERT(WM_SIZE == uMsg);
UpdateButton();
bHandled = FALSE;
return 0;
}
LRESULT OnSetMargins(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &/*bHandled*/)
{
ATLASSERT(EM_SETMARGINS == uMsg);
if(EC_LEFTMARGIN | wParam)
{
UINT nLMargin = LOWORD(lParam), nRMargin = LOWORD(lParam);
if(m_nButtonWidht > nRMargin)
{
ATLTRACE(_T("\nCButtonEditImplCCtrlT::OnSetMargins(): the right margin is changed to %d in order to reserve the space for button.\n\n"), m_nButtonWidht);
nRMargin = m_nButtonWidht;
}
lParam = (LPARAM)MAKELONG(nLMargin, nRMargin);
}
return DefWindowProc(uMsg, wParam, lParam);
}
LRESULT OnSetRect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &/*bHandled*/)
{
ATLASSERT(EM_SETRECT == uMsg);
LPRECT prcFmt = (LPRECT)lParam;
if(m_nButtonWidht > (UINT)prcFmt->left)
{
ATLTRACE(_T("\nCButtonEditImplCCtrlT::OnSetRect(): the right of formatting rectangle is changed to %d in order to reserve the space for drawing icon.\n\n"), m_nButtonWidht);
prcFmt->right -= m_nButtonWidht;
}
return DefWindowProc(uMsg, wParam, lParam);
}
LRESULT OnSetRectNP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &/*bHandled*/)
{
ATLASSERT(EM_SETRECTNP == uMsg);
LPRECT prcFmt = (LPRECT)lParam;
if(m_nButtonWidht > (UINT)prcFmt->left)
{
ATLTRACE(_T("\nCButtonEditImplCCtrlT::OnSetRectNP(): the right of formatting rectangle is changed to %d in order to reserve the space for drawing icon.\n\n"), m_nButtonWidht);
prcFmt->right -= m_nButtonWidht;
}
return DefWindowProc(uMsg, wParam, lParam);
}
void UpdateButton()
{
ATLASSERT(IsWindow());
if(m_wndInButton.IsWindow())
{
if(m_bHideButton)
{
m_wndInButton.ShowWindow(SW_HIDE);
InvalidateRect(&m_rcButton, TRUE);
}
else
{
RECT rcWindow;
GetWindowRect(&rcWindow);
RECT rcButton;
GetClientRect(&rcButton);
rcButton.left = rcButton.right - m_nButtonWidht;
int cyBorder = ((rcWindow.bottom - rcWindow.top) - (rcButton.bottom - rcButton.top)) / 2;
int cyEdge = ::GetSystemMetrics(SM_CYEDGE);
if(cyEdge - 1 < cyBorder)
::InflateRect(&rcButton, cyEdge - 1, cyEdge - 1);
m_rcButton = rcButton;
m_wndInButton.SetWindowPos(HWND_TOP, &rcButton, /*SWP_NOZORDER*/SWP_NOACTIVATE);
m_wndInButton.ShowWindow(SW_SHOW);
}
m_wndInButton.EnableWindow(IsWindowEnabled());
}
}
}; // template<class TEdit = CEdit> class CButtonEditImplCCtrlT : public CWindowImpl<CButtonEditImplCCtrlT, TEdit>
template<class TEdit = CEdit>
class CButtonEditImplNcCtrlT : public CWindowImpl<CButtonEditImplNcCtrlT, TEdit>
{
public:
typedef CButtonEditImplNcCtrlT thisClass;
typedef CWindowImpl<CButtonEditImplNcCtrlT, TEdit> baseClass;
BEGIN_MSG_MAP(thisClass)
MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize)
MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)
MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
COMMAND_CODE_HANDLER(BN_CLICKED, OnButtonNotifyClicked)
END_MSG_MAP()
protected:
typedef struct tagButtonInfo
{
RECT rect; // Button rectangle
UINT nWidth; // the width of the button
BOOL bHide; // hide or show the button
} ButtonInfo;
ButtonInfo m_buttonInfo;
CButton m_wndInButton;
public:
// c'tor
CButtonEditImplNcCtrlT()
{
::memset(&m_buttonInfo, 0, sizeof(ButtonInfo));
m_buttonInfo.nWidth = ::GetSystemMetrics(SM_CXVSCROLL);
}
BOOL HideButton(BOOL bHide)
{
if(!IsWindow())
return FALSE;
if(m_buttonInfo.bHide != bHide)
{
m_buttonInfo.bHide = bHide;
// Doing this forces our Edit control to pay attention to our change in it's client size
SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
return TRUE;
}
HWND Create(HWND hwndParent, RECT& rcPos, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
{
CEdit wndEditTemp;
HWND hWnd = wndEditTemp.Create(hwndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
wndEditTemp.Detach();
// HWND hWnd = baseClass::Create(hwndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
if(hWnd)
SubclassWindow(hWnd);
return hWnd;
}
BOOL SubclassWindow(HWND hWnd)
{
BOOL bRet = baseClass::SubclassWindow(hWnd);
if(!m_wndInButton.IsWindow())
{
m_wndInButton.Create(m_hWnd, &rcDefault, NULL, WS_POPUP | BS_PUSHBUTTON | BS_NOTIFY);
ATLASSERT(m_wndInButton.IsWindow());
m_wndInButton.SetFont((HFONT)::SendMessage(GetParent(), WM_GETFONT, 0, 0L));
m_wndInButton.SetWindowText(_T("..."));
}
// Doing this forces our Edit control to pay attention to our change in it's client size
SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
return bRet;
}
HWND UnsubclassWindow(BOOL bForce = FALSE)
{
if(m_wndInButton.IsWindow())
m_wndInButton.Detach();
HWND hWnd = baseClass::UnsubclassWindow(bForce);
// Doing this forces our Edit control to pay attention to our change in it's client size
::SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
return hWnd;
}
BOOL SetWindowPos(HWND hWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags)
{
if(!m_buttonInfo.bHide)
cy -= m_buttonInfo.nWidth;
return baseClass::SetWindowPos(hWndInsertAfter, x, y, cx, cy, nFlags);
}
BOOL SetWindowPos(HWND hWndInsertAfter, LPCRECT lpRect, UINT nFlags)
{
if(!m_buttonInfo.bHide)
{
RECT rcNew;
::CopyRect(&rcNew, lpRect);
rcNew.right -= m_buttonInfo.nWidth;
return baseClass::SetWindowPos(hWndInsertAfter, &rcNew, nFlags);
}
return baseClass::SetWindowPos(hWndInsertAfter, lpRect, nFlags);
}
protected:
LRESULT OnButtonNotifyClicked(WORD wNotifyCode, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
{
wNotifyCode;
ATLASSERT(BN_CLICKED == wNotifyCode);
::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
return 0;
}
LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
uMsg;
ATLASSERT(WM_NCCALCSIZE == uMsg);
LPNCCALCSIZE_PARAMS lpnccs = reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam);
LRESULT lRes = DefWindowProc(uMsg, wParam, lParam);
if(!m_buttonInfo.bHide)
{
// now we can allocate additional space by deflating the
// rectangle even further. Our button will go on the right-hand side,
// and will be the same width as a scrollbar button
lpnccs->rgrc[0].right -= m_buttonInfo.nWidth + ::GetSystemMetrics(SM_CXEDGE);
}
return lRes;
}
LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
uMsg;
ATLASSERT(WM_NCPAINT == uMsg);
if(!m_buttonInfo.bHide)
{
RECT rcWindow;
GetWindowRect(&rcWindow);
RECT rcClient;
GetClientRect(&rcClient);
CRgn rgn;
if(1 == wParam)
rgn.CreateRectRgnIndirect(&rcWindow);
else
rgn.Attach((HRGN)wParam);
RECT rcButton;
::CopyRect(&rcButton, &rcWindow);
rcButton.left = rcButton.right - m_buttonInfo.nWidth - /*2 * */::GetSystemMetrics(SM_CXEDGE);
int cyBorder = (rcWindow.bottom - rcWindow.top) - (rcClient.bottom - rcClient.top);
int cyEdge = ::GetSystemMetrics(SM_CYEDGE);
if(cyEdge - 1 < cyBorder)
::InflateRect(&rcButton, -cyEdge+ 1, -cyEdge + 1);
::CopyRect(&m_buttonInfo.rect, &rcButton);
rcButton.left -= ::GetSystemMetrics(SM_CXEDGE);
CRgn rgnButton;
rgnButton.CreateRectRgnIndirect(&rcButton);
::CombineRgn(rgn, rgn, rgnButton, RGN_XOR);
DefWindowProc(uMsg, (WPARAM)(HRGN)rgn, lParam);
if(1 != wParam)
rgn.Detach();
if(m_wndInButton.IsWindow())
m_wndInButton.SetWindowPos(m_hWnd, &m_buttonInfo.rect, SWP_NOZORDER | SWP_NOACTIVATE | SWP_SHOWWINDOW);
// An application returns zero if it processes this message.
return 0;
}
return DefWindowProc(uMsg, wParam, lParam);
}
LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
uMsg;
ATLASSERT(WM_NCHITTEST == uMsg);
LRESULT lRes = DefWindowProc(uMsg, wParam, lParam);
if(HTNOWHERE != lRes || m_buttonInfo.bHide)
return lRes;
// retrieve the mouse coordinates
POINT ptHit = { (short)LOWORD(lParam), (short)HIWORD(lParam) };
if(::PtInRect(&m_buttonInfo.rect, ptHit))
return HTTRANSPARENT;
return HTNOWHERE;
}
}; // template<class TEdit = CEdit> Class CButtonEditImplNcCtrlT : public CWindowImpl<CButtonEditImplNcCtrlT, TEdit>
template<class TEdit = CEdit>
class CButtonEditImplNcDrawT : public CWindowImpl<CButtonEditImplNcDrawT, TEdit>
{
public:
typedef CButtonEditImplNcDrawT thisClass;
typedef CWindowImpl<CButtonEditImplNcDrawT, TEdit> baseClass;
BEGIN_MSG_MAP(thisClass)
MESSAGE_HANDLER(WM_NCCALCSIZE, OnNcCalcSize)
MESSAGE_HANDLER(WM_NCPAINT, OnNcPaint)
MESSAGE_HANDLER(WM_NCHITTEST, OnNcHitTest)
MESSAGE_HANDLER(WM_NCLBUTTONDOWN, OnNcLButtonDownDblClk)
MESSAGE_HANDLER(WM_NCLBUTTONDBLCLK, OnNcLButtonDownDblClk)
MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
END_MSG_MAP()
protected:
typedef struct tagButtonInfo
{
RECT rect; // Button rectangle
UINT uCmd; // Command to send when clicked (WM_COMMAND)
BOOL bPressed; // Is the button pressed in or out?
BOOL bPressedMouseOver; // Is the button press and the mouse cursor over the button? to emulates the way a normal button in Windows works
UINT nWidth; // the width of the button
BOOL bHide; // hide or show the button
} ButtonInfo;
ButtonInfo m_buttonInfo;
public:
// c'tor
CButtonEditImplNcDrawT()
{
::memset(&m_buttonInfo, 0, sizeof(ButtonInfo));
m_buttonInfo.nWidth = ::GetSystemMetrics(SM_CXVSCROLL);
m_buttonInfo.uCmd = BEM_BROWSE;
}
// d'tor
virtual ~CButtonEditImplNcDrawT()
{
}
BOOL HideButton(BOOL bHide)
{
if(!IsWindow())
return FALSE;
if(m_buttonInfo.bHide != bHide)
{
m_buttonInfo.bHide = bHide;
// Doing this forces our Edit control to pay attention to our change in it's client size
SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
}
return TRUE;
}
HWND Create(HWND hwndParent, RECT& rcPos, LPCTSTR szWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
{
HWND hWnd = baseClass::Create(hwndParent, rcPos, szWindowName, dwStyle, dwExStyle, nID, lpCreateParam);
// Doing this forces our Edit control to pay attention to our change in it's client size
SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
return hWnd;
}
BOOL SubclassWindow(HWND hWnd)
{
BOOL bRet = baseClass::SubclassWindow(hWnd);
// Doing this forces our Edit control to pay attention to our change in it's client size
SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
return bRet;
}
HWND UnsubclassWindow(BOOL bForce = FALSE)
{
HWND hWnd = baseClass::UnsubclassWindow(bForce);
// Doing this forces our Edit control to pay attention to our change in it's client size
::SetWindowPos(hWnd, NULL, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
return hWnd;
}
BOOL SetWindowPos(HWND hWndInsertAfter, int x, int y, int cx, int cy, UINT nFlags)
{
cy -= m_buttonInfo.nWidth;
return baseClass::SetWindowPos(hWndInsertAfter, x, y, cx, cy, nFlags);
}
BOOL SetWindowPos(HWND hWndInsertAfter, LPCRECT lpRect, UINT nFlags)
{
RECT rcNew;
::CopyRect(&rcNew, lpRect);
rcNew.right -= m_buttonInfo.nWidth;
return baseClass::SetWindowPos(hWndInsertAfter, &rcNew, nFlags);
}
protected:
LRESULT OnNcCalcSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
uMsg;
ATLASSERT(WM_NCCALCSIZE == uMsg);
LPNCCALCSIZE_PARAMS lpnccs = reinterpret_cast<LPNCCALCSIZE_PARAMS>(lParam);
LRESULT lRes = DefWindowProc(uMsg, wParam, lParam);
if(!m_buttonInfo.bHide)
{
// now we can allocate additional space by deflating the
// rectangle even further. Our button will go on the right-hand side,
// and will be the same width as a scrollbar button
lpnccs->rgrc[0].right -= m_buttonInfo.nWidth;
}
return lRes;
}
LRESULT OnNcPaint(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
uMsg;
ATLASSERT(WM_NCPAINT == uMsg);
if(!m_buttonInfo.bHide)
{
// Get the SCREEN coordinates of this window.
RECT rcWindow;
GetWindowRect(&rcWindow);
////////////////////////////////////////////////////////////////////////////////////////////////////
// Update layouts
////////////////////////////////////////////////////////////////////////////////////////////////////
// calculate button rectangles
RECT rcButton;
::CopyRect(&rcButton, &rcWindow);
::OffsetRect(&rcButton, -rcWindow.left, -rcWindow.top);
if(WS_BORDER & GetStyle())
::InflateRect(&rcButton, -::GetSystemMetrics(SM_CXEDGE), -::GetSystemMetrics(SM_CYEDGE));
rcButton.left = rcButton.right - m_buttonInfo.nWidth - ::GetSystemMetrics(SM_CXEDGE);
::CopyRect(&m_buttonInfo.rect, &rcButton);
LRESULT lRes = DefWindowProc(uMsg, wParam, lParam);
// Draw Button
DrawButton();
return lRes;
}
else
return DefWindowProc(uMsg, wParam, lParam);
}
void DrawButton(HDC hdcWindow = NULL)
{
if(m_buttonInfo.bHide)
return;
CDCHandle dcWindow;
if(hdcWindow)
dcWindow.Attach(hdcWindow);
else
dcWindow.Attach(GetWindowDC());
// int nSaveDC = dcWindow.SaveDC();
CFontHandle oldFont = dcWindow.SelectFont(GetFont());
dcWindow.SetBkMode(TRANSPARENT);
dcWindow.IntersectClipRect(&m_buttonInfo.rect);
// erase background
CBrush brBtnFace;
brBtnFace.CreateSysColorBrush(COLOR_BTNFACE);
dcWindow.FillRect(&m_buttonInfo.rect, brBtnFace);
if(IsWindowEnabled())
{
if(m_buttonInfo.bPressedMouseOver)
{
RECT rcPressed;
::CopyRect(&rcPressed, &m_buttonInfo.rect);
::OffsetRect(&rcPressed, 1, 1);
dcWindow.DrawText(_T("..."), 3, &rcPressed, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
dcWindow.DrawEdge(&m_buttonInfo.rect, EDGE_RAISED, BF_RECT | BF_FLAT);
}
else
{
dcWindow.DrawText(_T("..."), 3, &m_buttonInfo.rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
dcWindow.DrawEdge(&m_buttonInfo.rect, EDGE_RAISED, BF_RECT);
}
}
else
{
dcWindow.SetTextColor(::GetSysColor(COLOR_BTNHIGHLIGHT));
::OffsetRect(&m_buttonInfo.rect, 1, 1);
dcWindow.DrawText(_T("..."), 3, &m_buttonInfo.rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
dcWindow.SetTextColor(::GetSysColor(COLOR_BTNSHADOW));
::OffsetRect(&m_buttonInfo.rect, -1, -1);
dcWindow.DrawText(_T("..."), 3, &m_buttonInfo.rect, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
dcWindow.DrawEdge(&m_buttonInfo.rect, EDGE_RAISED, BF_RECT);
}
dcWindow.SelectFont(oldFont);
// dcWindow.RestoreDC(nSaveDC);
if(hdcWindow)
dcWindow.Detach();
else
ReleaseDC(dcWindow.Detach());
}
LRESULT OnNcHitTest(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
uMsg;
ATLASSERT(WM_NCHITTEST == uMsg);
LRESULT lRes = DefWindowProc(uMsg, wParam, lParam);
if(HTNOWHERE != lRes || m_buttonInfo.bHide)
return lRes;
// retrieve the mouse coordinates
POINT ptHit = { (short)LOWORD(lParam), (short)HIWORD(lParam) };
RECT rcWindow;
GetWindowRect(&rcWindow);
RECT rcButton;
::CopyRect(&rcButton, &m_buttonInfo.rect);
::OffsetRect(&rcButton, rcWindow.left, rcWindow.top);
if(::PtInRect(&rcButton, ptHit))
return HTBORDER;
return HTNOWHERE;
}
LRESULT OnNcLButtonDownDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
uMsg;
ATLASSERT(WM_NCLBUTTONDOWN == uMsg || WM_NCLBUTTONDBLCLK == uMsg);
if(!m_buttonInfo.bHide)
{
// retrieve the mouse coordinates
POINT ptHit = { (short)LOWORD(lParam), (short)HIWORD(lParam) };
RECT rcWindow;
GetWindowRect(&rcWindow);
// to see if button has been clicked
//get screen coordinates of each button
RECT rcButton;
::CopyRect(&rcButton, &m_buttonInfo.rect);
::OffsetRect(&rcButton, rcWindow.left, rcWindow.top);
//if clicked in a custom button
if(::PtInRect(&rcButton, ptHit))
{
m_buttonInfo.bPressed = TRUE;
m_buttonInfo.bPressedMouseOver = TRUE;
DrawButton();
SetCapture();
// If an application processes this message, it should return zero.
return 0;
}
}
return DefWindowProc(uMsg, wParam, lParam);
}
LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
uMsg;
ATLASSERT(WM_LBUTTONUP == uMsg);
if(!m_buttonInfo.bPressed || m_buttonInfo.bHide)
return DefWindowProc(uMsg, wParam, lParam);
ReleaseCapture();
RECT rcWindow;
GetWindowRect(&rcWindow);
RECT rcButton;
::CopyRect(&rcButton, &m_buttonInfo.rect);
::OffsetRect(&rcButton, rcWindow.left, rcWindow.top);
// retrieve the mouse coordinates
POINT ptHit = { (short)LOWORD(lParam), (short)HIWORD(lParam) };
ClientToScreen(&ptHit);
// if clicked in a button
if(::PtInRect(&rcButton, ptHit))
{
SendMessage(WM_COMMAND, (WPARAM)m_buttonInfo.uCmd, MAKELPARAM(ptHit.x, ptHit.y));
}
m_buttonInfo.bPressed = FALSE;
m_buttonInfo.bPressedMouseOver = FALSE;
DrawButton();
// If an application processes this message, it should return zero.
return 0;
}
LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
{
uMsg;
ATLASSERT(WM_MOUSEMOVE == uMsg);
if(!m_buttonInfo.bPressed || m_buttonInfo.bHide)
return DefWindowProc(uMsg, wParam, lParam);
RECT rcWindow;
GetWindowRect(&rcWindow);
RECT rcButton;
::CopyRect(&rcButton, &m_buttonInfo.rect);
::OffsetRect(&rcButton, rcWindow.left, rcWindow.top);
// retrieve the mouse coordinates
POINT ptHit = { (short)LOWORD(lParam), (short)HIWORD(lParam) };
ClientToScreen(&ptHit);
BOOL bPressedMouseOver = ::PtInRect(&rcButton, ptHit);
if(bPressedMouseOver != m_buttonInfo.bPressedMouseOver)
{
m_buttonInfo.bPressedMouseOver ^= 1;
DrawButton();
}
// If an application processes this message, it should return zero.
return 0;
}
}; // template<class TEdit = CEdit> class CButtonEditImplNcDrawT : public CWindowImpl<CButtonEditImplNcDrawT, TEdit>
} // namespace codeproject
#endif // #if !defined(__BUTTONEDIT_H_)