Index: third_party/wtl/include/atlctrlx.h |
diff --git a/third_party/wtl/include/atlctrlx.h b/third_party/wtl/include/atlctrlx.h |
deleted file mode 100644 |
index e1ce59ed2642cf7bd9068fcb94670aa196d926d1..0000000000000000000000000000000000000000 |
--- a/third_party/wtl/include/atlctrlx.h |
+++ /dev/null |
@@ -1,4824 +0,0 @@ |
-// Windows Template Library - WTL version 8.0 |
-// Copyright (C) Microsoft Corporation. All rights reserved. |
-// |
-// This file is a part of the Windows Template Library. |
-// The use and distribution terms for this software are covered by the |
-// Microsoft Permissive License (Ms-PL) which can be found in the file |
-// Ms-PL.txt at the root of this distribution. |
- |
-#ifndef __ATLCTRLX_H__ |
-#define __ATLCTRLX_H__ |
- |
-#pragma once |
- |
-#ifndef __cplusplus |
- #error ATL requires C++ compilation (use a .cpp suffix) |
-#endif |
- |
-#ifndef __ATLAPP_H__ |
- #error atlctrlx.h requires atlapp.h to be included first |
-#endif |
- |
-#ifndef __ATLCTRLS_H__ |
- #error atlctrlx.h requires atlctrls.h to be included first |
-#endif |
- |
-#ifndef WM_UPDATEUISTATE |
- #define WM_UPDATEUISTATE 0x0128 |
-#endif // !WM_UPDATEUISTATE |
- |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// Classes in this file: |
-// |
-// CBitmapButtonImpl<T, TBase, TWinTraits> |
-// CBitmapButton |
-// CCheckListViewCtrlImpl<T, TBase, TWinTraits> |
-// CCheckListViewCtrl |
-// CHyperLinkImpl<T, TBase, TWinTraits> |
-// CHyperLink |
-// CWaitCursor |
-// CCustomWaitCursor |
-// CMultiPaneStatusBarCtrlImpl<T, TBase> |
-// CMultiPaneStatusBarCtrl |
-// CPaneContainerImpl<T, TBase, TWinTraits> |
-// CPaneContainer |
-// CSortListViewImpl<T> |
-// CSortListViewCtrlImpl<T, TBase, TWinTraits> |
-// CSortListViewCtrl |
-// CTabViewImpl<T, TBase, TWinTraits> |
-// CTabView |
- |
-namespace WTL |
-{ |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// CBitmapButton - bitmap button implementation |
- |
-#ifndef _WIN32_WCE |
- |
-// bitmap button extended styles |
-#define BMPBTN_HOVER 0x00000001 |
-#define BMPBTN_AUTO3D_SINGLE 0x00000002 |
-#define BMPBTN_AUTO3D_DOUBLE 0x00000004 |
-#define BMPBTN_AUTOSIZE 0x00000008 |
-#define BMPBTN_SHAREIMAGELISTS 0x00000010 |
-#define BMPBTN_AUTOFIRE 0x00000020 |
- |
-template <class T, class TBase = CButton, class TWinTraits = ATL::CControlWinTraits> |
-class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits> |
-{ |
-public: |
- DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) |
- |
- enum |
- { |
- _nImageNormal = 0, |
- _nImagePushed, |
- _nImageFocusOrHover, |
- _nImageDisabled, |
- |
- _nImageCount = 4, |
- }; |
- |
- enum |
- { |
- ID_TIMER_FIRST = 1000, |
- ID_TIMER_REPEAT = 1001 |
- }; |
- |
- // Bitmap button specific extended styles |
- DWORD m_dwExtendedStyle; |
- |
- CImageList m_ImageList; |
- int m_nImage[_nImageCount]; |
- |
- CToolTipCtrl m_tip; |
- LPTSTR m_lpstrToolTipText; |
- |
- // Internal states |
- unsigned m_fMouseOver:1; |
- unsigned m_fFocus:1; |
- unsigned m_fPressed:1; |
- |
- |
-// Constructor/Destructor |
- CBitmapButtonImpl(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) : |
- m_ImageList(hImageList), m_dwExtendedStyle(dwExtendedStyle), |
- m_lpstrToolTipText(NULL), |
- m_fMouseOver(0), m_fFocus(0), m_fPressed(0) |
- { |
- m_nImage[_nImageNormal] = -1; |
- m_nImage[_nImagePushed] = -1; |
- m_nImage[_nImageFocusOrHover] = -1; |
- m_nImage[_nImageDisabled] = -1; |
- } |
- |
- ~CBitmapButtonImpl() |
- { |
- if((m_dwExtendedStyle & BMPBTN_SHAREIMAGELISTS) == 0) |
- m_ImageList.Destroy(); |
- delete [] m_lpstrToolTipText; |
- } |
- |
- // overridden to provide proper initialization |
- BOOL SubclassWindow(HWND hWnd) |
- { |
-#if (_MSC_VER >= 1300) |
- BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits>::SubclassWindow(hWnd); |
-#else // !(_MSC_VER >= 1300) |
- typedef ATL::CWindowImpl< T, TBase, TWinTraits> _baseClass; |
- BOOL bRet = _baseClass::SubclassWindow(hWnd); |
-#endif // !(_MSC_VER >= 1300) |
- if(bRet) |
- Init(); |
- return bRet; |
- } |
- |
-// Attributes |
- DWORD GetBitmapButtonExtendedStyle() const |
- { |
- return m_dwExtendedStyle; |
- } |
- |
- DWORD SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) |
- { |
- DWORD dwPrevStyle = m_dwExtendedStyle; |
- if(dwMask == 0) |
- m_dwExtendedStyle = dwExtendedStyle; |
- else |
- m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); |
- return dwPrevStyle; |
- } |
- |
- HIMAGELIST GetImageList() const |
- { |
- return m_ImageList; |
- } |
- |
- HIMAGELIST SetImageList(HIMAGELIST hImageList) |
- { |
- HIMAGELIST hImageListPrev = m_ImageList; |
- m_ImageList = hImageList; |
- if((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0 && ::IsWindow(m_hWnd)) |
- SizeToImage(); |
- return hImageListPrev; |
- } |
- |
- int GetToolTipTextLength() const |
- { |
- return (m_lpstrToolTipText == NULL) ? -1 : lstrlen(m_lpstrToolTipText); |
- } |
- |
- bool GetToolTipText(LPTSTR lpstrText, int nLength) const |
- { |
- ATLASSERT(lpstrText != NULL); |
- if(m_lpstrToolTipText == NULL) |
- return false; |
- |
- errno_t nRet = SecureHelper::strncpy_x(lpstrText, nLength, m_lpstrToolTipText, _TRUNCATE); |
- |
- return (nRet == 0 || nRet == STRUNCATE); |
- } |
- |
- bool SetToolTipText(LPCTSTR lpstrText) |
- { |
- if(m_lpstrToolTipText != NULL) |
- { |
- delete [] m_lpstrToolTipText; |
- m_lpstrToolTipText = NULL; |
- } |
- |
- if(lpstrText == NULL) |
- { |
- if(m_tip.IsWindow()) |
- m_tip.Activate(FALSE); |
- return true; |
- } |
- |
- int cchLen = lstrlen(lpstrText) + 1; |
- ATLTRY(m_lpstrToolTipText = new TCHAR[cchLen]); |
- if(m_lpstrToolTipText == NULL) |
- return false; |
- |
- SecureHelper::strcpy_x(m_lpstrToolTipText, cchLen, lpstrText); |
- if(m_tip.IsWindow()) |
- { |
- m_tip.Activate(TRUE); |
- m_tip.AddTool(m_hWnd, m_lpstrToolTipText); |
- } |
- |
- return true; |
- } |
- |
-// Operations |
- void SetImages(int nNormal, int nPushed = -1, int nFocusOrHover = -1, int nDisabled = -1) |
- { |
- if(nNormal != -1) |
- m_nImage[_nImageNormal] = nNormal; |
- if(nPushed != -1) |
- m_nImage[_nImagePushed] = nPushed; |
- if(nFocusOrHover != -1) |
- m_nImage[_nImageFocusOrHover] = nFocusOrHover; |
- if(nDisabled != -1) |
- m_nImage[_nImageDisabled] = nDisabled; |
- } |
- |
- BOOL SizeToImage() |
- { |
- ATLASSERT(::IsWindow(m_hWnd) && m_ImageList.m_hImageList != NULL); |
- int cx = 0; |
- int cy = 0; |
- if(!m_ImageList.GetIconSize(cx, cy)) |
- return FALSE; |
- return ResizeClient(cx, cy); |
- } |
- |
-// Overrideables |
- void DoPaint(CDCHandle dc) |
- { |
- ATLASSERT(m_ImageList.m_hImageList != NULL); // image list must be set |
- ATLASSERT(m_nImage[0] != -1); // main bitmap must be set |
- |
- // set bitmap according to the current button state |
- int nImage = -1; |
- bool bHover = IsHoverMode(); |
- if(!IsWindowEnabled()) |
- nImage = m_nImage[_nImageDisabled]; |
- else if(m_fPressed == 1) |
- nImage = m_nImage[_nImagePushed]; |
- else if((!bHover && m_fFocus == 1) || (bHover && m_fMouseOver == 1)) |
- nImage = m_nImage[_nImageFocusOrHover]; |
- if(nImage == -1) // not there, use default one |
- nImage = m_nImage[_nImageNormal]; |
- |
- // draw the button image |
- int xyPos = 0; |
- if((m_fPressed == 1) && ((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0) && (m_nImage[_nImagePushed] == -1)) |
- xyPos = 1; |
- m_ImageList.Draw(dc, nImage, xyPos, xyPos, ILD_NORMAL); |
- |
- // draw 3D border if required |
- if((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0) |
- { |
- RECT rect; |
- GetClientRect(&rect); |
- |
- if(m_fPressed == 1) |
- dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_SUNKENOUTER : EDGE_SUNKEN, BF_RECT); |
- else if(!bHover || m_fMouseOver == 1) |
- dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_RAISEDINNER : EDGE_RAISED, BF_RECT); |
- |
- if(!bHover && m_fFocus == 1) |
- { |
- ::InflateRect(&rect, -2 * ::GetSystemMetrics(SM_CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE)); |
- dc.DrawFocusRect(&rect); |
- } |
- } |
- } |
- |
-// Message map and handlers |
- BEGIN_MSG_MAP(CBitmapButtonImpl) |
- MESSAGE_HANDLER(WM_CREATE, OnCreate) |
- MESSAGE_HANDLER(WM_DESTROY, OnDestroy) |
- MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage) |
- MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) |
- MESSAGE_HANDLER(WM_PAINT, OnPaint) |
- MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) |
- MESSAGE_HANDLER(WM_SETFOCUS, OnFocus) |
- MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus) |
- MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) |
- MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk) |
- MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) |
- MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged) |
- MESSAGE_HANDLER(WM_ENABLE, OnEnable) |
- MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) |
- MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) |
- MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) |
- MESSAGE_HANDLER(WM_KEYUP, OnKeyUp) |
- MESSAGE_HANDLER(WM_TIMER, OnTimer) |
- MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState) |
- END_MSG_MAP() |
- |
- LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- Init(); |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- if(m_tip.IsWindow()) |
- { |
- m_tip.DestroyWindow(); |
- m_tip.m_hWnd = NULL; |
- } |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) |
- { |
- MSG msg = { m_hWnd, uMsg, wParam, lParam }; |
- if(m_tip.IsWindow()) |
- m_tip.RelayEvent(&msg); |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- return 1; // no background needed |
- } |
- |
- LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- T* pT = static_cast<T*>(this); |
- if(wParam != NULL) |
- { |
- pT->DoPaint((HDC)wParam); |
- } |
- else |
- { |
- CPaintDC dc(m_hWnd); |
- pT->DoPaint(dc.m_hDC); |
- } |
- return 0; |
- } |
- |
- LRESULT OnFocus(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- m_fFocus = (uMsg == WM_SETFOCUS) ? 1 : 0; |
- Invalidate(); |
- UpdateWindow(); |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- LRESULT lRet = 0; |
- if(IsHoverMode()) |
- SetCapture(); |
- else |
- lRet = DefWindowProc(uMsg, wParam, lParam); |
- if(::GetCapture() == m_hWnd) |
- { |
- m_fPressed = 1; |
- Invalidate(); |
- UpdateWindow(); |
- } |
- if((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) |
- { |
- int nElapse = 250; |
- int nDelay = 0; |
- if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDelay, 0)) |
- nElapse += nDelay * 250; // all milli-seconds |
- SetTimer(ID_TIMER_FIRST, nElapse); |
- } |
- return lRet; |
- } |
- |
- LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- LRESULT lRet = 0; |
- if(!IsHoverMode()) |
- lRet = DefWindowProc(uMsg, wParam, lParam); |
- if(::GetCapture() != m_hWnd) |
- SetCapture(); |
- if(m_fPressed == 0) |
- { |
- m_fPressed = 1; |
- Invalidate(); |
- UpdateWindow(); |
- } |
- return lRet; |
- } |
- |
- LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- LRESULT lRet = 0; |
- bool bHover = IsHoverMode(); |
- if(!bHover) |
- lRet = DefWindowProc(uMsg, wParam, lParam); |
- if(::GetCapture() == m_hWnd) |
- { |
- if(bHover && m_fPressed == 1) |
- ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); |
- ::ReleaseCapture(); |
- } |
- return lRet; |
- } |
- |
- LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- if(m_fPressed == 1) |
- { |
- m_fPressed = 0; |
- Invalidate(); |
- UpdateWindow(); |
- } |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- Invalidate(); |
- UpdateWindow(); |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) |
- { |
- if(::GetCapture() == m_hWnd) |
- { |
- POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; |
- ClientToScreen(&ptCursor); |
- RECT rect = { 0 }; |
- GetWindowRect(&rect); |
- unsigned int uPressed = ::PtInRect(&rect, ptCursor) ? 1 : 0; |
- if(m_fPressed != uPressed) |
- { |
- m_fPressed = uPressed; |
- Invalidate(); |
- UpdateWindow(); |
- } |
- } |
- else if(IsHoverMode() && m_fMouseOver == 0) |
- { |
- m_fMouseOver = 1; |
- Invalidate(); |
- UpdateWindow(); |
- StartTrackMouseLeave(); |
- } |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- if(m_fMouseOver == 1) |
- { |
- m_fMouseOver = 0; |
- Invalidate(); |
- UpdateWindow(); |
- } |
- return 0; |
- } |
- |
- LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- if(wParam == VK_SPACE && IsHoverMode()) |
- return 0; // ignore if in hover mode |
- if(wParam == VK_SPACE && m_fPressed == 0) |
- { |
- m_fPressed = 1; |
- Invalidate(); |
- UpdateWindow(); |
- } |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- if(wParam == VK_SPACE && IsHoverMode()) |
- return 0; // ignore if in hover mode |
- if(wParam == VK_SPACE && m_fPressed == 1) |
- { |
- m_fPressed = 0; |
- Invalidate(); |
- UpdateWindow(); |
- } |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- ATLASSERT((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0); |
- switch(wParam) // timer ID |
- { |
- case ID_TIMER_FIRST: |
- KillTimer(ID_TIMER_FIRST); |
- if(m_fPressed == 1) |
- { |
- ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); |
- int nElapse = 250; |
- int nRepeat = 40; |
- if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0)) |
- nElapse = 10000 / (10 * nRepeat + 25); // milli-seconds, approximated |
- SetTimer(ID_TIMER_REPEAT, nElapse); |
- } |
- break; |
- case ID_TIMER_REPEAT: |
- if(m_fPressed == 1) |
- ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); |
- else if(::GetCapture() != m_hWnd) |
- KillTimer(ID_TIMER_REPEAT); |
- break; |
- default: // not our timer |
- break; |
- } |
- return 0; |
- } |
- |
- LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- // If the control is subclassed or superclassed, this message can cause |
- // repainting without WM_PAINT. We don't use this state, so just do nothing. |
- return 0; |
- } |
- |
-// Implementation |
- void Init() |
- { |
- // We need this style to prevent Windows from painting the button |
- ModifyStyle(0, BS_OWNERDRAW); |
- |
- // create a tool tip |
- m_tip.Create(m_hWnd); |
- ATLASSERT(m_tip.IsWindow()); |
- if(m_tip.IsWindow() && m_lpstrToolTipText != NULL) |
- { |
- m_tip.Activate(TRUE); |
- m_tip.AddTool(m_hWnd, m_lpstrToolTipText); |
- } |
- |
- if(m_ImageList.m_hImageList != NULL && (m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0) |
- SizeToImage(); |
- } |
- |
- BOOL StartTrackMouseLeave() |
- { |
- TRACKMOUSEEVENT tme = { 0 }; |
- tme.cbSize = sizeof(tme); |
- tme.dwFlags = TME_LEAVE; |
- tme.hwndTrack = m_hWnd; |
- return _TrackMouseEvent(&tme); |
- } |
- |
- bool IsHoverMode() const |
- { |
- return ((m_dwExtendedStyle & BMPBTN_HOVER) != 0); |
- } |
-}; |
- |
- |
-class CBitmapButton : public CBitmapButtonImpl<CBitmapButton> |
-{ |
-public: |
- DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName()) |
- |
- CBitmapButton(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) : |
- CBitmapButtonImpl<CBitmapButton>(dwExtendedStyle, hImageList) |
- { } |
-}; |
- |
-#endif // !_WIN32_WCE |
- |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// CCheckListCtrlView - list view control with check boxes |
- |
-template <DWORD t_dwStyle, DWORD t_dwExStyle, DWORD t_dwExListViewStyle> |
-class CCheckListViewCtrlImplTraits |
-{ |
-public: |
- static DWORD GetWndStyle(DWORD dwStyle) |
- { |
- return (dwStyle == 0) ? t_dwStyle : dwStyle; |
- } |
- |
- static DWORD GetWndExStyle(DWORD dwExStyle) |
- { |
- return (dwExStyle == 0) ? t_dwExStyle : dwExStyle; |
- } |
- |
- static DWORD GetExtendedLVStyle() |
- { |
- return t_dwExListViewStyle; |
- } |
-}; |
- |
-typedef CCheckListViewCtrlImplTraits<WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS, WS_EX_CLIENTEDGE, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT> CCheckListViewCtrlTraits; |
- |
-template <class T, class TBase = CListViewCtrl, class TWinTraits = CCheckListViewCtrlTraits> |
-class ATL_NO_VTABLE CCheckListViewCtrlImpl : public ATL::CWindowImpl<T, TBase, TWinTraits> |
-{ |
-public: |
- DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) |
- |
-// Attributes |
- static DWORD GetExtendedLVStyle() |
- { |
- return TWinTraits::GetExtendedLVStyle(); |
- } |
- |
-// Operations |
- BOOL SubclassWindow(HWND hWnd) |
- { |
-#if (_MSC_VER >= 1300) |
- BOOL bRet = ATL::CWindowImplBaseT< TBase, TWinTraits>::SubclassWindow(hWnd); |
-#else // !(_MSC_VER >= 1300) |
- typedef ATL::CWindowImplBaseT< TBase, TWinTraits> _baseClass; |
- BOOL bRet = _baseClass::SubclassWindow(hWnd); |
-#endif // !(_MSC_VER >= 1300) |
- if(bRet) |
- { |
- T* pT = static_cast<T*>(this); |
- pT; |
- ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0); |
- SetExtendedListViewStyle(pT->GetExtendedLVStyle()); |
- } |
- return bRet; |
- } |
- |
- void CheckSelectedItems(int nCurrItem) |
- { |
- // first check if this item is selected |
- LVITEM lvi = { 0 }; |
- lvi.iItem = nCurrItem; |
- lvi.iSubItem = 0; |
- lvi.mask = LVIF_STATE; |
- lvi.stateMask = LVIS_SELECTED; |
- GetItem(&lvi); |
- // if item is not selected, don't do anything |
- if(!(lvi.state & LVIS_SELECTED)) |
- return; |
- // new check state will be reverse of the current state, |
- BOOL bCheck = !GetCheckState(nCurrItem); |
- int nItem = -1; |
- int nOldItem = -1; |
- while((nItem = GetNextItem(nOldItem, LVNI_SELECTED)) != -1) |
- { |
- if(nItem != nCurrItem) |
- SetCheckState(nItem, bCheck); |
- nOldItem = nItem; |
- } |
- } |
- |
-// Implementation |
- BEGIN_MSG_MAP(CCheckListViewCtrlImpl) |
- MESSAGE_HANDLER(WM_CREATE, OnCreate) |
- MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) |
- MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown) |
- MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown) |
- END_MSG_MAP() |
- |
- LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- // first let list view control initialize everything |
- LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); |
- T* pT = static_cast<T*>(this); |
- pT; |
- ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0); |
- SetExtendedListViewStyle(pT->GetExtendedLVStyle()); |
- return lRet; |
- } |
- |
- LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) |
- { |
- POINT ptMsg = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; |
- LVHITTESTINFO lvh = { 0 }; |
- lvh.pt = ptMsg; |
- if(HitTest(&lvh) != -1 && lvh.flags == LVHT_ONITEMSTATEICON && ::GetKeyState(VK_CONTROL) >= 0) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->CheckSelectedItems(lvh.iItem); |
- } |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- if(wParam == VK_SPACE) |
- { |
- int nCurrItem = GetNextItem(-1, LVNI_FOCUSED); |
- if(nCurrItem != -1 && ::GetKeyState(VK_CONTROL) >= 0) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->CheckSelectedItems(nCurrItem); |
- } |
- } |
- bHandled = FALSE; |
- return 1; |
- } |
-}; |
- |
-class CCheckListViewCtrl : public CCheckListViewCtrlImpl<CCheckListViewCtrl> |
-{ |
-public: |
- DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName()) |
-}; |
- |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// CHyperLink - hyper link control implementation |
- |
-#if (WINVER < 0x0500) && !defined(_WIN32_WCE) |
-__declspec(selectany) struct |
-{ |
- enum { cxWidth = 32, cyHeight = 32 }; |
- int xHotSpot; |
- int yHotSpot; |
- unsigned char arrANDPlane[cxWidth * cyHeight / 8]; |
- unsigned char arrXORPlane[cxWidth * cyHeight / 8]; |
-} _AtlHyperLink_CursorData = |
-{ |
- 5, 0, |
- { |
- 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, |
- 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF, |
- 0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, |
- 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF, |
- 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, |
- 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF |
- }, |
- { |
- 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, |
- 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00, |
- 0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00, |
- 0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00, |
- 0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00, |
- 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
- } |
-}; |
-#endif // (WINVER < 0x0500) && !defined(_WIN32_WCE) |
- |
-#define HLINK_UNDERLINED 0x00000000 |
-#define HLINK_NOTUNDERLINED 0x00000001 |
-#define HLINK_UNDERLINEHOVER 0x00000002 |
-#define HLINK_COMMANDBUTTON 0x00000004 |
-#define HLINK_NOTIFYBUTTON 0x0000000C |
-#define HLINK_USETAGS 0x00000010 |
-#define HLINK_USETAGSBOLD 0x00000030 |
-#define HLINK_NOTOOLTIP 0x00000040 |
- |
-// Notes: |
-// - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned |
-// - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored |
- |
-template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits> |
-class ATL_NO_VTABLE CHyperLinkImpl : public ATL::CWindowImpl< T, TBase, TWinTraits > |
-{ |
-public: |
- LPTSTR m_lpstrLabel; |
- LPTSTR m_lpstrHyperLink; |
- |
- HCURSOR m_hCursor; |
- HFONT m_hFont; |
- HFONT m_hFontNormal; |
- |
- RECT m_rcLink; |
-#ifndef _WIN32_WCE |
- CToolTipCtrl m_tip; |
-#endif // !_WIN32_WCE |
- |
- COLORREF m_clrLink; |
- COLORREF m_clrVisited; |
- |
- DWORD m_dwExtendedStyle; // Hyper Link specific extended styles |
- |
- bool m_bPaintLabel:1; |
- bool m_bVisited:1; |
- bool m_bHover:1; |
- bool m_bInternalLinkFont:1; |
- |
- |
-// Constructor/Destructor |
- CHyperLinkImpl(DWORD dwExtendedStyle = HLINK_UNDERLINED) : |
- m_lpstrLabel(NULL), m_lpstrHyperLink(NULL), |
- m_hCursor(NULL), m_hFont(NULL), m_hFontNormal(NULL), |
- m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128)), |
- m_dwExtendedStyle(dwExtendedStyle), |
- m_bPaintLabel(true), m_bVisited(false), |
- m_bHover(false), m_bInternalLinkFont(false) |
- { |
- ::SetRectEmpty(&m_rcLink); |
- } |
- |
- ~CHyperLinkImpl() |
- { |
- delete [] m_lpstrLabel; |
- delete [] m_lpstrHyperLink; |
- if(m_bInternalLinkFont && m_hFont != NULL) |
- ::DeleteObject(m_hFont); |
-#if (WINVER < 0x0500) && !defined(_WIN32_WCE) |
- // It was created, not loaded, so we have to destroy it |
- if(m_hCursor != NULL) |
- ::DestroyCursor(m_hCursor); |
-#endif // (WINVER < 0x0500) && !defined(_WIN32_WCE) |
- } |
- |
-// Attributes |
- DWORD GetHyperLinkExtendedStyle() const |
- { |
- return m_dwExtendedStyle; |
- } |
- |
- DWORD SetHyperLinkExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) |
- { |
- DWORD dwPrevStyle = m_dwExtendedStyle; |
- if(dwMask == 0) |
- m_dwExtendedStyle = dwExtendedStyle; |
- else |
- m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); |
- return dwPrevStyle; |
- } |
- |
- bool GetLabel(LPTSTR lpstrBuffer, int nLength) const |
- { |
- if(m_lpstrLabel == NULL) |
- return false; |
- ATLASSERT(lpstrBuffer != NULL); |
- if(nLength <= lstrlen(m_lpstrLabel)) |
- return false; |
- |
- SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrLabel); |
- |
- return true; |
- } |
- |
- bool SetLabel(LPCTSTR lpstrLabel) |
- { |
- delete [] m_lpstrLabel; |
- m_lpstrLabel = NULL; |
- int cchLen = lstrlen(lpstrLabel) + 1; |
- ATLTRY(m_lpstrLabel = new TCHAR[cchLen]); |
- if(m_lpstrLabel == NULL) |
- return false; |
- |
- SecureHelper::strcpy_x(m_lpstrLabel, cchLen, lpstrLabel); |
- T* pT = static_cast<T*>(this); |
- pT->CalcLabelRect(); |
- |
- if(m_hWnd != NULL) |
- SetWindowText(lpstrLabel); // Set this for accessibility |
- |
- return true; |
- } |
- |
- bool GetHyperLink(LPTSTR lpstrBuffer, int nLength) const |
- { |
- if(m_lpstrHyperLink == NULL) |
- return false; |
- ATLASSERT(lpstrBuffer != NULL); |
- if(nLength <= lstrlen(m_lpstrHyperLink)) |
- return false; |
- |
- SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrHyperLink); |
- |
- return true; |
- } |
- |
- bool SetHyperLink(LPCTSTR lpstrLink) |
- { |
- delete [] m_lpstrHyperLink; |
- m_lpstrHyperLink = NULL; |
- int cchLen = lstrlen(lpstrLink) + 1; |
- ATLTRY(m_lpstrHyperLink = new TCHAR[cchLen]); |
- if(m_lpstrHyperLink == NULL) |
- return false; |
- |
- SecureHelper::strcpy_x(m_lpstrHyperLink, cchLen, lpstrLink); |
- if(m_lpstrLabel == NULL) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->CalcLabelRect(); |
- } |
-#ifndef _WIN32_WCE |
- if(m_tip.IsWindow()) |
- { |
- m_tip.Activate(TRUE); |
- m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1); |
- } |
-#endif // !_WIN32_WCE |
- return true; |
- } |
- |
- HFONT GetLinkFont() const |
- { |
- return m_hFont; |
- } |
- |
- void SetLinkFont(HFONT hFont) |
- { |
- if(m_bInternalLinkFont && m_hFont != NULL) |
- { |
- ::DeleteObject(m_hFont); |
- m_bInternalLinkFont = false; |
- } |
- m_hFont = hFont; |
- } |
- |
- int GetIdealHeight() const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) |
- return -1; |
- if(!m_bPaintLabel) |
- return -1; |
- |
- CClientDC dc(m_hWnd); |
- RECT rect = { 0 }; |
- GetClientRect(&rect); |
- HFONT hFontOld = dc.SelectFont(m_hFontNormal); |
- RECT rcText = rect; |
- dc.DrawText(_T("NS"), -1, &rcText, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); |
- dc.SelectFont(m_hFont); |
- RECT rcLink = rect; |
- dc.DrawText(_T("NS"), -1, &rcLink, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); |
- dc.SelectFont(hFontOld); |
- return __max(rcText.bottom - rcText.top, rcLink.bottom - rcLink.top); |
- } |
- |
- bool GetIdealSize(SIZE& size) const |
- { |
- int cx = 0, cy = 0; |
- bool bRet = GetIdealSize(cx, cy); |
- if(bRet) |
- { |
- size.cx = cx; |
- size.cy = cy; |
- } |
- return bRet; |
- } |
- |
- bool GetIdealSize(int& cx, int& cy) const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) |
- return false; |
- if(!m_bPaintLabel) |
- return false; |
- |
- CClientDC dc(m_hWnd); |
- RECT rcClient = { 0 }; |
- GetClientRect(&rcClient); |
- RECT rcAll = rcClient; |
- |
- if(IsUsingTags()) |
- { |
- // find tags and label parts |
- LPTSTR lpstrLeft = NULL; |
- int cchLeft = 0; |
- LPTSTR lpstrLink = NULL; |
- int cchLink = 0; |
- LPTSTR lpstrRight = NULL; |
- int cchRight = 0; |
- |
- const T* pT = static_cast<const T*>(this); |
- pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); |
- |
- // get label part rects |
- HFONT hFontOld = dc.SelectFont(m_hFontNormal); |
- RECT rcLeft = rcClient; |
- dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); |
- |
- dc.SelectFont(m_hFont); |
- RECT rcLink = { rcLeft.right, rcLeft.top, rcClient.right, rcClient.bottom }; |
- dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); |
- |
- dc.SelectFont(m_hFontNormal); |
- RECT rcRight = { rcLink.right, rcLink.top, rcClient.right, rcClient.bottom }; |
- dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); |
- |
- dc.SelectFont(hFontOld); |
- |
- int cyMax = __max(rcLeft.bottom, max(rcLink.bottom, rcRight.bottom)); |
- ::SetRect(&rcAll, rcLeft.left, rcLeft.top, rcRight.right, cyMax); |
- } |
- else |
- { |
- HFONT hOldFont = NULL; |
- if(m_hFont != NULL) |
- hOldFont = dc.SelectFont(m_hFont); |
- LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; |
- DWORD dwStyle = GetStyle(); |
- int nDrawStyle = DT_LEFT; |
- if (dwStyle & SS_CENTER) |
- nDrawStyle = DT_CENTER; |
- else if (dwStyle & SS_RIGHT) |
- nDrawStyle = DT_RIGHT; |
- dc.DrawText(lpstrText, -1, &rcAll, nDrawStyle | DT_WORDBREAK | DT_CALCRECT); |
- if(m_hFont != NULL) |
- dc.SelectFont(hOldFont); |
- if (dwStyle & SS_CENTER) |
- { |
- int dx = (rcClient.right - rcAll.right) / 2; |
- ::OffsetRect(&rcAll, dx, 0); |
- } |
- else if (dwStyle & SS_RIGHT) |
- { |
- int dx = rcClient.right - rcAll.right; |
- ::OffsetRect(&rcAll, dx, 0); |
- } |
- } |
- |
- cx = rcAll.right - rcAll.left; |
- cy = rcAll.bottom - rcAll.top; |
- |
- return true; |
- } |
- |
- // for command buttons only |
- bool GetToolTipText(LPTSTR lpstrBuffer, int nLength) const |
- { |
- ATLASSERT(IsCommandButton()); |
- return GetHyperLink(lpstrBuffer, nLength); |
- } |
- |
- bool SetToolTipText(LPCTSTR lpstrToolTipText) |
- { |
- ATLASSERT(IsCommandButton()); |
- return SetHyperLink(lpstrToolTipText); |
- } |
- |
-// Operations |
- BOOL SubclassWindow(HWND hWnd) |
- { |
- ATLASSERT(m_hWnd == NULL); |
- ATLASSERT(::IsWindow(hWnd)); |
-#if (_MSC_VER >= 1300) |
- BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits>::SubclassWindow(hWnd); |
-#else // !(_MSC_VER >= 1300) |
- typedef ATL::CWindowImpl< T, TBase, TWinTraits> _baseClass; |
- BOOL bRet = _baseClass::SubclassWindow(hWnd); |
-#endif // !(_MSC_VER >= 1300) |
- if(bRet) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->Init(); |
- } |
- return bRet; |
- } |
- |
- bool Navigate() |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- bool bRet = true; |
- if(IsNotifyButton()) |
- { |
- NMHDR nmhdr = { m_hWnd, GetDlgCtrlID(), NM_CLICK }; |
- ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr); |
- } |
- else if(IsCommandButton()) |
- { |
- ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd); |
- } |
- else |
- { |
- ATLASSERT(m_lpstrHyperLink != NULL); |
-#ifndef _WIN32_WCE |
- DWORD_PTR dwRet = (DWORD_PTR)::ShellExecute(0, _T("open"), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL); |
- bRet = (dwRet > 32); |
-#else // CE specific |
- SHELLEXECUTEINFO shExeInfo = { sizeof(SHELLEXECUTEINFO), 0, 0, L"open", m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL, 0, 0, 0, 0, 0, 0, 0 }; |
- ::ShellExecuteEx(&shExeInfo); |
- DWORD_PTR dwRet = (DWORD_PTR)shExeInfo.hInstApp; |
- bRet = (dwRet == 0) || (dwRet > 32); |
-#endif // _WIN32_WCE |
- ATLASSERT(bRet); |
- if(bRet) |
- { |
- m_bVisited = true; |
- Invalidate(); |
- } |
- } |
- return bRet; |
- } |
- |
-// Message map and handlers |
- BEGIN_MSG_MAP(CHyperLinkImpl) |
- MESSAGE_HANDLER(WM_CREATE, OnCreate) |
-#ifndef _WIN32_WCE |
- MESSAGE_HANDLER(WM_DESTROY, OnDestroy) |
- MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage) |
-#endif // !_WIN32_WCE |
- MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) |
- MESSAGE_HANDLER(WM_PAINT, OnPaint) |
-#ifndef _WIN32_WCE |
- MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) |
-#endif // !_WIN32_WCE |
- MESSAGE_HANDLER(WM_SETFOCUS, OnFocus) |
- MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus) |
- MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove) |
-#ifndef _WIN32_WCE |
- MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave) |
-#endif // !_WIN32_WCE |
- MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown) |
- MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp) |
- MESSAGE_HANDLER(WM_CHAR, OnChar) |
- MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode) |
- MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor) |
- MESSAGE_HANDLER(WM_ENABLE, OnEnable) |
- MESSAGE_HANDLER(WM_GETFONT, OnGetFont) |
- MESSAGE_HANDLER(WM_SETFONT, OnSetFont) |
- MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState) |
- MESSAGE_HANDLER(WM_SIZE, OnSize) |
- END_MSG_MAP() |
- |
- LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->Init(); |
- return 0; |
- } |
- |
-#ifndef _WIN32_WCE |
- LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- if(m_tip.IsWindow()) |
- { |
- m_tip.DestroyWindow(); |
- m_tip.m_hWnd = NULL; |
- } |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) |
- { |
- MSG msg = { m_hWnd, uMsg, wParam, lParam }; |
- if(m_tip.IsWindow() && IsUsingToolTip()) |
- m_tip.RelayEvent(&msg); |
- bHandled = FALSE; |
- return 1; |
- } |
-#endif // !_WIN32_WCE |
- |
- LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- return 1; // no background painting needed (we do it all during WM_PAINT) |
- } |
- |
- LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- if(!m_bPaintLabel) |
- { |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- T* pT = static_cast<T*>(this); |
- if(wParam != NULL) |
- { |
- pT->DoEraseBackground((HDC)wParam); |
- pT->DoPaint((HDC)wParam); |
- } |
- else |
- { |
- CPaintDC dc(m_hWnd); |
- pT->DoEraseBackground(dc.m_hDC); |
- pT->DoPaint(dc.m_hDC); |
- } |
- |
- return 0; |
- } |
- |
- LRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- if(m_bPaintLabel) |
- Invalidate(); |
- else |
- bHandled = FALSE; |
- return 0; |
- } |
- |
- LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) |
- { |
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; |
- if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt)) |
- { |
- ::SetCursor(m_hCursor); |
- if(IsUnderlineHover()) |
- { |
- if(!m_bHover) |
- { |
- m_bHover = true; |
- InvalidateRect(&m_rcLink); |
- UpdateWindow(); |
-#ifndef _WIN32_WCE |
- StartTrackMouseLeave(); |
-#endif // !_WIN32_WCE |
- } |
- } |
- } |
- else |
- { |
- if(IsUnderlineHover()) |
- { |
- if(m_bHover) |
- { |
- m_bHover = false; |
- InvalidateRect(&m_rcLink); |
- UpdateWindow(); |
- } |
- } |
- bHandled = FALSE; |
- } |
- return 0; |
- } |
- |
-#ifndef _WIN32_WCE |
- LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- if(IsUnderlineHover() && m_bHover) |
- { |
- m_bHover = false; |
- InvalidateRect(&m_rcLink); |
- UpdateWindow(); |
- } |
- return 0; |
- } |
-#endif // !_WIN32_WCE |
- |
- LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; |
- if(::PtInRect(&m_rcLink, pt)) |
- { |
- SetFocus(); |
- SetCapture(); |
- } |
- return 0; |
- } |
- |
- LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- if(GetCapture() == m_hWnd) |
- { |
- ReleaseCapture(); |
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; |
- if(::PtInRect(&m_rcLink, pt)) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->Navigate(); |
- } |
- } |
- return 0; |
- } |
- |
- LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- if(wParam == VK_RETURN || wParam == VK_SPACE) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->Navigate(); |
- } |
- return 0; |
- } |
- |
- LRESULT OnGetDlgCode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- return DLGC_WANTCHARS; |
- } |
- |
- LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- POINT pt = { 0, 0 }; |
- GetCursorPos(&pt); |
- ScreenToClient(&pt); |
- if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRect(&m_rcLink, pt)) |
- { |
- return TRUE; |
- } |
- bHandled = FALSE; |
- return FALSE; |
- } |
- |
- LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- Invalidate(); |
- UpdateWindow(); |
- return 0; |
- } |
- |
- LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- return (LRESULT)m_hFontNormal; |
- } |
- |
- LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- m_hFontNormal = (HFONT)wParam; |
- if((BOOL)lParam) |
- { |
- Invalidate(); |
- UpdateWindow(); |
- } |
- return 0; |
- } |
- |
- LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- // If the control is subclassed or superclassed, this message can cause |
- // repainting without WM_PAINT. We don't use this state, so just do nothing. |
- return 0; |
- } |
- |
- LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->CalcLabelRect(); |
- pT->Invalidate(); |
- return 0; |
- } |
- |
-// Implementation |
- void Init() |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- |
- // Check if we should paint a label |
- const int cchBuff = 8; |
- TCHAR szBuffer[cchBuff] = { 0 }; |
- if(::GetClassName(m_hWnd, szBuffer, cchBuff)) |
- { |
- if(lstrcmpi(szBuffer, _T("static")) == 0) |
- { |
- ModifyStyle(0, SS_NOTIFY); // we need this |
- DWORD dwStyle = GetStyle() & 0x000000FF; |
-#ifndef _WIN32_WCE |
- if(dwStyle == SS_ICON || dwStyle == SS_BLACKRECT || dwStyle == SS_GRAYRECT || |
- dwStyle == SS_WHITERECT || dwStyle == SS_BLACKFRAME || dwStyle == SS_GRAYFRAME || |
- dwStyle == SS_WHITEFRAME || dwStyle == SS_OWNERDRAW || |
- dwStyle == SS_BITMAP || dwStyle == SS_ENHMETAFILE) |
-#else // CE specific |
- if(dwStyle == SS_ICON || dwStyle == SS_BITMAP) |
-#endif // _WIN32_WCE |
- m_bPaintLabel = false; |
- } |
- } |
- |
- // create or load a cursor |
-#if (WINVER >= 0x0500) || defined(_WIN32_WCE) |
- m_hCursor = ::LoadCursor(NULL, IDC_HAND); |
-#else |
- m_hCursor = ::CreateCursor(ModuleHelper::GetModuleInstance(), _AtlHyperLink_CursorData.xHotSpot, _AtlHyperLink_CursorData.yHotSpot, _AtlHyperLink_CursorData.cxWidth, _AtlHyperLink_CursorData.cyHeight, _AtlHyperLink_CursorData.arrANDPlane, _AtlHyperLink_CursorData.arrXORPlane); |
-#endif |
- ATLASSERT(m_hCursor != NULL); |
- |
- // set font |
- if(m_bPaintLabel) |
- { |
- ATL::CWindow wnd = GetParent(); |
- m_hFontNormal = wnd.GetFont(); |
- if(m_hFontNormal == NULL) |
- m_hFontNormal = (HFONT)::GetStockObject(SYSTEM_FONT); |
- if(m_hFontNormal != NULL && m_hFont == NULL) |
- { |
- LOGFONT lf = { 0 }; |
- CFontHandle font = m_hFontNormal; |
- font.GetLogFont(&lf); |
- if(IsUsingTagsBold()) |
- lf.lfWeight = FW_BOLD; |
- else if(!IsNotUnderlined()) |
- lf.lfUnderline = TRUE; |
- m_hFont = ::CreateFontIndirect(&lf); |
- m_bInternalLinkFont = true; |
- ATLASSERT(m_hFont != NULL); |
- } |
- } |
- |
-#ifndef _WIN32_WCE |
- // create a tool tip |
- m_tip.Create(m_hWnd); |
- ATLASSERT(m_tip.IsWindow()); |
-#endif // !_WIN32_WCE |
- |
- // set label (defaults to window text) |
- if(m_lpstrLabel == NULL) |
- { |
- int nLen = GetWindowTextLength(); |
- if(nLen > 0) |
- { |
- CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff; |
- LPTSTR lpstrText = buff.Allocate(nLen + 1); |
- ATLASSERT(lpstrText != NULL); |
- if((lpstrText != NULL) && (GetWindowText(lpstrText, nLen + 1) > 0)) |
- SetLabel(lpstrText); |
- } |
- } |
- |
- T* pT = static_cast<T*>(this); |
- pT->CalcLabelRect(); |
- |
- // set hyperlink (defaults to label), or just activate tool tip if already set |
- if(m_lpstrHyperLink == NULL && !IsCommandButton()) |
- { |
- if(m_lpstrLabel != NULL) |
- SetHyperLink(m_lpstrLabel); |
- } |
-#ifndef _WIN32_WCE |
- else |
- { |
- m_tip.Activate(TRUE); |
- m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1); |
- } |
-#endif // !_WIN32_WCE |
- |
- // set link colors |
- if(m_bPaintLabel) |
- { |
- ATL::CRegKey rk; |
- LONG lRet = rk.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Explorer\\Settings")); |
- if(lRet == 0) |
- { |
- const int cchValue = 12; |
- TCHAR szValue[cchValue] = { 0 }; |
-#if (_ATL_VER >= 0x0700) |
- ULONG ulCount = cchValue; |
- lRet = rk.QueryStringValue(_T("Anchor Color"), szValue, &ulCount); |
-#else |
- DWORD dwCount = cchValue * sizeof(TCHAR); |
- lRet = rk.QueryValue(szValue, _T("Anchor Color"), &dwCount); |
-#endif |
- if(lRet == 0) |
- { |
- COLORREF clr = pT->_ParseColorString(szValue); |
- ATLASSERT(clr != CLR_INVALID); |
- if(clr != CLR_INVALID) |
- m_clrLink = clr; |
- } |
- |
-#if (_ATL_VER >= 0x0700) |
- ulCount = cchValue; |
- lRet = rk.QueryStringValue(_T("Anchor Color Visited"), szValue, &ulCount); |
-#else |
- dwCount = cchValue * sizeof(TCHAR); |
- lRet = rk.QueryValue(szValue, _T("Anchor Color Visited"), &dwCount); |
-#endif |
- if(lRet == 0) |
- { |
- COLORREF clr = pT->_ParseColorString(szValue); |
- ATLASSERT(clr != CLR_INVALID); |
- if(clr != CLR_INVALID) |
- m_clrVisited = clr; |
- } |
- } |
- } |
- } |
- |
- static COLORREF _ParseColorString(LPTSTR lpstr) |
- { |
- int c[3] = { -1, -1, -1 }; |
- LPTSTR p = NULL; |
- for(int i = 0; i < 2; i++) |
- { |
- for(p = lpstr; *p != _T('\0'); p = ::CharNext(p)) |
- { |
- if(*p == _T(',')) |
- { |
- *p = _T('\0'); |
- c[i] = T::_xttoi(lpstr); |
- lpstr = &p[1]; |
- break; |
- } |
- } |
- if(c[i] == -1) |
- return CLR_INVALID; |
- } |
- if(*lpstr == _T('\0')) |
- return CLR_INVALID; |
- c[2] = T::_xttoi(lpstr); |
- |
- return RGB(c[0], c[1], c[2]); |
- } |
- |
- bool CalcLabelRect() |
- { |
- if(!::IsWindow(m_hWnd)) |
- return false; |
- if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL) |
- return false; |
- |
- CClientDC dc(m_hWnd); |
- RECT rcClient = { 0 }; |
- GetClientRect(&rcClient); |
- m_rcLink = rcClient; |
- if(!m_bPaintLabel) |
- return true; |
- |
- if(IsUsingTags()) |
- { |
- // find tags and label parts |
- LPTSTR lpstrLeft = NULL; |
- int cchLeft = 0; |
- LPTSTR lpstrLink = NULL; |
- int cchLink = 0; |
- LPTSTR lpstrRight = NULL; |
- int cchRight = 0; |
- |
- T* pT = static_cast<T*>(this); |
- pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); |
- ATLASSERT(lpstrLink != NULL); |
- ATLASSERT(cchLink > 0); |
- |
- // get label part rects |
- HFONT hFontOld = dc.SelectFont(m_hFontNormal); |
- |
- RECT rcLeft = rcClient; |
- if(lpstrLeft != NULL) |
- dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); |
- |
- dc.SelectFont(m_hFont); |
- RECT rcLink = rcClient; |
- if(lpstrLeft != NULL) |
- rcLink.left = rcLeft.right; |
- dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | DT_WORDBREAK | DT_CALCRECT); |
- |
- dc.SelectFont(hFontOld); |
- |
- m_rcLink = rcLink; |
- } |
- else |
- { |
- HFONT hOldFont = NULL; |
- if(m_hFont != NULL) |
- hOldFont = dc.SelectFont(m_hFont); |
- LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; |
- DWORD dwStyle = GetStyle(); |
- int nDrawStyle = DT_LEFT; |
- if (dwStyle & SS_CENTER) |
- nDrawStyle = DT_CENTER; |
- else if (dwStyle & SS_RIGHT) |
- nDrawStyle = DT_RIGHT; |
- dc.DrawText(lpstrText, -1, &m_rcLink, nDrawStyle | DT_WORDBREAK | DT_CALCRECT); |
- if(m_hFont != NULL) |
- dc.SelectFont(hOldFont); |
- if (dwStyle & SS_CENTER) |
- { |
- int dx = (rcClient.right - m_rcLink.right) / 2; |
- ::OffsetRect(&m_rcLink, dx, 0); |
- } |
- else if (dwStyle & SS_RIGHT) |
- { |
- int dx = rcClient.right - m_rcLink.right; |
- ::OffsetRect(&m_rcLink, dx, 0); |
- } |
- } |
- |
- return true; |
- } |
- |
- void CalcLabelParts(LPTSTR& lpstrLeft, int& cchLeft, LPTSTR& lpstrLink, int& cchLink, LPTSTR& lpstrRight, int& cchRight) const |
- { |
- lpstrLeft = NULL; |
- cchLeft = 0; |
- lpstrLink = NULL; |
- cchLink = 0; |
- lpstrRight = NULL; |
- cchRight = 0; |
- |
- LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; |
- int cchText = lstrlen(lpstrText); |
- bool bOutsideLink = true; |
- for(int i = 0; i < cchText; i++) |
- { |
- if(lpstrText[i] != _T('<')) |
- continue; |
- |
- if(bOutsideLink) |
- { |
- if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 3, _T("<A>"), 3) == CSTR_EQUAL) |
- { |
- if(i > 0) |
- { |
- lpstrLeft = lpstrText; |
- cchLeft = i; |
- } |
- lpstrLink = &lpstrText[i + 3]; |
- bOutsideLink = false; |
- } |
- } |
- else |
- { |
- if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 4, _T("</A>"), 4) == CSTR_EQUAL) |
- { |
- cchLink = i - 3 - cchLeft; |
- if(lpstrText[i + 4] != 0) |
- { |
- lpstrRight = &lpstrText[i + 4]; |
- cchRight = cchText - (i + 4); |
- break; |
- } |
- } |
- } |
- } |
- |
- } |
- |
- void DoEraseBackground(CDCHandle dc) |
- { |
- HBRUSH hBrush = (HBRUSH)::SendMessage(GetParent(), WM_CTLCOLORSTATIC, (WPARAM)dc.m_hDC, (LPARAM)m_hWnd); |
- if(hBrush != NULL) |
- { |
- RECT rect = { 0 }; |
- GetClientRect(&rect); |
- dc.FillRect(&rect, hBrush); |
- } |
- } |
- |
- void DoPaint(CDCHandle dc) |
- { |
- if(IsUsingTags()) |
- { |
- // find tags and label parts |
- LPTSTR lpstrLeft = NULL; |
- int cchLeft = 0; |
- LPTSTR lpstrLink = NULL; |
- int cchLink = 0; |
- LPTSTR lpstrRight = NULL; |
- int cchRight = 0; |
- |
- T* pT = static_cast<T*>(this); |
- pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight); |
- |
- // get label part rects |
- RECT rcClient = { 0 }; |
- GetClientRect(&rcClient); |
- |
- dc.SetBkMode(TRANSPARENT); |
- HFONT hFontOld = dc.SelectFont(m_hFontNormal); |
- |
- if(lpstrLeft != NULL) |
- dc.DrawText(lpstrLeft, cchLeft, &rcClient, DT_LEFT | DT_WORDBREAK); |
- |
- COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT))); |
- if(m_hFont != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover))) |
- dc.SelectFont(m_hFont); |
- else |
- dc.SelectFont(m_hFontNormal); |
- |
- dc.DrawText(lpstrLink, cchLink, &m_rcLink, DT_LEFT | DT_WORDBREAK); |
- |
- dc.SetTextColor(clrOld); |
- dc.SelectFont(m_hFontNormal); |
- if(lpstrRight != NULL) |
- { |
- RECT rcRight = { m_rcLink.right, m_rcLink.top, rcClient.right, rcClient.bottom }; |
- dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | DT_WORDBREAK); |
- } |
- |
- if(GetFocus() == m_hWnd) |
- dc.DrawFocusRect(&m_rcLink); |
- |
- dc.SelectFont(hFontOld); |
- } |
- else |
- { |
- dc.SetBkMode(TRANSPARENT); |
- COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT))); |
- |
- HFONT hFontOld = NULL; |
- if(m_hFont != NULL && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover))) |
- hFontOld = dc.SelectFont(m_hFont); |
- else |
- hFontOld = dc.SelectFont(m_hFontNormal); |
- |
- LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink; |
- |
- DWORD dwStyle = GetStyle(); |
- int nDrawStyle = DT_LEFT; |
- if (dwStyle & SS_CENTER) |
- nDrawStyle = DT_CENTER; |
- else if (dwStyle & SS_RIGHT) |
- nDrawStyle = DT_RIGHT; |
- |
- dc.DrawText(lpstrText, -1, &m_rcLink, nDrawStyle | DT_WORDBREAK); |
- |
- if(GetFocus() == m_hWnd) |
- dc.DrawFocusRect(&m_rcLink); |
- |
- dc.SetTextColor(clrOld); |
- dc.SelectFont(hFontOld); |
- } |
- } |
- |
-#ifndef _WIN32_WCE |
- BOOL StartTrackMouseLeave() |
- { |
- TRACKMOUSEEVENT tme = { 0 }; |
- tme.cbSize = sizeof(tme); |
- tme.dwFlags = TME_LEAVE; |
- tme.hwndTrack = m_hWnd; |
- return _TrackMouseEvent(&tme); |
- } |
-#endif // !_WIN32_WCE |
- |
-// Implementation helpers |
- bool IsUnderlined() const |
- { |
- return ((m_dwExtendedStyle & (HLINK_NOTUNDERLINED | HLINK_UNDERLINEHOVER)) == 0); |
- } |
- |
- bool IsNotUnderlined() const |
- { |
- return ((m_dwExtendedStyle & HLINK_NOTUNDERLINED) != 0); |
- } |
- |
- bool IsUnderlineHover() const |
- { |
- return ((m_dwExtendedStyle & HLINK_UNDERLINEHOVER) != 0); |
- } |
- |
- bool IsCommandButton() const |
- { |
- return ((m_dwExtendedStyle & HLINK_COMMANDBUTTON) != 0); |
- } |
- |
- bool IsNotifyButton() const |
- { |
- return ((m_dwExtendedStyle & HLINK_NOTIFYBUTTON) == HLINK_NOTIFYBUTTON); |
- } |
- |
- bool IsUsingTags() const |
- { |
- return ((m_dwExtendedStyle & HLINK_USETAGS) != 0); |
- } |
- |
- bool IsUsingTagsBold() const |
- { |
- return ((m_dwExtendedStyle & HLINK_USETAGSBOLD) == HLINK_USETAGSBOLD); |
- } |
- |
- bool IsUsingToolTip() const |
- { |
- return ((m_dwExtendedStyle & HLINK_NOTOOLTIP) == 0); |
- } |
- |
- static int _xttoi(const TCHAR* nptr) |
- { |
-#ifndef _ATL_MIN_CRT |
- return _ttoi(nptr); |
-#else // _ATL_MIN_CRT |
- while(*nptr == _T(' ')) // skip spaces |
- ++nptr; |
- |
- int c = (int)(_TUCHAR)*nptr++; |
- int sign = c; // save sign indication |
- if (c == _T('-') || c == _T('+')) |
- c = (int)(_TUCHAR)*nptr++; // skip sign |
- |
- int total = 0; |
- while((TCHAR)c >= _T('0') && (TCHAR)c <= _T('9')) |
- { |
- total = 10 * total + ((TCHAR)c - _T('0')); // accumulate digit |
- c = (int)(_TUCHAR)*nptr++; // get next char |
- } |
- |
- // return result, negated if necessary |
- return ((TCHAR)sign != _T('-')) ? total : -total; |
-#endif // _ATL_MIN_CRT |
- } |
-}; |
- |
- |
-class CHyperLink : public CHyperLinkImpl<CHyperLink> |
-{ |
-public: |
- DECLARE_WND_CLASS(_T("WTL_HyperLink")) |
-}; |
- |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// CWaitCursor - displays a wait cursor |
- |
-class CWaitCursor |
-{ |
-public: |
-// Data |
- HCURSOR m_hWaitCursor; |
- HCURSOR m_hOldCursor; |
- bool m_bInUse; |
- |
-// Constructor/destructor |
- CWaitCursor(bool bSet = true, LPCTSTR lpstrCursor = IDC_WAIT, bool bSys = true) : m_hOldCursor(NULL), m_bInUse(false) |
- { |
- HINSTANCE hInstance = bSys ? NULL : ModuleHelper::GetResourceInstance(); |
- m_hWaitCursor = ::LoadCursor(hInstance, lpstrCursor); |
- ATLASSERT(m_hWaitCursor != NULL); |
- |
- if(bSet) |
- Set(); |
- } |
- |
- ~CWaitCursor() |
- { |
- Restore(); |
- } |
- |
-// Methods |
- bool Set() |
- { |
- if(m_bInUse) |
- return false; |
- m_hOldCursor = ::SetCursor(m_hWaitCursor); |
- m_bInUse = true; |
- return true; |
- } |
- |
- bool Restore() |
- { |
- if(!m_bInUse) |
- return false; |
- ::SetCursor(m_hOldCursor); |
- m_bInUse = false; |
- return true; |
- } |
-}; |
- |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// CCustomWaitCursor - for custom and animated cursors |
- |
-class CCustomWaitCursor : public CWaitCursor |
-{ |
-public: |
-// Constructor/destructor |
- CCustomWaitCursor(ATL::_U_STRINGorID cursor, bool bSet = true, HINSTANCE hInstance = NULL) : |
- CWaitCursor(false, IDC_WAIT, true) |
- { |
- if(hInstance == NULL) |
- hInstance = ModuleHelper::GetResourceInstance(); |
- m_hWaitCursor = (HCURSOR)::LoadImage(hInstance, cursor.m_lpstr, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE); |
- |
- if(bSet) |
- Set(); |
- } |
- |
- ~CCustomWaitCursor() |
- { |
- Restore(); |
-#if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) |
- ::DestroyCursor(m_hWaitCursor); |
-#endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP))) |
- } |
-}; |
- |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// CMultiPaneStatusBarCtrl - Status Bar with multiple panes |
- |
-template <class T, class TBase = CStatusBarCtrl> |
-class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl : public ATL::CWindowImpl< T, TBase > |
-{ |
-public: |
- DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) |
- |
-// Data |
- enum { m_cxPaneMargin = 3 }; |
- |
- int m_nPanes; |
- int* m_pPane; |
- |
-// Constructor/destructor |
- CMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL) |
- { } |
- |
- ~CMultiPaneStatusBarCtrlImpl() |
- { |
- delete [] m_pPane; |
- } |
- |
-// Methods |
- HWND Create(HWND hWndParent, LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) |
- { |
-#if (_MSC_VER >= 1300) |
- return ATL::CWindowImpl< T, TBase >::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID); |
-#else // !(_MSC_VER >= 1300) |
- typedef ATL::CWindowImpl< T, TBase > _baseClass; |
- return _baseClass::Create(hWndParent, rcDefault, lpstrText, dwStyle, 0, nID); |
-#endif // !(_MSC_VER >= 1300) |
- } |
- |
- HWND Create(HWND hWndParent, UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR) |
- { |
- const int cchMax = 128; // max text length is 127 for status bars (+1 for null) |
- TCHAR szText[cchMax]; |
- szText[0] = 0; |
- ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax); |
- return Create(hWndParent, szText, dwStyle, nID); |
- } |
- |
- BOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(nPanes > 0); |
- |
- m_nPanes = nPanes; |
- delete [] m_pPane; |
- m_pPane = NULL; |
- |
- ATLTRY(m_pPane = new int[nPanes]); |
- ATLASSERT(m_pPane != NULL); |
- if(m_pPane == NULL) |
- return FALSE; |
- |
- CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff; |
- int* pPanesPos = buff.Allocate(nPanes); |
- ATLASSERT(pPanesPos != NULL); |
- if(pPanesPos == NULL) |
- return FALSE; |
- |
- SecureHelper::memcpy_x(m_pPane, nPanes * sizeof(int), pPanes, nPanes * sizeof(int)); |
- |
- // get status bar DC and set font |
- CClientDC dc(m_hWnd); |
- HFONT hOldFont = dc.SelectFont(GetFont()); |
- |
- // get status bar borders |
- int arrBorders[3] = { 0 }; |
- GetBorders(arrBorders); |
- |
- const int cchBuff = 128; |
- TCHAR szBuff[cchBuff] = { 0 }; |
- SIZE size = { 0, 0 }; |
- int cxLeft = arrBorders[0]; |
- |
- // calculate right edge of each part |
- for(int i = 0; i < nPanes; i++) |
- { |
- if(pPanes[i] == ID_DEFAULT_PANE) |
- { |
- // make very large, will be resized later |
- pPanesPos[i] = INT_MAX / 2; |
- } |
- else |
- { |
- ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff); |
- dc.GetTextExtent(szBuff, lstrlen(szBuff), &size); |
- T* pT = static_cast<T*>(this); |
- pT; |
- pPanesPos[i] = cxLeft + size.cx + arrBorders[2] + 2 * pT->m_cxPaneMargin; |
- } |
- cxLeft = pPanesPos[i]; |
- } |
- |
- BOOL bRet = SetParts(nPanes, pPanesPos); |
- |
- if(bRet && bSetText) |
- { |
- for(int i = 0; i < nPanes; i++) |
- { |
- if(pPanes[i] != ID_DEFAULT_PANE) |
- { |
- ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff); |
- SetPaneText(m_pPane[i], szBuff); |
- } |
- } |
- } |
- |
- dc.SelectFont(hOldFont); |
- return bRet; |
- } |
- |
- bool GetPaneTextLength(int nPaneID, int* pcchLength = NULL, int* pnType = NULL) const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- int nIndex = GetPaneIndexFromID(nPaneID); |
- if(nIndex == -1) |
- return false; |
- |
- int nLength = GetTextLength(nIndex, pnType); |
- if(pcchLength != NULL) |
- *pcchLength = nLength; |
- |
- return true; |
- } |
- |
- BOOL GetPaneText(int nPaneID, LPTSTR lpstrText, int* pcchLength = NULL, int* pnType = NULL) const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- int nIndex = GetPaneIndexFromID(nPaneID); |
- if(nIndex == -1) |
- return FALSE; |
- |
- int nLength = GetText(nIndex, lpstrText, pnType); |
- if(pcchLength != NULL) |
- *pcchLength = nLength; |
- |
- return TRUE; |
- } |
- |
- BOOL SetPaneText(int nPaneID, LPCTSTR lpstrText, int nType = 0) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- int nIndex = GetPaneIndexFromID(nPaneID); |
- if(nIndex == -1) |
- return FALSE; |
- |
- return SetText(nIndex, lpstrText, nType); |
- } |
- |
- BOOL GetPaneRect(int nPaneID, LPRECT lpRect) const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- int nIndex = GetPaneIndexFromID(nPaneID); |
- if(nIndex == -1) |
- return FALSE; |
- |
- return GetRect(nIndex, lpRect); |
- } |
- |
- BOOL SetPaneWidth(int nPaneID, int cxWidth) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(nPaneID != ID_DEFAULT_PANE); // Can't resize this one |
- int nIndex = GetPaneIndexFromID(nPaneID); |
- if(nIndex == -1) |
- return FALSE; |
- |
- // get pane positions |
- CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff; |
- int* pPanesPos = buff.Allocate(m_nPanes); |
- if(pPanesPos == NULL) |
- return FALSE; |
- GetParts(m_nPanes, pPanesPos); |
- // calculate offset |
- int cxPaneWidth = pPanesPos[nIndex] - ((nIndex == 0) ? 0 : pPanesPos[nIndex - 1]); |
- int cxOff = cxWidth - cxPaneWidth; |
- // find variable width pane |
- int nDef = m_nPanes; |
- for(int i = 0; i < m_nPanes; i++) |
- { |
- if(m_pPane[i] == ID_DEFAULT_PANE) |
- { |
- nDef = i; |
- break; |
- } |
- } |
- // resize |
- if(nIndex < nDef) // before default pane |
- { |
- for(int i = nIndex; i < nDef; i++) |
- pPanesPos[i] += cxOff; |
- |
- } |
- else // after default one |
- { |
- for(int i = nDef; i < nIndex; i++) |
- pPanesPos[i] -= cxOff; |
- } |
- // set pane postions |
- return SetParts(m_nPanes, pPanesPos); |
- } |
- |
-#if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) |
- BOOL GetPaneTipText(int nPaneID, LPTSTR lpstrText, int nSize) const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- int nIndex = GetPaneIndexFromID(nPaneID); |
- if(nIndex == -1) |
- return FALSE; |
- |
- GetTipText(nIndex, lpstrText, nSize); |
- return TRUE; |
- } |
- |
- BOOL SetPaneTipText(int nPaneID, LPCTSTR lpstrText) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- int nIndex = GetPaneIndexFromID(nPaneID); |
- if(nIndex == -1) |
- return FALSE; |
- |
- SetTipText(nIndex, lpstrText); |
- return TRUE; |
- } |
-#endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE) |
- |
-#if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) |
- BOOL GetPaneIcon(int nPaneID, HICON& hIcon) const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- int nIndex = GetPaneIndexFromID(nPaneID); |
- if(nIndex == -1) |
- return FALSE; |
- |
- hIcon = GetIcon(nIndex); |
- return TRUE; |
- } |
- |
- BOOL SetPaneIcon(int nPaneID, HICON hIcon) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- int nIndex = GetPaneIndexFromID(nPaneID); |
- if(nIndex == -1) |
- return FALSE; |
- |
- return SetIcon(nIndex, hIcon); |
- } |
-#endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500)) |
- |
-// Message map and handlers |
- BEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl< T >) |
- MESSAGE_HANDLER(WM_SIZE, OnSize) |
- END_MSG_MAP() |
- |
- LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- LRESULT lRet = DefWindowProc(uMsg, wParam, lParam); |
- if(wParam != SIZE_MINIMIZED && m_nPanes > 0) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->UpdatePanesLayout(); |
- } |
- return lRet; |
- } |
- |
-// Implementation |
- BOOL UpdatePanesLayout() |
- { |
- // get pane positions |
- CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff; |
- int* pPanesPos = buff.Allocate(m_nPanes); |
- ATLASSERT(pPanesPos != NULL); |
- if(pPanesPos == NULL) |
- return FALSE; |
- int nRet = GetParts(m_nPanes, pPanesPos); |
- ATLASSERT(nRet == m_nPanes); |
- if(nRet != m_nPanes) |
- return FALSE; |
- // calculate offset |
- RECT rcClient = { 0 }; |
- GetClientRect(&rcClient); |
- int cxOff = rcClient.right - pPanesPos[m_nPanes - 1]; |
-#ifndef _WIN32_WCE |
- // Move panes left if size grip box is present |
- if((GetStyle() & SBARS_SIZEGRIP) != 0) |
- cxOff -= ::GetSystemMetrics(SM_CXVSCROLL) + ::GetSystemMetrics(SM_CXEDGE); |
-#endif // !_WIN32_WCE |
- // find variable width pane |
- int i; |
- for(i = 0; i < m_nPanes; i++) |
- { |
- if(m_pPane[i] == ID_DEFAULT_PANE) |
- break; |
- } |
- // resize all panes from the variable one to the right |
- if((i < m_nPanes) && (pPanesPos[i] + cxOff) > ((i == 0) ? 0 : pPanesPos[i - 1])) |
- { |
- for(; i < m_nPanes; i++) |
- pPanesPos[i] += cxOff; |
- } |
- // set pane postions |
- return SetParts(m_nPanes, pPanesPos); |
- } |
- |
- int GetPaneIndexFromID(int nPaneID) const |
- { |
- for(int i = 0; i < m_nPanes; i++) |
- { |
- if(m_pPane[i] == nPaneID) |
- return i; |
- } |
- |
- return -1; // not found |
- } |
-}; |
- |
-class CMultiPaneStatusBarCtrl : public CMultiPaneStatusBarCtrlImpl<CMultiPaneStatusBarCtrl> |
-{ |
-public: |
- DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName()) |
-}; |
- |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// CPaneContainer - provides header with title and close button for panes |
- |
-// pane container extended styles |
-#define PANECNT_NOCLOSEBUTTON 0x00000001 |
-#define PANECNT_VERTICAL 0x00000002 |
-#define PANECNT_FLATBORDER 0x00000004 |
-#define PANECNT_NOBORDER 0x00000008 |
- |
-template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits> |
-class ATL_NO_VTABLE CPaneContainerImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CCustomDraw< T > |
-{ |
-public: |
- DECLARE_WND_CLASS_EX(NULL, 0, -1) |
- |
-// Constants |
- enum |
- { |
- m_cxyBorder = 2, |
- m_cxyTextOffset = 4, |
- m_cxyBtnOffset = 1, |
- |
- m_cchTitle = 80, |
- |
- m_cxImageTB = 13, |
- m_cyImageTB = 11, |
- m_cxyBtnAddTB = 7, |
- |
- m_cxToolBar = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + m_cxyBtnOffset, |
- |
- m_xBtnImageLeft = 6, |
- m_yBtnImageTop = 5, |
- m_xBtnImageRight = 12, |
- m_yBtnImageBottom = 11, |
- |
- m_nCloseBtnID = ID_PANE_CLOSE |
- }; |
- |
-// Data members |
- CToolBarCtrl m_tb; |
- ATL::CWindow m_wndClient; |
- int m_cxyHeader; |
- TCHAR m_szTitle[m_cchTitle]; |
- DWORD m_dwExtendedStyle; // Pane container specific extended styles |
- |
- |
-// Constructor |
- CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0) |
- { |
- m_szTitle[0] = 0; |
- } |
- |
-// Attributes |
- DWORD GetPaneContainerExtendedStyle() const |
- { |
- return m_dwExtendedStyle; |
- } |
- |
- DWORD SetPaneContainerExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) |
- { |
- DWORD dwPrevStyle = m_dwExtendedStyle; |
- if(dwMask == 0) |
- m_dwExtendedStyle = dwExtendedStyle; |
- else |
- m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); |
- if(m_hWnd != NULL) |
- { |
- T* pT = static_cast<T*>(this); |
- bool bUpdate = false; |
- |
- if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) != 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)) // add close button |
- { |
- pT->CreateCloseButton(); |
- bUpdate = true; |
- } |
- else if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) == 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) != 0)) // remove close button |
- { |
- pT->DestroyCloseButton(); |
- bUpdate = true; |
- } |
- |
- if((dwPrevStyle & PANECNT_VERTICAL) != (m_dwExtendedStyle & PANECNT_VERTICAL)) // change orientation |
- { |
- pT->CalcSize(); |
- bUpdate = true; |
- } |
- |
- if((dwPrevStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER)) != |
- (m_dwExtendedStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER))) // change border |
- { |
- bUpdate = true; |
- } |
- |
- if(bUpdate) |
- pT->UpdateLayout(); |
- } |
- return dwPrevStyle; |
- } |
- |
- HWND GetClient() const |
- { |
- return m_wndClient; |
- } |
- |
- HWND SetClient(HWND hWndClient) |
- { |
- HWND hWndOldClient = m_wndClient; |
- m_wndClient = hWndClient; |
- if(m_hWnd != NULL) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->UpdateLayout(); |
- } |
- return hWndOldClient; |
- } |
- |
- BOOL GetTitle(LPTSTR lpstrTitle, int cchLength) const |
- { |
- ATLASSERT(lpstrTitle != NULL); |
- |
- errno_t nRet = SecureHelper::strncpy_x(lpstrTitle, cchLength, m_szTitle, _TRUNCATE); |
- |
- return (nRet == 0 || nRet == STRUNCATE); |
- } |
- |
- BOOL SetTitle(LPCTSTR lpstrTitle) |
- { |
- ATLASSERT(lpstrTitle != NULL); |
- |
- errno_t nRet = SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE); |
- bool bRet = (nRet == 0 || nRet == STRUNCATE); |
- if(bRet && m_hWnd != NULL) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->UpdateLayout(); |
- } |
- |
- return bRet; |
- } |
- |
- int GetTitleLength() const |
- { |
- return lstrlen(m_szTitle); |
- } |
- |
-// Methods |
- HWND Create(HWND hWndParent, LPCTSTR lpstrTitle = NULL, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, |
- DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL) |
- { |
- if(lpstrTitle != NULL) |
- SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE); |
-#if (_MSC_VER >= 1300) |
- return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); |
-#else // !(_MSC_VER >= 1300) |
- typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; |
- return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); |
-#endif // !(_MSC_VER >= 1300) |
- } |
- |
- HWND Create(HWND hWndParent, UINT uTitleID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, |
- DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL) |
- { |
- if(uTitleID != 0U) |
- ::LoadString(ModuleHelper::GetResourceInstance(), uTitleID, m_szTitle, m_cchTitle); |
-#if (_MSC_VER >= 1300) |
- return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); |
-#else // !(_MSC_VER >= 1300) |
- typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass; |
- return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam); |
-#endif // !(_MSC_VER >= 1300) |
- } |
- |
- BOOL EnableCloseButton(BOOL bEnable) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- T* pT = static_cast<T*>(this); |
- pT; // avoid level 4 warning |
- return (m_tb.m_hWnd != NULL) ? m_tb.EnableButton(pT->m_nCloseBtnID, bEnable) : FALSE; |
- } |
- |
- void UpdateLayout() |
- { |
- RECT rcClient = { 0 }; |
- GetClientRect(&rcClient); |
- T* pT = static_cast<T*>(this); |
- pT->UpdateLayout(rcClient.right, rcClient.bottom); |
- } |
- |
-// Message map and handlers |
- BEGIN_MSG_MAP(CPaneContainerImpl) |
- MESSAGE_HANDLER(WM_CREATE, OnCreate) |
- MESSAGE_HANDLER(WM_SIZE, OnSize) |
- MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) |
- MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground) |
- MESSAGE_HANDLER(WM_PAINT, OnPaint) |
-#ifndef _WIN32_WCE |
- MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint) |
-#endif // !_WIN32_WCE |
- MESSAGE_HANDLER(WM_NOTIFY, OnNotify) |
- MESSAGE_HANDLER(WM_COMMAND, OnCommand) |
- FORWARD_NOTIFICATIONS() |
- END_MSG_MAP() |
- |
- LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->CalcSize(); |
- |
- if((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0) |
- pT->CreateCloseButton(); |
- |
- return 0; |
- } |
- |
- LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)); |
- return 0; |
- } |
- |
- LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- if(m_wndClient.m_hWnd != NULL) |
- m_wndClient.SetFocus(); |
- return 0; |
- } |
- |
- LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- return 1; // no background needed |
- } |
- |
- LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- T* pT = static_cast<T*>(this); |
- if(wParam != NULL) |
- { |
- pT->DrawPaneTitle((HDC)wParam); |
- |
- if(m_wndClient.m_hWnd == NULL) // no client window |
- pT->DrawPane((HDC)wParam); |
- } |
- else |
- { |
- CPaintDC dc(m_hWnd); |
- pT->DrawPaneTitle(dc.m_hDC); |
- |
- if(m_wndClient.m_hWnd == NULL) // no client window |
- pT->DrawPane(dc.m_hDC); |
- } |
- |
- return 0; |
- } |
- |
- LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) |
- { |
- if(m_tb.m_hWnd == NULL) |
- { |
- bHandled = FALSE; |
- return 1; |
- } |
- |
- T* pT = static_cast<T*>(this); |
- pT; |
- LPNMHDR lpnmh = (LPNMHDR)lParam; |
- LRESULT lRet = 0; |
- |
- // pass toolbar custom draw notifications to the base class |
- if(lpnmh->code == NM_CUSTOMDRAW && lpnmh->hwndFrom == m_tb.m_hWnd) |
- lRet = CCustomDraw< T >::OnCustomDraw(0, lpnmh, bHandled); |
-#ifndef _WIN32_WCE |
- // tooltip notifications come with the tooltip window handle and button ID, |
- // pass them to the parent if we don't handle them |
- else if(lpnmh->code == TTN_GETDISPINFO && lpnmh->idFrom == pT->m_nCloseBtnID) |
- bHandled = pT->GetToolTipText(lpnmh); |
-#endif // !_WIN32_WCE |
- // only let notifications not from the toolbar go to the parent |
- else if(lpnmh->hwndFrom != m_tb.m_hWnd && lpnmh->idFrom != pT->m_nCloseBtnID) |
- bHandled = FALSE; |
- |
- return lRet; |
- } |
- |
- LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled) |
- { |
- // if command comes from the close button, substitute HWND of the pane container instead |
- if(m_tb.m_hWnd != NULL && (HWND)lParam == m_tb.m_hWnd) |
- return ::SendMessage(GetParent(), WM_COMMAND, wParam, (LPARAM)m_hWnd); |
- |
- bHandled = FALSE; |
- return 1; |
- } |
- |
-// Custom draw overrides |
- DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/) |
- { |
- return CDRF_NOTIFYITEMDRAW; // we need per-item notifications |
- } |
- |
- DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw) |
- { |
- CDCHandle dc = lpNMCustomDraw->hdc; |
-#if (_WIN32_IE >= 0x0400) |
- RECT& rc = lpNMCustomDraw->rc; |
-#else // !(_WIN32_IE >= 0x0400) |
- RECT rc; |
- m_tb.GetItemRect(0, &rc); |
-#endif // !(_WIN32_IE >= 0x0400) |
- |
- dc.FillRect(&rc, COLOR_3DFACE); |
- |
- return CDRF_NOTIFYPOSTPAINT; |
- } |
- |
- DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw) |
- { |
- CDCHandle dc = lpNMCustomDraw->hdc; |
-#if (_WIN32_IE >= 0x0400) |
- RECT& rc = lpNMCustomDraw->rc; |
-#else // !(_WIN32_IE >= 0x0400) |
- RECT rc = { 0 }; |
- m_tb.GetItemRect(0, &rc); |
-#endif // !(_WIN32_IE >= 0x0400) |
- |
- RECT rcImage = { m_xBtnImageLeft, m_yBtnImageTop, m_xBtnImageRight + 1, m_yBtnImageBottom + 1 }; |
- ::OffsetRect(&rcImage, rc.left, rc.top); |
- T* pT = static_cast<T*>(this); |
- |
- if((lpNMCustomDraw->uItemState & CDIS_DISABLED) != 0) |
- { |
- RECT rcShadow = rcImage; |
- ::OffsetRect(&rcShadow, 1, 1); |
- CPen pen1; |
- pen1.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT)); |
- pT->DrawButtonImage(dc, rcShadow, pen1); |
- CPen pen2; |
- pen2.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW)); |
- pT->DrawButtonImage(dc, rcImage, pen2); |
- } |
- else |
- { |
- if((lpNMCustomDraw->uItemState & CDIS_SELECTED) != 0) |
- ::OffsetRect(&rcImage, 1, 1); |
- CPen pen; |
- pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT)); |
- pT->DrawButtonImage(dc, rcImage, pen); |
- } |
- |
- return CDRF_DODEFAULT; // continue with the default item painting |
- } |
- |
-// Implementation - overrideable methods |
- void UpdateLayout(int cxWidth, int cyHeight) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- RECT rect = { 0 }; |
- |
- if(IsVertical()) |
- { |
- ::SetRect(&rect, 0, 0, m_cxyHeader, cyHeight); |
- if(m_tb.m_hWnd != NULL) |
- m_tb.SetWindowPos(NULL, m_cxyBorder, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); |
- |
- if(m_wndClient.m_hWnd != NULL) |
- m_wndClient.SetWindowPos(NULL, m_cxyHeader, 0, cxWidth - m_cxyHeader, cyHeight, SWP_NOZORDER); |
- else |
- rect.right = cxWidth; |
- } |
- else |
- { |
- ::SetRect(&rect, 0, 0, cxWidth, m_cxyHeader); |
- if(m_tb.m_hWnd != NULL) |
- m_tb.SetWindowPos(NULL, rect.right - m_cxToolBar, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE); |
- |
- if(m_wndClient.m_hWnd != NULL) |
- m_wndClient.SetWindowPos(NULL, 0, m_cxyHeader, cxWidth, cyHeight - m_cxyHeader, SWP_NOZORDER); |
- else |
- rect.bottom = cyHeight; |
- } |
- |
- InvalidateRect(&rect); |
- } |
- |
- void CreateCloseButton() |
- { |
- ATLASSERT(m_tb.m_hWnd == NULL); |
- // create toolbar for the "x" button |
- m_tb.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NOMOVEY | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT, 0); |
- ATLASSERT(m_tb.IsWindow()); |
- |
- if(m_tb.m_hWnd != NULL) |
- { |
- T* pT = static_cast<T*>(this); |
- pT; // avoid level 4 warning |
- |
- m_tb.SetButtonStructSize(); |
- |
- TBBUTTON tbbtn = { 0 }; |
- tbbtn.idCommand = pT->m_nCloseBtnID; |
- tbbtn.fsState = TBSTATE_ENABLED; |
- tbbtn.fsStyle = TBSTYLE_BUTTON; |
- m_tb.AddButtons(1, &tbbtn); |
- |
- m_tb.SetBitmapSize(m_cxImageTB, m_cyImageTB); |
- m_tb.SetButtonSize(m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB); |
- |
- if(IsVertical()) |
- m_tb.SetWindowPos(NULL, m_cxyBorder + m_cxyBtnOffset, m_cxyBorder + m_cxyBtnOffset, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB, SWP_NOZORDER | SWP_NOACTIVATE); |
- else |
- m_tb.SetWindowPos(NULL, 0, 0, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE); |
- } |
- } |
- |
- void DestroyCloseButton() |
- { |
- if(m_tb.m_hWnd != NULL) |
- m_tb.DestroyWindow(); |
- } |
- |
- void CalcSize() |
- { |
- T* pT = static_cast<T*>(this); |
- CFontHandle font = pT->GetTitleFont(); |
- LOGFONT lf = { 0 }; |
- font.GetLogFont(lf); |
- if(IsVertical()) |
- { |
- m_cxyHeader = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder; |
- } |
- else |
- { |
- int cyFont = abs(lf.lfHeight) + m_cxyBorder + 2 * m_cxyTextOffset; |
- int cyBtn = m_cyImageTB + m_cxyBtnAddTB + m_cxyBorder + 2 * m_cxyBtnOffset; |
- m_cxyHeader = __max(cyFont, cyBtn); |
- } |
- } |
- |
- HFONT GetTitleFont() const |
- { |
- return AtlGetDefaultGuiFont(); |
- } |
- |
-#ifndef _WIN32_WCE |
- BOOL GetToolTipText(LPNMHDR /*lpnmh*/) |
- { |
- return FALSE; |
- } |
-#endif // !_WIN32_WCE |
- |
- void DrawPaneTitle(CDCHandle dc) |
- { |
- RECT rect = { 0 }; |
- GetClientRect(&rect); |
- |
- UINT uBorder = BF_LEFT | BF_TOP | BF_ADJUST; |
- if(IsVertical()) |
- { |
- rect.right = rect.left + m_cxyHeader; |
- uBorder |= BF_BOTTOM; |
- } |
- else |
- { |
- rect.bottom = rect.top + m_cxyHeader; |
- uBorder |= BF_RIGHT; |
- } |
- |
- if((m_dwExtendedStyle & PANECNT_NOBORDER) == 0) |
- { |
- if((m_dwExtendedStyle & PANECNT_FLATBORDER) != 0) |
- uBorder |= BF_FLAT; |
- dc.DrawEdge(&rect, EDGE_ETCHED, uBorder); |
- } |
- dc.FillRect(&rect, COLOR_3DFACE); |
- |
- if(!IsVertical()) // draw title only for horizontal pane container |
- { |
- dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); |
- dc.SetBkMode(TRANSPARENT); |
- T* pT = static_cast<T*>(this); |
- HFONT hFontOld = dc.SelectFont(pT->GetTitleFont()); |
- rect.left += m_cxyTextOffset; |
- rect.right -= m_cxyTextOffset; |
- if(m_tb.m_hWnd != NULL) |
- rect.right -= m_cxToolBar;; |
-#ifndef _WIN32_WCE |
- dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS); |
-#else // CE specific |
- dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER); |
-#endif // _WIN32_WCE |
- dc.SelectFont(hFontOld); |
- } |
- } |
- |
- // called only if pane is empty |
- void DrawPane(CDCHandle dc) |
- { |
- RECT rect = { 0 }; |
- GetClientRect(&rect); |
- if(IsVertical()) |
- rect.left += m_cxyHeader; |
- else |
- rect.top += m_cxyHeader; |
- if((GetExStyle() & WS_EX_CLIENTEDGE) == 0) |
- dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); |
- dc.FillRect(&rect, COLOR_APPWORKSPACE); |
- } |
- |
- // drawing helper - draws "x" button image |
- void DrawButtonImage(CDCHandle dc, RECT& rcImage, HPEN hPen) |
- { |
-#if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400) |
- HPEN hPenOld = dc.SelectPen(hPen); |
- |
- dc.MoveTo(rcImage.left, rcImage.top); |
- dc.LineTo(rcImage.right, rcImage.bottom); |
- dc.MoveTo(rcImage.left + 1, rcImage.top); |
- dc.LineTo(rcImage.right + 1, rcImage.bottom); |
- |
- dc.MoveTo(rcImage.left, rcImage.bottom - 1); |
- dc.LineTo(rcImage.right, rcImage.top - 1); |
- dc.MoveTo(rcImage.left + 1, rcImage.bottom - 1); |
- dc.LineTo(rcImage.right + 1, rcImage.top - 1); |
- |
- dc.SelectPen(hPenOld); |
-#else // (_WIN32_WCE < 400) |
- rcImage; |
- hPen; |
- // no support for the "x" button image |
-#endif // (_WIN32_WCE < 400) |
- } |
- |
- bool IsVertical() const |
- { |
- return ((m_dwExtendedStyle & PANECNT_VERTICAL) != 0); |
- } |
-}; |
- |
-class CPaneContainer : public CPaneContainerImpl<CPaneContainer> |
-{ |
-public: |
- DECLARE_WND_CLASS_EX(_T("WTL_PaneContainer"), 0, -1) |
-}; |
- |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// CSortListViewCtrl - implements sorting for a listview control |
- |
-// sort listview extended styles |
-#define SORTLV_USESHELLBITMAPS 0x00000001 |
- |
-// Notification sent to parent when sort column is changed by user clicking header. |
-#define SLVN_SORTCHANGED LVN_LAST |
- |
-// A LPNMSORTLISTVIEW is sent with the SLVN_SORTCHANGED notification |
-typedef struct tagNMSORTLISTVIEW |
-{ |
- NMHDR hdr; |
- int iNewSortColumn; |
- int iOldSortColumn; |
-} NMSORTLISTVIEW, *LPNMSORTLISTVIEW; |
- |
-// Column sort types. Can be set on a per-column basis with the SetColumnSortType method. |
-enum |
-{ |
- LVCOLSORT_NONE, |
- LVCOLSORT_TEXT, // default |
- LVCOLSORT_TEXTNOCASE, |
- LVCOLSORT_LONG, |
- LVCOLSORT_DOUBLE, |
- LVCOLSORT_DECIMAL, |
- LVCOLSORT_DATETIME, |
- LVCOLSORT_DATE, |
- LVCOLSORT_TIME, |
- LVCOLSORT_CUSTOM, |
- LVCOLSORT_LAST = LVCOLSORT_CUSTOM |
-}; |
- |
- |
-template <class T> |
-class CSortListViewImpl |
-{ |
-public: |
- enum |
- { |
- m_cchCmpTextMax = 32, // overrideable |
- m_cxSortImage = 16, |
- m_cySortImage = 15, |
- m_cxSortArrow = 11, |
- m_cySortArrow = 6, |
- m_iSortUp = 0, // index of sort bitmaps |
- m_iSortDown = 1, |
- m_nShellSortUpID = 133 |
- }; |
- |
- // passed to LVCompare functions as lParam1 and lParam2 |
- struct LVCompareParam |
- { |
- int iItem; |
- DWORD_PTR dwItemData; |
- union |
- { |
- long lValue; |
- double dblValue; |
- DECIMAL decValue; |
- LPCTSTR pszValue; |
- }; |
- }; |
- |
- // passed to LVCompare functions as the lParamSort parameter |
- struct LVSortInfo |
- { |
- T* pT; |
- int iSortCol; |
- bool bDescending; |
- }; |
- |
- bool m_bSortDescending; |
- bool m_bCommCtrl6; |
- int m_iSortColumn; |
- CBitmap m_bmSort[2]; |
- int m_fmtOldSortCol; |
- HBITMAP m_hbmOldSortCol; |
- DWORD m_dwSortLVExtendedStyle; |
- ATL::CSimpleArray<WORD> m_arrColSortType; |
- bool m_bUseWaitCursor; |
- |
- CSortListViewImpl() : |
- m_bSortDescending(false), |
- m_bCommCtrl6(false), |
- m_iSortColumn(-1), |
- m_fmtOldSortCol(0), |
- m_hbmOldSortCol(NULL), |
- m_dwSortLVExtendedStyle(SORTLV_USESHELLBITMAPS), |
- m_bUseWaitCursor(true) |
- { |
-#ifndef _WIN32_WCE |
- DWORD dwMajor = 0; |
- DWORD dwMinor = 0; |
- HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor); |
- m_bCommCtrl6 = SUCCEEDED(hRet) && dwMajor >= 6; |
-#endif // !_WIN32_WCE |
- } |
- |
-// Attributes |
- void SetSortColumn(int iCol) |
- { |
- T* pT = static_cast<T*>(this); |
- ATLASSERT(::IsWindow(pT->m_hWnd)); |
- CHeaderCtrl header = pT->GetHeader(); |
- ATLASSERT(header.m_hWnd != NULL); |
- ATLASSERT(iCol >= -1 && iCol < m_arrColSortType.GetSize()); |
- |
- int iOldSortCol = m_iSortColumn; |
- m_iSortColumn = iCol; |
- if(m_bCommCtrl6) |
- { |
-#ifndef HDF_SORTUP |
- const int HDF_SORTUP = 0x0400; |
-#endif // HDF_SORTUP |
-#ifndef HDF_SORTDOWN |
- const int HDF_SORTDOWN = 0x0200; |
-#endif // HDF_SORTDOWN |
- const int nMask = HDF_SORTUP | HDF_SORTDOWN; |
- HDITEM hditem = { HDI_FORMAT }; |
- if(iOldSortCol != iCol && iOldSortCol >= 0 && header.GetItem(iOldSortCol, &hditem)) |
- { |
- hditem.fmt &= ~nMask; |
- header.SetItem(iOldSortCol, &hditem); |
- } |
- if(iCol >= 0 && header.GetItem(iCol, &hditem)) |
- { |
- hditem.fmt &= ~nMask; |
- hditem.fmt |= m_bSortDescending ? HDF_SORTDOWN : HDF_SORTUP; |
- header.SetItem(iCol, &hditem); |
- } |
- return; |
- } |
- |
- if(m_bmSort[m_iSortUp].IsNull()) |
- pT->CreateSortBitmaps(); |
- |
- // restore previous sort column's bitmap, if any, and format |
- HDITEM hditem = { HDI_BITMAP | HDI_FORMAT }; |
- if(iOldSortCol != iCol && iOldSortCol >= 0) |
- { |
- hditem.hbm = m_hbmOldSortCol; |
- hditem.fmt = m_fmtOldSortCol; |
- header.SetItem(iOldSortCol, &hditem); |
- } |
- |
- // save new sort column's bitmap and format, and add our sort bitmap |
- if(iCol >= 0 && header.GetItem(iCol, &hditem)) |
- { |
- if(iOldSortCol != iCol) |
- { |
- m_fmtOldSortCol = hditem.fmt; |
- m_hbmOldSortCol = hditem.hbm; |
- } |
- hditem.fmt &= ~HDF_IMAGE; |
- hditem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT; |
- int i = m_bSortDescending ? m_iSortDown : m_iSortUp; |
- hditem.hbm = m_bmSort[i]; |
- header.SetItem(iCol, &hditem); |
- } |
- } |
- |
- int GetSortColumn() const |
- { |
- return m_iSortColumn; |
- } |
- |
- void SetColumnSortType(int iCol, WORD wType) |
- { |
- ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize()); |
- ATLASSERT(wType >= LVCOLSORT_NONE && wType <= LVCOLSORT_LAST); |
- m_arrColSortType[iCol] = wType; |
- } |
- |
- WORD GetColumnSortType(int iCol) const |
- { |
- ATLASSERT((iCol >= 0) && iCol < m_arrColSortType.GetSize()); |
- return m_arrColSortType[iCol]; |
- } |
- |
- int GetColumnCount() const |
- { |
- const T* pT = static_cast<const T*>(this); |
- ATLASSERT(::IsWindow(pT->m_hWnd)); |
- CHeaderCtrl header = pT->GetHeader(); |
- return header.m_hWnd != NULL ? header.GetItemCount() : 0; |
- } |
- |
- bool IsSortDescending() const |
- { |
- return m_bSortDescending; |
- } |
- |
- DWORD GetSortListViewExtendedStyle() const |
- { |
- return m_dwSortLVExtendedStyle; |
- } |
- |
- DWORD SetSortListViewExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0) |
- { |
- DWORD dwPrevStyle = m_dwSortLVExtendedStyle; |
- if(dwMask == 0) |
- m_dwSortLVExtendedStyle = dwExtendedStyle; |
- else |
- m_dwSortLVExtendedStyle = (m_dwSortLVExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask); |
- return dwPrevStyle; |
- } |
- |
-// Operations |
- bool DoSortItems(int iCol, bool bDescending = false) |
- { |
- T* pT = static_cast<T*>(this); |
- ATLASSERT(::IsWindow(pT->m_hWnd)); |
- ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize()); |
- |
- WORD wType = m_arrColSortType[iCol]; |
- if(wType == LVCOLSORT_NONE) |
- return false; |
- |
- int nCount = pT->GetItemCount(); |
- if(nCount < 2) |
- { |
- m_bSortDescending = bDescending; |
- SetSortColumn(iCol); |
- return true; |
- } |
- |
- CWaitCursor waitCursor(false); |
- if(m_bUseWaitCursor) |
- waitCursor.Set(); |
- |
- LVCompareParam* pParam = NULL; |
- ATLTRY(pParam = new LVCompareParam[nCount]); |
- PFNLVCOMPARE pFunc = NULL; |
- TCHAR pszTemp[pT->m_cchCmpTextMax]; |
- bool bStrValue = false; |
- |
- switch(wType) |
- { |
- case LVCOLSORT_TEXT: |
- pFunc = (PFNLVCOMPARE)pT->LVCompareText; |
- case LVCOLSORT_TEXTNOCASE: |
- if(pFunc == NULL) |
- pFunc = (PFNLVCOMPARE)pT->LVCompareTextNoCase; |
- case LVCOLSORT_CUSTOM: |
- { |
- if(pFunc == NULL) |
- pFunc = (PFNLVCOMPARE)pT->LVCompareCustom; |
- |
- for(int i = 0; i < nCount; i++) |
- { |
- pParam[i].iItem = i; |
- pParam[i].dwItemData = pT->GetItemData(i); |
- pParam[i].pszValue = new TCHAR[pT->m_cchCmpTextMax]; |
- pT->GetItemText(i, iCol, (LPTSTR)pParam[i].pszValue, pT->m_cchCmpTextMax); |
- pT->SetItemData(i, (DWORD_PTR)&pParam[i]); |
- } |
- bStrValue = true; |
- } |
- break; |
- case LVCOLSORT_LONG: |
- { |
- pFunc = (PFNLVCOMPARE)pT->LVCompareLong; |
- for(int i = 0; i < nCount; i++) |
- { |
- pParam[i].iItem = i; |
- pParam[i].dwItemData = pT->GetItemData(i); |
- pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); |
- pParam[i].lValue = pT->StrToLong(pszTemp); |
- pT->SetItemData(i, (DWORD_PTR)&pParam[i]); |
- } |
- } |
- break; |
- case LVCOLSORT_DOUBLE: |
- { |
- pFunc = (PFNLVCOMPARE)pT->LVCompareDouble; |
- for(int i = 0; i < nCount; i++) |
- { |
- pParam[i].iItem = i; |
- pParam[i].dwItemData = pT->GetItemData(i); |
- pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); |
- pParam[i].dblValue = pT->StrToDouble(pszTemp); |
- pT->SetItemData(i, (DWORD_PTR)&pParam[i]); |
- } |
- } |
- break; |
- case LVCOLSORT_DECIMAL: |
- { |
- pFunc = (PFNLVCOMPARE)pT->LVCompareDecimal; |
- for(int i = 0; i < nCount; i++) |
- { |
- pParam[i].iItem = i; |
- pParam[i].dwItemData = pT->GetItemData(i); |
- pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); |
- pT->StrToDecimal(pszTemp, &pParam[i].decValue); |
- pT->SetItemData(i, (DWORD_PTR)&pParam[i]); |
- } |
- } |
- break; |
- case LVCOLSORT_DATETIME: |
- case LVCOLSORT_DATE: |
- case LVCOLSORT_TIME: |
- { |
- pFunc = (PFNLVCOMPARE)pT->LVCompareDouble; |
- DWORD dwFlags = LOCALE_NOUSEROVERRIDE; |
- if(wType == LVCOLSORT_DATE) |
- dwFlags |= VAR_DATEVALUEONLY; |
- else if(wType == LVCOLSORT_TIME) |
- dwFlags |= VAR_TIMEVALUEONLY; |
- for(int i = 0; i < nCount; i++) |
- { |
- pParam[i].iItem = i; |
- pParam[i].dwItemData = pT->GetItemData(i); |
- pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax); |
- pParam[i].dblValue = pT->DateStrToDouble(pszTemp, dwFlags); |
- pT->SetItemData(i, (DWORD_PTR)&pParam[i]); |
- } |
- } |
- break; |
- default: |
- ATLTRACE2(atlTraceUI, 0, _T("Unknown value for sort type in CSortListViewImpl::DoSortItems()\n")); |
- break; |
- } // switch(wType) |
- |
- ATLASSERT(pFunc != NULL); |
- LVSortInfo lvsi = { pT, iCol, bDescending }; |
- bool bRet = ((BOOL)pT->DefWindowProc(LVM_SORTITEMS, (WPARAM)&lvsi, (LPARAM)pFunc) != FALSE); |
- for(int i = 0; i < nCount; i++) |
- { |
- DWORD_PTR dwItemData = pT->GetItemData(i); |
- LVCompareParam* p = (LVCompareParam*)dwItemData; |
- ATLASSERT(p != NULL); |
- if(bStrValue) |
- delete [] (TCHAR*)p->pszValue; |
- pT->SetItemData(i, p->dwItemData); |
- } |
- delete [] pParam; |
- |
- if(bRet) |
- { |
- m_bSortDescending = bDescending; |
- SetSortColumn(iCol); |
- } |
- |
- if(m_bUseWaitCursor) |
- waitCursor.Restore(); |
- |
- return bRet; |
- } |
- |
- void CreateSortBitmaps() |
- { |
- if((m_dwSortLVExtendedStyle & SORTLV_USESHELLBITMAPS) != 0) |
- { |
- bool bFree = false; |
- LPCTSTR pszModule = _T("shell32.dll"); |
- HINSTANCE hShell = ::GetModuleHandle(pszModule); |
- |
- if (hShell == NULL) |
- { |
- hShell = ::LoadLibrary(pszModule); |
- bFree = true; |
- } |
- |
- if (hShell != NULL) |
- { |
- bool bSuccess = true; |
- for(int i = m_iSortUp; i <= m_iSortDown; i++) |
- { |
- if(!m_bmSort[i].IsNull()) |
- m_bmSort[i].DeleteObject(); |
- m_bmSort[i] = (HBITMAP)::LoadImage(hShell, MAKEINTRESOURCE(m_nShellSortUpID + i), |
-#ifndef _WIN32_WCE |
- IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); |
-#else // CE specific |
- IMAGE_BITMAP, 0, 0, 0); |
-#endif // _WIN32_WCE |
- if(m_bmSort[i].IsNull()) |
- { |
- bSuccess = false; |
- break; |
- } |
- } |
- if(bFree) |
- ::FreeLibrary(hShell); |
- if(bSuccess) |
- return; |
- } |
- } |
- |
- T* pT = static_cast<T*>(this); |
- for(int i = m_iSortUp; i <= m_iSortDown; i++) |
- { |
- if(!m_bmSort[i].IsNull()) |
- m_bmSort[i].DeleteObject(); |
- |
- CDC dcMem; |
- CClientDC dc(::GetDesktopWindow()); |
- dcMem.CreateCompatibleDC(dc.m_hDC); |
- m_bmSort[i].CreateCompatibleBitmap(dc.m_hDC, m_cxSortImage, m_cySortImage); |
- HBITMAP hbmOld = dcMem.SelectBitmap(m_bmSort[i]); |
- RECT rc = {0,0,m_cxSortImage, m_cySortImage}; |
- pT->DrawSortBitmap(dcMem.m_hDC, i, &rc); |
- dcMem.SelectBitmap(hbmOld); |
- dcMem.DeleteDC(); |
- } |
- } |
- |
- void NotifyParentSortChanged(int iNewSortCol, int iOldSortCol) |
- { |
- T* pT = static_cast<T*>(this); |
- int nID = pT->GetDlgCtrlID(); |
- NMSORTLISTVIEW nm = { { pT->m_hWnd, nID, SLVN_SORTCHANGED }, iNewSortCol, iOldSortCol }; |
- ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nm); |
- } |
- |
-// Overrideables |
- int CompareItemsCustom(LVCompareParam* /*pItem1*/, LVCompareParam* /*pItem2*/, int /*iSortCol*/) |
- { |
- // pItem1 and pItem2 contain valid iItem, dwItemData, and pszValue members. |
- // If item1 > item2 return 1, if item1 < item2 return -1, else return 0. |
- return 0; |
- } |
- |
- void DrawSortBitmap(CDCHandle dc, int iBitmap, LPRECT prc) |
- { |
- dc.FillRect(prc, ::GetSysColorBrush(COLOR_BTNFACE)); |
- HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW)); |
- CPen pen; |
- pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNSHADOW)); |
- HPEN hpenOld = dc.SelectPen(pen); |
- POINT ptOrg = { (m_cxSortImage - m_cxSortArrow) / 2, (m_cySortImage - m_cySortArrow) / 2 }; |
- if(iBitmap == m_iSortUp) |
- { |
- POINT pts[3] = |
- { |
- { ptOrg.x + m_cxSortArrow / 2, ptOrg.y }, |
- { ptOrg.x, ptOrg.y + m_cySortArrow - 1 }, |
- { ptOrg.x + m_cxSortArrow - 1, ptOrg.y + m_cySortArrow - 1 } |
- }; |
- dc.Polygon(pts, 3); |
- } |
- else |
- { |
- POINT pts[3] = |
- { |
- { ptOrg.x, ptOrg.y }, |
- { ptOrg.x + m_cxSortArrow / 2, ptOrg.y + m_cySortArrow - 1 }, |
- { ptOrg.x + m_cxSortArrow - 1, ptOrg.y } |
- }; |
- dc.Polygon(pts, 3); |
- } |
- dc.SelectBrush(hbrOld); |
- dc.SelectPen(hpenOld); |
- } |
- |
- double DateStrToDouble(LPCTSTR lpstr, DWORD dwFlags) |
- { |
- ATLASSERT(lpstr != NULL); |
- if(lpstr == NULL || lpstr[0] == _T('\0')) |
- return 0; |
- |
- USES_CONVERSION; |
- HRESULT hRet = E_FAIL; |
- DATE dRet = 0; |
- if (FAILED(hRet = ::VarDateFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, dwFlags, &dRet))) |
- { |
- ATLTRACE2(atlTraceUI, 0, _T("VarDateFromStr failed with result of 0x%8.8X\n"), hRet); |
- dRet = 0; |
- } |
- return dRet; |
- } |
- |
- long StrToLong(LPCTSTR lpstr) |
- { |
- ATLASSERT(lpstr != NULL); |
- if(lpstr == NULL || lpstr[0] == _T('\0')) |
- return 0; |
- |
- USES_CONVERSION; |
- HRESULT hRet = E_FAIL; |
- long lRet = 0; |
- if (FAILED(hRet = ::VarI4FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &lRet))) |
- { |
- ATLTRACE2(atlTraceUI, 0, _T("VarI4FromStr failed with result of 0x%8.8X\n"), hRet); |
- lRet = 0; |
- } |
- return lRet; |
- } |
- |
- double StrToDouble(LPCTSTR lpstr) |
- { |
- ATLASSERT(lpstr != NULL); |
- if(lpstr == NULL || lpstr[0] == _T('\0')) |
- return 0; |
- |
- USES_CONVERSION; |
- HRESULT hRet = E_FAIL; |
- double dblRet = 0; |
- if (FAILED(hRet = ::VarR8FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &dblRet))) |
- { |
- ATLTRACE2(atlTraceUI, 0, _T("VarR8FromStr failed with result of 0x%8.8X\n"), hRet); |
- dblRet = 0; |
- } |
- return dblRet; |
- } |
- |
- bool StrToDecimal(LPCTSTR lpstr, DECIMAL* pDecimal) |
- { |
- ATLASSERT(lpstr != NULL); |
- ATLASSERT(pDecimal != NULL); |
- if(lpstr == NULL || pDecimal == NULL) |
- return false; |
- |
- USES_CONVERSION; |
- HRESULT hRet = E_FAIL; |
- if (FAILED(hRet = ::VarDecFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, pDecimal))) |
- { |
- ATLTRACE2(atlTraceUI, 0, _T("VarDecFromStr failed with result of 0x%8.8X\n"), hRet); |
- pDecimal->Lo64 = 0; |
- pDecimal->Hi32 = 0; |
- pDecimal->signscale = 0; |
- return false; |
- } |
- return true; |
- } |
- |
-// Overrideable PFNLVCOMPARE functions |
- static int CALLBACK LVCompareText(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) |
- { |
- ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); |
- |
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1; |
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2; |
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort; |
- |
- int nRet = lstrcmp(pParam1->pszValue, pParam2->pszValue); |
- return pInfo->bDescending ? -nRet : nRet; |
- } |
- |
- static int CALLBACK LVCompareTextNoCase(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) |
- { |
- ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); |
- |
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1; |
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2; |
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort; |
- |
- int nRet = lstrcmpi(pParam1->pszValue, pParam2->pszValue); |
- return pInfo->bDescending ? -nRet : nRet; |
- } |
- |
- static int CALLBACK LVCompareLong(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) |
- { |
- ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); |
- |
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1; |
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2; |
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort; |
- |
- int nRet = 0; |
- if(pParam1->lValue > pParam2->lValue) |
- nRet = 1; |
- else if(pParam1->lValue < pParam2->lValue) |
- nRet = -1; |
- return pInfo->bDescending ? -nRet : nRet; |
- } |
- |
- static int CALLBACK LVCompareDouble(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) |
- { |
- ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); |
- |
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1; |
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2; |
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort; |
- |
- int nRet = 0; |
- if(pParam1->dblValue > pParam2->dblValue) |
- nRet = 1; |
- else if(pParam1->dblValue < pParam2->dblValue) |
- nRet = -1; |
- return pInfo->bDescending ? -nRet : nRet; |
- } |
- |
- static int CALLBACK LVCompareCustom(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) |
- { |
- ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); |
- |
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1; |
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2; |
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort; |
- |
- int nRet = pInfo->pT->CompareItemsCustom(pParam1, pParam2, pInfo->iSortCol); |
- return pInfo->bDescending ? -nRet : nRet; |
- } |
- |
-#ifndef _WIN32_WCE |
- static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) |
- { |
- ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); |
- |
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1; |
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2; |
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort; |
- |
- int nRet = (int)::VarDecCmp(&pParam1->decValue, &pParam2->decValue); |
- nRet--; |
- return pInfo->bDescending ? -nRet : nRet; |
- } |
-#else |
- // Compare mantissas, ignore sign and scale |
- static int CompareMantissas(const DECIMAL& decLeft, const DECIMAL& decRight) |
- { |
- if (decLeft.Hi32 < decRight.Hi32) |
- { |
- return -1; |
- } |
- if (decLeft.Hi32 > decRight.Hi32) |
- { |
- return 1; |
- } |
- // Here, decLeft.Hi32 == decRight.Hi32 |
- if (decLeft.Lo64 < decRight.Lo64) |
- { |
- return -1; |
- } |
- if (decLeft.Lo64 > decRight.Lo64) |
- { |
- return 1; |
- } |
- return 0; |
- } |
- |
- // return values: VARCMP_LT, VARCMP_EQ, VARCMP_GT, VARCMP_NULL |
- static HRESULT VarDecCmp(const DECIMAL* pdecLeft, const DECIMAL* pdecRight) |
- { |
- static const ULONG powersOfTen[] = |
- { |
- 10ul, |
- 100ul, |
- 1000ul, |
- 10000ul, |
- 100000ul, |
- 1000000ul, |
- 10000000ul, |
- 100000000ul, |
- 1000000000ul |
- }; |
- static const int largestPower = sizeof(powersOfTen) / sizeof(powersOfTen[0]); |
- if (!pdecLeft || !pdecRight) |
- { |
- return VARCMP_NULL; |
- } |
- |
- // Degenerate case - at least one comparand is of the form |
- // [+-]0*10^N (denormalized zero) |
- bool bLeftZero = (!pdecLeft->Lo64 && !pdecLeft->Hi32); |
- bool bRightZero = (!pdecRight->Lo64 && !pdecRight->Hi32); |
- if (bLeftZero && bRightZero) |
- { |
- return VARCMP_EQ; |
- } |
- bool bLeftNeg = ((pdecLeft->sign & DECIMAL_NEG) != 0); |
- bool bRightNeg = ((pdecRight->sign & DECIMAL_NEG) != 0); |
- if (bLeftZero) |
- { |
- return (bRightNeg ? VARCMP_GT : VARCMP_LT); |
- } |
- // This also covers the case where the comparands have different signs |
- if (bRightZero || bLeftNeg != bRightNeg) |
- { |
- return (bLeftNeg ? VARCMP_LT : VARCMP_GT); |
- } |
- |
- // Here both comparands have the same sign and need to be compared |
- // on mantissa and scale. The result is obvious when |
- // 1. Scales are equal (then compare mantissas) |
- // 2. A number with smaller scale is also the one with larger mantissa |
- // (then this number is obviously larger) |
- // In the remaining case, we would multiply the number with smaller |
- // scale by 10 and simultaneously increment its scale (which amounts to |
- // adding trailing zeros after decimal point), until the numbers fall under |
- // one of the two cases above |
- DECIMAL temp; |
- bool bInvert = bLeftNeg; // the final result needs to be inverted |
- if (pdecLeft->scale < pdecRight->scale) |
- { |
- temp = *pdecLeft; |
- } |
- else |
- { |
- temp = *pdecRight; |
- pdecRight = pdecLeft; |
- bInvert = !bInvert; |
- } |
- |
- // Now temp is the number with smaller (or equal) scale, and |
- // we can modify it freely without touching original parameters |
- int comp; |
- while ((comp = CompareMantissas(temp, *pdecRight)) < 0 && |
- temp.scale < pdecRight->scale) |
- { |
- // Multiply by an appropriate power of 10 |
- int scaleDiff = pdecRight->scale - temp.scale; |
- if (scaleDiff > largestPower) |
- { |
- // Keep the multiplier representable in 32bit |
- scaleDiff = largestPower; |
- } |
- DWORDLONG power = powersOfTen[scaleDiff - 1]; |
- // Multiply temp's mantissa by power |
- DWORDLONG product = temp.Lo32 * power; |
- ULONG carry = static_cast<ULONG>(product >> 32); |
- temp.Lo32 = static_cast<ULONG>(product); |
- product = temp.Mid32 * power + carry; |
- carry = static_cast<ULONG>(product >> 32); |
- temp.Mid32 = static_cast<ULONG>(product); |
- product = temp.Hi32 * power + carry; |
- if (static_cast<ULONG>(product >> 32)) |
- { |
- // Multiplication overflowed - pdecLeft is clearly larger |
- break; |
- } |
- temp.Hi32 = static_cast<ULONG>(product); |
- temp.scale = (BYTE)(temp.scale + scaleDiff); |
- } |
- if (temp.scale < pdecRight->scale) |
- { |
- comp = 1; |
- } |
- if (bInvert) |
- { |
- comp = -comp; |
- } |
- return (comp > 0 ? VARCMP_GT : comp < 0 ? VARCMP_LT : VARCMP_EQ); |
- } |
- |
- static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) |
- { |
- ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NULL); |
- |
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1; |
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2; |
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort; |
- |
- int nRet = (int)VarDecCmp(&pParam1->decValue, &pParam2->decValue); |
- nRet--; |
- return pInfo->bDescending ? -nRet : nRet; |
- } |
-#endif // !_WIN32_WCE |
- |
- BEGIN_MSG_MAP(CSortListViewImpl) |
- MESSAGE_HANDLER(LVM_INSERTCOLUMN, OnInsertColumn) |
- MESSAGE_HANDLER(LVM_DELETECOLUMN, OnDeleteColumn) |
- NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, OnHeaderItemClick) |
- NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, OnHeaderItemClick) |
- MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange) |
- END_MSG_MAP() |
- |
- LRESULT OnInsertColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- T* pT = static_cast<T*>(this); |
- LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); |
- if(lRet == -1) |
- return -1; |
- |
- WORD wType = 0; |
- m_arrColSortType.Add(wType); |
- int nCount = m_arrColSortType.GetSize(); |
- ATLASSERT(nCount == GetColumnCount()); |
- |
- for(int i = nCount - 1; i > lRet; i--) |
- m_arrColSortType[i] = m_arrColSortType[i - 1]; |
- m_arrColSortType[(int)lRet] = LVCOLSORT_TEXT; |
- |
- if(lRet <= m_iSortColumn) |
- m_iSortColumn++; |
- |
- return lRet; |
- } |
- |
- LRESULT OnDeleteColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- T* pT = static_cast<T*>(this); |
- LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam); |
- if(lRet == 0) |
- return 0; |
- |
- int iCol = (int)wParam; |
- if(m_iSortColumn == iCol) |
- m_iSortColumn = -1; |
- else if(m_iSortColumn > iCol) |
- m_iSortColumn--; |
- m_arrColSortType.RemoveAt(iCol); |
- |
- return lRet; |
- } |
- |
- LRESULT OnHeaderItemClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) |
- { |
- LPNMHEADER p = (LPNMHEADER)pnmh; |
- if(p->iButton == 0) |
- { |
- int iOld = m_iSortColumn; |
- bool bDescending = (m_iSortColumn == p->iItem) ? !m_bSortDescending : false; |
- if(DoSortItems(p->iItem, bDescending)) |
- NotifyParentSortChanged(p->iItem, iOld); |
- } |
- bHandled = FALSE; |
- return 0; |
- } |
- |
- LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
-#ifndef _WIN32_WCE |
- if(wParam == SPI_SETNONCLIENTMETRICS) |
- GetSystemSettings(); |
-#else // CE specific |
- wParam; // avoid level 4 warning |
- GetSystemSettings(); |
-#endif // _WIN32_WCE |
- bHandled = FALSE; |
- return 0; |
- } |
- |
- void GetSystemSettings() |
- { |
- if(!m_bCommCtrl6 && !m_bmSort[m_iSortUp].IsNull()) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->CreateSortBitmaps(); |
- if(m_iSortColumn != -1) |
- SetSortColumn(m_iSortColumn); |
- } |
- } |
- |
-}; |
- |
- |
-typedef ATL::CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | LVS_REPORT | LVS_SHOWSELALWAYS , WS_EX_CLIENTEDGE> CSortListViewCtrlTraits; |
- |
-template <class T, class TBase = CListViewCtrl, class TWinTraits = CSortListViewCtrlTraits> |
-class ATL_NO_VTABLE CSortListViewCtrlImpl: public ATL::CWindowImpl<T, TBase, TWinTraits>, public CSortListViewImpl<T> |
-{ |
-public: |
- DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName()) |
- |
- bool SortItems(int iCol, bool bDescending = false) |
- { |
- return DoSortItems(iCol, bDescending); |
- } |
- |
- BEGIN_MSG_MAP(CSortListViewCtrlImpl) |
- MESSAGE_HANDLER(LVM_INSERTCOLUMN, CSortListViewImpl<T>::OnInsertColumn) |
- MESSAGE_HANDLER(LVM_DELETECOLUMN, CSortListViewImpl<T>::OnDeleteColumn) |
- NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, CSortListViewImpl<T>::OnHeaderItemClick) |
- NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, CSortListViewImpl<T>::OnHeaderItemClick) |
- MESSAGE_HANDLER(WM_SETTINGCHANGE, CSortListViewImpl<T>::OnSettingChange) |
- END_MSG_MAP() |
-}; |
- |
-class CSortListViewCtrl : public CSortListViewCtrlImpl<CSortListViewCtrl> |
-{ |
-public: |
- DECLARE_WND_SUPERCLASS(_T("WTL_SortListViewCtrl"), GetWndClassName()) |
-}; |
- |
- |
-/////////////////////////////////////////////////////////////////////////////// |
-// CTabView - implements tab view window |
- |
-// TabView Notifications |
-#define TBVN_PAGEACTIVATED (0U-741) |
-#define TBVN_CONTEXTMENU (0U-742) |
- |
-// Notification data for TBVN_CONTEXTMENU |
-struct TBVCONTEXTMENUINFO |
-{ |
- NMHDR hdr; |
- POINT pt; |
-}; |
- |
-typedef TBVCONTEXTMENUINFO* LPTBVCONTEXTMENUINFO; |
- |
- |
-template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits> |
-class ATL_NO_VTABLE CTabViewImpl : public ATL::CWindowImpl<T, TBase, TWinTraits> |
-{ |
-public: |
- DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE) |
- |
-// Declarations and enums |
- struct TABVIEWPAGE |
- { |
- HWND hWnd; |
- LPTSTR lpstrTitle; |
- LPVOID pData; |
- }; |
- |
- struct TCITEMEXTRA |
- { |
- TCITEMHEADER tciheader; |
- TABVIEWPAGE tvpage; |
- |
- operator LPTCITEM() { return (LPTCITEM)this; } |
- }; |
- |
- enum |
- { |
- m_nTabID = 1313, |
- m_cxMoveMark = 6, |
- m_cyMoveMark = 3, |
- m_nMenuItemsMax = (ID_WINDOW_TABLAST - ID_WINDOW_TABFIRST + 1) |
- }; |
- |
-// Data members |
- ATL::CContainedWindowT<CTabCtrl> m_tab; |
- int m_cyTabHeight; |
- |
- int m_nActivePage; |
- |
- int m_nInsertItem; |
- POINT m_ptStartDrag; |
- |
- CMenuHandle m_menu; |
- |
- int m_cchTabTextLength; |
- |
- int m_nMenuItemsCount; |
- |
- ATL::CWindow m_wndTitleBar; |
- LPTSTR m_lpstrTitleBarBase; |
- int m_cchTitleBarLength; |
- |
- CImageList m_ilDrag; |
- |
- bool m_bDestroyPageOnRemove:1; |
- bool m_bDestroyImageList:1; |
- bool m_bActivePageMenuItem:1; |
- bool m_bActiveAsDefaultMenuItem:1; |
- bool m_bEmptyMenuItem:1; |
- bool m_bWindowsMenuItem:1; |
- // internal |
- bool m_bTabCapture:1; |
- bool m_bTabDrag:1; |
- |
-// Constructor/destructor |
- CTabViewImpl() : |
- m_nActivePage(-1), |
- m_cyTabHeight(0), |
- m_tab(this, 1), |
- m_nInsertItem(-1), |
- m_cchTabTextLength(30), |
- m_nMenuItemsCount(10), |
- m_lpstrTitleBarBase(NULL), |
- m_cchTitleBarLength(100), |
- m_bDestroyPageOnRemove(true), |
- m_bDestroyImageList(true), |
- m_bActivePageMenuItem(true), |
- m_bActiveAsDefaultMenuItem(false), |
- m_bEmptyMenuItem(false), |
- m_bWindowsMenuItem(false), |
- m_bTabCapture(false), |
- m_bTabDrag(false) |
- { |
- m_ptStartDrag.x = 0; |
- m_ptStartDrag.y = 0; |
- } |
- |
- ~CTabViewImpl() |
- { |
- delete [] m_lpstrTitleBarBase; |
- } |
- |
-// Message filter function - to be called from PreTranslateMessage of the main window |
- BOOL PreTranslateMessage(MSG* pMsg) |
- { |
- if(IsWindow() == FALSE) |
- return FALSE; |
- |
- BOOL bRet = FALSE; |
- |
- // Check for TabView built-in accelerators (Ctrl+Tab/Ctrl+Shift+Tab - next/previous page) |
- int nCount = GetPageCount(); |
- if(nCount > 0) |
- { |
- bool bControl = (::GetKeyState(VK_CONTROL) < 0); |
- if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_TAB) && bControl) |
- { |
- if(nCount > 1) |
- { |
- int nPage = m_nActivePage; |
- bool bShift = (::GetKeyState(VK_SHIFT) < 0); |
- if(bShift) |
- nPage = (nPage > 0) ? (nPage - 1) : (nCount - 1); |
- else |
- nPage = ((nPage >= 0) && (nPage < (nCount - 1))) ? (nPage + 1) : 0; |
- |
- SetActivePage(nPage); |
- T* pT = static_cast<T*>(this); |
- pT->OnPageActivated(m_nActivePage); |
- } |
- |
- bRet = TRUE; |
- } |
- } |
- |
- // If we are doing drag-drop, check for Escape key that cancels it |
- if(bRet == FALSE) |
- { |
- if(m_bTabCapture && pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) |
- { |
- ::ReleaseCapture(); |
- bRet = TRUE; |
- } |
- } |
- |
- // Pass the message to the active page |
- if(bRet == FALSE) |
- { |
- if(m_nActivePage != -1) |
- bRet = (BOOL)::SendMessage(GetPageHWND(m_nActivePage), WM_FORWARDMSG, 0, (LPARAM)pMsg); |
- } |
- |
- return bRet; |
- } |
- |
-// Attributes |
- int GetPageCount() const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- return m_tab.GetItemCount(); |
- } |
- |
- int GetActivePage() const |
- { |
- return m_nActivePage; |
- } |
- |
- void SetActivePage(int nPage) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(IsValidPageIndex(nPage)); |
- |
- T* pT = static_cast<T*>(this); |
- |
- SetRedraw(FALSE); |
- |
- if(m_nActivePage != -1) |
- ::ShowWindow(GetPageHWND(m_nActivePage), FALSE); |
- m_nActivePage = nPage; |
- m_tab.SetCurSel(m_nActivePage); |
- ::ShowWindow(GetPageHWND(m_nActivePage), TRUE); |
- |
- pT->UpdateLayout(); |
- |
- SetRedraw(TRUE); |
- RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); |
- |
- if(::GetFocus() != m_tab.m_hWnd) |
- ::SetFocus(GetPageHWND(m_nActivePage)); |
- |
- pT->UpdateTitleBar(); |
- pT->UpdateMenu(); |
- } |
- |
- HIMAGELIST GetImageList() const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- return m_tab.GetImageList(); |
- } |
- |
- HIMAGELIST SetImageList(HIMAGELIST hImageList) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- return m_tab.SetImageList(hImageList); |
- } |
- |
- void SetWindowMenu(HMENU hMenu) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- |
- m_menu = hMenu; |
- |
- T* pT = static_cast<T*>(this); |
- pT->UpdateMenu(); |
- } |
- |
- void SetTitleBarWindow(HWND hWnd) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- |
- delete [] m_lpstrTitleBarBase; |
- m_lpstrTitleBarBase = NULL; |
- |
- m_wndTitleBar = hWnd; |
- if(hWnd == NULL) |
- return; |
- |
- int cchLen = m_wndTitleBar.GetWindowTextLength() + 1; |
- ATLTRY(m_lpstrTitleBarBase = new TCHAR[cchLen]); |
- if(m_lpstrTitleBarBase != NULL) |
- { |
- m_wndTitleBar.GetWindowText(m_lpstrTitleBarBase, cchLen); |
- T* pT = static_cast<T*>(this); |
- pT->UpdateTitleBar(); |
- } |
- } |
- |
-// Page attributes |
- HWND GetPageHWND(int nPage) const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(IsValidPageIndex(nPage)); |
- |
- TCITEMEXTRA tcix = { 0 }; |
- tcix.tciheader.mask = TCIF_PARAM; |
- m_tab.GetItem(nPage, tcix); |
- |
- return tcix.tvpage.hWnd; |
- } |
- |
- LPCTSTR GetPageTitle(int nPage) const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(IsValidPageIndex(nPage)); |
- |
- TCITEMEXTRA tcix = { 0 }; |
- tcix.tciheader.mask = TCIF_PARAM; |
- if(m_tab.GetItem(nPage, tcix) == FALSE) |
- return NULL; |
- |
- return tcix.tvpage.lpstrTitle; |
- } |
- |
- bool SetPageTitle(int nPage, LPCTSTR lpstrTitle) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(IsValidPageIndex(nPage)); |
- |
- T* pT = static_cast<T*>(this); |
- |
- int cchBuff = lstrlen(lpstrTitle) + 1; |
- LPTSTR lpstrBuff = NULL; |
- ATLTRY(lpstrBuff = new TCHAR[cchBuff]); |
- if(lpstrBuff == NULL) |
- return false; |
- |
- SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle); |
- TCITEMEXTRA tcix = { 0 }; |
- tcix.tciheader.mask = TCIF_PARAM; |
- if(m_tab.GetItem(nPage, tcix) == FALSE) |
- return false; |
- |
- CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff; |
- LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); |
- if(lpstrTabText == NULL) |
- return false; |
- |
- delete [] tcix.tvpage.lpstrTitle; |
- |
- pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1); |
- |
- tcix.tciheader.mask = TCIF_TEXT | TCIF_PARAM; |
- tcix.tciheader.pszText = lpstrTabText; |
- tcix.tvpage.lpstrTitle = lpstrBuff; |
- if(m_tab.SetItem(nPage, tcix) == FALSE) |
- return false; |
- |
- pT->UpdateTitleBar(); |
- pT->UpdateMenu(); |
- |
- return true; |
- } |
- |
- LPVOID GetPageData(int nPage) const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(IsValidPageIndex(nPage)); |
- |
- TCITEMEXTRA tcix = { 0 }; |
- tcix.tciheader.mask = TCIF_PARAM; |
- m_tab.GetItem(nPage, tcix); |
- |
- return tcix.tvpage.pData; |
- } |
- |
- LPVOID SetPageData(int nPage, LPVOID pData) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(IsValidPageIndex(nPage)); |
- |
- TCITEMEXTRA tcix = { 0 }; |
- tcix.tciheader.mask = TCIF_PARAM; |
- m_tab.GetItem(nPage, tcix); |
- LPVOID pDataOld = tcix.tvpage.pData; |
- |
- tcix.tvpage.pData = pData; |
- m_tab.SetItem(nPage, tcix); |
- |
- return pDataOld; |
- } |
- |
- int GetPageImage(int nPage) const |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(IsValidPageIndex(nPage)); |
- |
- TCITEMEXTRA tcix = { 0 }; |
- tcix.tciheader.mask = TCIF_IMAGE; |
- m_tab.GetItem(nPage, tcix); |
- |
- return tcix.tciheader.iImage; |
- } |
- |
- int SetPageImage(int nPage, int nImage) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(IsValidPageIndex(nPage)); |
- |
- TCITEMEXTRA tcix = { 0 }; |
- tcix.tciheader.mask = TCIF_IMAGE; |
- m_tab.GetItem(nPage, tcix); |
- int nImageOld = tcix.tciheader.iImage; |
- |
- tcix.tciheader.iImage = nImage; |
- m_tab.SetItem(nPage, tcix); |
- |
- return nImageOld; |
- } |
- |
-// Operations |
- bool AddPage(HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL) |
- { |
- return InsertPage(GetPageCount(), hWndView, lpstrTitle, nImage, pData); |
- } |
- |
- bool InsertPage(int nPage, HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(nPage == GetPageCount() || IsValidPageIndex(nPage)); |
- |
- T* pT = static_cast<T*>(this); |
- |
- int cchBuff = lstrlen(lpstrTitle) + 1; |
- LPTSTR lpstrBuff = NULL; |
- ATLTRY(lpstrBuff = new TCHAR[cchBuff]); |
- if(lpstrBuff == NULL) |
- return false; |
- |
- SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle); |
- |
- CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff; |
- LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); |
- if(lpstrTabText == NULL) |
- return false; |
- |
- pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1); |
- |
- SetRedraw(FALSE); |
- |
- TCITEMEXTRA tcix = { 0 }; |
- tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; |
- tcix.tciheader.pszText = lpstrTabText; |
- tcix.tciheader.iImage = nImage; |
- tcix.tvpage.hWnd = hWndView; |
- tcix.tvpage.lpstrTitle = lpstrBuff; |
- tcix.tvpage.pData = pData; |
- int nItem = m_tab.InsertItem(nPage, tcix); |
- if(nItem == -1) |
- { |
- delete [] lpstrBuff; |
- SetRedraw(TRUE); |
- return false; |
- } |
- |
- SetActivePage(nItem); |
- pT->OnPageActivated(m_nActivePage); |
- |
- if(GetPageCount() == 1) |
- pT->ShowTabControl(true); |
- |
- pT->UpdateLayout(); |
- |
- SetRedraw(TRUE); |
- RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN); |
- |
- return true; |
- } |
- |
- void RemovePage(int nPage) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- ATLASSERT(IsValidPageIndex(nPage)); |
- |
- T* pT = static_cast<T*>(this); |
- |
- SetRedraw(FALSE); |
- |
- if(GetPageCount() == 1) |
- pT->ShowTabControl(false); |
- |
- if(m_bDestroyPageOnRemove) |
- ::DestroyWindow(GetPageHWND(nPage)); |
- else |
- ::ShowWindow(GetPageHWND(nPage), FALSE); |
- LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(nPage); |
- delete [] lpstrTitle; |
- |
- ATLVERIFY(m_tab.DeleteItem(nPage) != FALSE); |
- |
- if(m_nActivePage == nPage) |
- { |
- m_nActivePage = -1; |
- |
- if(nPage > 0) |
- { |
- SetActivePage(nPage - 1); |
- } |
- else if(GetPageCount() > 0) |
- { |
- SetActivePage(nPage); |
- } |
- else |
- { |
- SetRedraw(TRUE); |
- Invalidate(); |
- UpdateWindow(); |
- pT->UpdateTitleBar(); |
- pT->UpdateMenu(); |
- } |
- } |
- else |
- { |
- nPage = (nPage < m_nActivePage) ? (m_nActivePage - 1) : m_nActivePage; |
- m_nActivePage = -1; |
- SetActivePage(nPage); |
- } |
- |
- pT->OnPageActivated(m_nActivePage); |
- } |
- |
- void RemoveAllPages() |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- |
- if(GetPageCount() == 0) |
- return; |
- |
- T* pT = static_cast<T*>(this); |
- |
- SetRedraw(FALSE); |
- |
- pT->ShowTabControl(false); |
- |
- for(int i = 0; i < GetPageCount(); i++) |
- { |
- if(m_bDestroyPageOnRemove) |
- ::DestroyWindow(GetPageHWND(i)); |
- else |
- ::ShowWindow(GetPageHWND(i), FALSE); |
- LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(i); |
- delete [] lpstrTitle; |
- } |
- m_tab.DeleteAllItems(); |
- |
- m_nActivePage = -1; |
- pT->OnPageActivated(m_nActivePage); |
- |
- SetRedraw(TRUE); |
- Invalidate(); |
- UpdateWindow(); |
- |
- pT->UpdateTitleBar(); |
- pT->UpdateMenu(); |
- } |
- |
- int PageIndexFromHwnd(HWND hWnd) const |
- { |
- int nIndex = -1; |
- |
- for(int i = 0; i < GetPageCount(); i++) |
- { |
- if(GetPageHWND(i) == hWnd) |
- { |
- nIndex = i; |
- break; |
- } |
- } |
- |
- return nIndex; |
- } |
- |
- void BuildWindowMenu(HMENU hMenu, int nMenuItemsCount = 10, bool bEmptyMenuItem = true, bool bWindowsMenuItem = true, bool bActivePageMenuItem = true, bool bActiveAsDefaultMenuItem = false) |
- { |
- ATLASSERT(::IsWindow(m_hWnd)); |
- |
- CMenuHandle menu = hMenu; |
- T* pT = static_cast<T*>(this); |
- pT; // avoid level 4 warning |
- int nFirstPos = 0; |
- |
- // Find first menu item in our range |
-#ifndef _WIN32_WCE |
- for(nFirstPos = 0; nFirstPos < menu.GetMenuItemCount(); nFirstPos++) |
- { |
- UINT nID = menu.GetMenuItemID(nFirstPos); |
- if((nID >= ID_WINDOW_TABFIRST && nID <= ID_WINDOW_TABLAST) || nID == ID_WINDOW_SHOWTABLIST) |
- break; |
- } |
-#else // CE specific |
- for(nFirstPos = 0; ; nFirstPos++) |
- { |
- CMenuItemInfo mii; |
- mii.fMask = MIIM_ID; |
- BOOL bRet = menu.GetMenuItemInfo(nFirstPos, TRUE, &mii); |
- if(bRet == FALSE) |
- break; |
- if((mii.wID >= ID_WINDOW_TABFIRST && mii.wID <= ID_WINDOW_TABLAST) || mii.wID == ID_WINDOW_SHOWTABLIST) |
- break; |
- } |
-#endif // _WIN32_WCE |
- |
- // Remove all menu items for tab pages |
- BOOL bRet = TRUE; |
- while(bRet != FALSE) |
- bRet = menu.DeleteMenu(nFirstPos, MF_BYPOSITION); |
- |
- // Add separator if it's not already there |
- int nPageCount = GetPageCount(); |
- if((bWindowsMenuItem || (nPageCount > 0)) && (nFirstPos > 0)) |
- { |
- CMenuItemInfo mii; |
- mii.fMask = MIIM_TYPE; |
- menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii); |
- if((nFirstPos <= 0) || ((mii.fType & MFT_SEPARATOR) == 0)) |
- { |
- menu.AppendMenu(MF_SEPARATOR); |
- nFirstPos++; |
- } |
- } |
- |
- // Add menu items for all pages |
- if(nPageCount > 0) |
- { |
- // Append menu items for all pages |
- const int cchPrefix = 3; // 2 digits + space |
- nMenuItemsCount = __min(min(nPageCount, nMenuItemsCount), (int)m_nMenuItemsMax); |
- ATLASSERT(nMenuItemsCount < 100); // 2 digits only |
- if(nMenuItemsCount >= 100) |
- nMenuItemsCount = 99; |
- |
- for(int i = 0; i < nMenuItemsCount; i++) |
- { |
- LPCTSTR lpstrTitle = GetPageTitle(i); |
- int nLen = lstrlen(lpstrTitle); |
- CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff; |
- LPTSTR lpstrText = buff.Allocate(cchPrefix + nLen + 1); |
- ATLASSERT(lpstrText != NULL); |
- if(lpstrText != NULL) |
- { |
- LPCTSTR lpstrFormat = (i < 9) ? _T("&%i %s") : _T("%i %s"); |
- SecureHelper::wsprintf_x(lpstrText, cchPrefix + nLen + 1, lpstrFormat, i + 1, lpstrTitle); |
- menu.AppendMenu(MF_STRING, ID_WINDOW_TABFIRST + i, lpstrText); |
- } |
- } |
- |
- // Mark active page |
- if(bActivePageMenuItem && (m_nActivePage != -1)) |
- { |
-#ifndef _WIN32_WCE |
- if(bActiveAsDefaultMenuItem) |
- { |
- menu.SetMenuDefaultItem((UINT)-1, TRUE); |
- menu.SetMenuDefaultItem(nFirstPos + m_nActivePage, TRUE); |
- } |
- else |
-#else // CE specific |
- bActiveAsDefaultMenuItem; // avoid level 4 warning |
-#endif // _WIN32_WCE |
- { |
- menu.CheckMenuRadioItem(nFirstPos, nFirstPos + nMenuItemsCount, nFirstPos + m_nActivePage, MF_BYPOSITION); |
- } |
- } |
- } |
- else |
- { |
- if(bEmptyMenuItem) |
- { |
- menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_TABFIRST, pT->GetEmptyListText()); |
- menu.EnableMenuItem(ID_WINDOW_TABFIRST, MF_GRAYED); |
- } |
- |
- // Remove separator if nothing else is there |
- if(!bEmptyMenuItem && !bWindowsMenuItem && (nFirstPos > 0)) |
- { |
- CMenuItemInfo mii; |
- mii.fMask = MIIM_TYPE; |
- menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii); |
- if((mii.fType & MFT_SEPARATOR) != 0) |
- menu.DeleteMenu(nFirstPos - 1, MF_BYPOSITION); |
- } |
- } |
- |
- // Add "Windows..." menu item |
- if(bWindowsMenuItem) |
- menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_SHOWTABLIST, pT->GetWindowsMenuItemText()); |
- } |
- |
-// Message map and handlers |
- BEGIN_MSG_MAP(CTabViewImpl) |
- MESSAGE_HANDLER(WM_CREATE, OnCreate) |
- MESSAGE_HANDLER(WM_DESTROY, OnDestroy) |
- MESSAGE_HANDLER(WM_SIZE, OnSize) |
- MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus) |
- NOTIFY_HANDLER(m_nTabID, TCN_SELCHANGE, OnTabChanged) |
- NOTIFY_ID_HANDLER(m_nTabID, OnTabNotification) |
-#ifndef _WIN32_WCE |
- NOTIFY_CODE_HANDLER(TTN_GETDISPINFO, OnTabGetDispInfo) |
-#endif // !_WIN32_WCE |
- FORWARD_NOTIFICATIONS() |
- ALT_MSG_MAP(1) // tab control |
- MESSAGE_HANDLER(WM_LBUTTONDOWN, OnTabLButtonDown) |
- MESSAGE_HANDLER(WM_LBUTTONUP, OnTabLButtonUp) |
- MESSAGE_HANDLER(WM_CAPTURECHANGED, OnTabCaptureChanged) |
- MESSAGE_HANDLER(WM_MOUSEMOVE, OnTabMouseMove) |
- MESSAGE_HANDLER(WM_RBUTTONUP, OnTabRButtonUp) |
- MESSAGE_HANDLER(WM_SYSKEYDOWN, OnTabSysKeyDown) |
- END_MSG_MAP() |
- |
- LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->CreateTabControl(); |
- |
- return 0; |
- } |
- |
- LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- RemoveAllPages(); |
- |
- if(m_bDestroyImageList) |
- { |
- CImageList il = m_tab.SetImageList(NULL); |
- if(il.m_hImageList != NULL) |
- il.Destroy(); |
- } |
- |
- return 0; |
- } |
- |
- LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->UpdateLayout(); |
- return 0; |
- } |
- |
- LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/) |
- { |
- if(m_nActivePage != -1) |
- ::SetFocus(GetPageHWND(m_nActivePage)); |
- return 0; |
- } |
- |
- LRESULT OnTabChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) |
- { |
- SetActivePage(m_tab.GetCurSel()); |
- T* pT = static_cast<T*>(this); |
- pT->OnPageActivated(m_nActivePage); |
- |
- return 0; |
- } |
- |
- LRESULT OnTabNotification(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/) |
- { |
- // nothing to do - this just blocks all tab control |
- // notifications from being propagated further |
- return 0; |
- } |
- |
-#ifndef _WIN32_WCE |
- LRESULT OnTabGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled) |
- { |
- LPNMTTDISPINFO pTTDI = (LPNMTTDISPINFO)pnmh; |
- if(pTTDI->hdr.hwndFrom == m_tab.GetTooltips()) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->UpdateTooltipText(pTTDI); |
- } |
- else |
- { |
- bHandled = FALSE; |
- } |
- |
- return 0; |
- } |
-#endif // !_WIN32_WCE |
- |
-// Tab control message handlers |
- LRESULT OnTabLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) |
- { |
- if(m_tab.GetItemCount() > 1) |
- { |
- m_bTabCapture = true; |
- m_tab.SetCapture(); |
- |
- m_ptStartDrag.x = GET_X_LPARAM(lParam); |
- m_ptStartDrag.y = GET_Y_LPARAM(lParam); |
- } |
- |
- bHandled = FALSE; |
- return 0; |
- } |
- |
- LRESULT OnTabLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) |
- { |
- if(m_bTabCapture) |
- { |
- if(m_bTabDrag) |
- { |
- TCHITTESTINFO hti = { 0 }; |
- hti.pt.x = GET_X_LPARAM(lParam); |
- hti.pt.y = GET_Y_LPARAM(lParam); |
- int nItem = m_tab.HitTest(&hti); |
- if(nItem != -1) |
- MovePage(m_nActivePage, nItem); |
- } |
- |
- ::ReleaseCapture(); |
- } |
- |
- bHandled = FALSE; |
- return 0; |
- } |
- |
- LRESULT OnTabCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- if(m_bTabCapture) |
- { |
- m_bTabCapture = false; |
- |
- if(m_bTabDrag) |
- { |
- m_bTabDrag = false; |
- T* pT = static_cast<T*>(this); |
- pT->DrawMoveMark(-1); |
- |
-#ifndef _WIN32_WCE |
- m_ilDrag.DragLeave(GetDesktopWindow()); |
-#endif // !_WIN32_WCE |
- m_ilDrag.EndDrag(); |
- |
- m_ilDrag.Destroy(); |
- m_ilDrag.m_hImageList = NULL; |
- } |
- } |
- |
- bHandled = FALSE; |
- return 0; |
- } |
- |
- LRESULT OnTabMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled) |
- { |
- bHandled = FALSE; |
- |
- if(m_bTabCapture) |
- { |
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) }; |
- |
- if(!m_bTabDrag) |
- { |
-#ifndef _WIN32_WCE |
- if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CXDRAG) || |
- abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CYDRAG)) |
-#else // CE specific |
- if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= 4 || |
- abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= 4) |
-#endif // _WIN32_WCE |
- { |
- T* pT = static_cast<T*>(this); |
- pT->GenerateDragImage(m_nActivePage); |
- |
- int cxCursor = ::GetSystemMetrics(SM_CXCURSOR); |
- int cyCursor = ::GetSystemMetrics(SM_CYCURSOR); |
- m_ilDrag.BeginDrag(0, -(cxCursor / 2), -(cyCursor / 2)); |
-#ifndef _WIN32_WCE |
- POINT ptEnter = m_ptStartDrag; |
- m_tab.ClientToScreen(&ptEnter); |
- m_ilDrag.DragEnter(GetDesktopWindow(), ptEnter); |
-#endif // !_WIN32_WCE |
- |
- m_bTabDrag = true; |
- } |
- } |
- |
- if(m_bTabDrag) |
- { |
- TCHITTESTINFO hti = { 0 }; |
- hti.pt = pt; |
- int nItem = m_tab.HitTest(&hti); |
- |
- T* pT = static_cast<T*>(this); |
- pT->SetMoveCursor(nItem != -1); |
- |
- if(m_nInsertItem != nItem) |
- pT->DrawMoveMark(nItem); |
- |
- m_ilDrag.DragShowNolock((nItem != -1) ? TRUE : FALSE); |
- m_tab.ClientToScreen(&pt); |
- m_ilDrag.DragMove(pt); |
- |
- bHandled = TRUE; |
- } |
- } |
- |
- return 0; |
- } |
- |
- LRESULT OnTabRButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/) |
- { |
- TCHITTESTINFO hti = { 0 }; |
- hti.pt.x = GET_X_LPARAM(lParam); |
- hti.pt.y = GET_Y_LPARAM(lParam); |
- int nItem = m_tab.HitTest(&hti); |
- if(nItem != -1) |
- { |
- T* pT = static_cast<T*>(this); |
- pT->OnContextMenu(nItem, hti.pt); |
- } |
- |
- return 0; |
- } |
- |
- LRESULT OnTabSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled) |
- { |
- bool bShift = (::GetKeyState(VK_SHIFT) < 0); |
- if(wParam == VK_F10 && bShift) |
- { |
- if(m_nActivePage != -1) |
- { |
- RECT rect = { 0 }; |
- m_tab.GetItemRect(m_nActivePage, &rect); |
- POINT pt = { rect.left, rect.bottom }; |
- T* pT = static_cast<T*>(this); |
- pT->OnContextMenu(m_nActivePage, pt); |
- } |
- } |
- else |
- { |
- bHandled = FALSE; |
- } |
- |
- return 0; |
- } |
- |
-// Implementation helpers |
- bool IsValidPageIndex(int nPage) const |
- { |
- return (nPage >= 0 && nPage < GetPageCount()); |
- } |
- |
- bool MovePage(int nMovePage, int nInsertBeforePage) |
- { |
- ATLASSERT(IsValidPageIndex(nMovePage)); |
- ATLASSERT(IsValidPageIndex(nInsertBeforePage)); |
- |
- if(!IsValidPageIndex(nMovePage) || !IsValidPageIndex(nInsertBeforePage)) |
- return false; |
- |
- if(nMovePage == nInsertBeforePage) |
- return true; // nothing to do |
- |
- CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff; |
- LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1); |
- if(lpstrTabText == NULL) |
- return false; |
- TCITEMEXTRA tcix = { 0 }; |
- tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM; |
- tcix.tciheader.pszText = lpstrTabText; |
- tcix.tciheader.cchTextMax = m_cchTabTextLength + 1; |
- BOOL bRet = m_tab.GetItem(nMovePage, tcix); |
- ATLASSERT(bRet != FALSE); |
- if(bRet == FALSE) |
- return false; |
- |
- int nInsertItem = (nInsertBeforePage > nMovePage) ? nInsertBeforePage + 1 : nInsertBeforePage; |
- int nNewItem = m_tab.InsertItem(nInsertItem, tcix); |
- ATLASSERT(nNewItem == nInsertItem); |
- if(nNewItem != nInsertItem) |
- { |
- ATLVERIFY(m_tab.DeleteItem(nNewItem)); |
- return false; |
- } |
- |
- if(nMovePage > nInsertBeforePage) |
- ATLVERIFY(m_tab.DeleteItem(nMovePage + 1) != FALSE); |
- else if(nMovePage < nInsertBeforePage) |
- ATLVERIFY(m_tab.DeleteItem(nMovePage) != FALSE); |
- |
- SetActivePage(nInsertBeforePage); |
- T* pT = static_cast<T*>(this); |
- pT->OnPageActivated(m_nActivePage); |
- |
- return true; |
- } |
- |
-// Implementation overrideables |
- bool CreateTabControl() |
- { |
-#ifndef _WIN32_WCE |
- m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_TOOLTIPS, 0, m_nTabID); |
-#else // CE specific |
- m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, m_nTabID); |
-#endif // _WIN32_WCE |
- ATLASSERT(m_tab.m_hWnd != NULL); |
- if(m_tab.m_hWnd == NULL) |
- return false; |
- |
- m_tab.SetFont(AtlGetDefaultGuiFont()); |
- |
- m_tab.SetItemExtra(sizeof(TABVIEWPAGE)); |
- |
- T* pT = static_cast<T*>(this); |
- m_cyTabHeight = pT->CalcTabHeight(); |
- |
- return true; |
- } |
- |
- int CalcTabHeight() |
- { |
- int nCount = m_tab.GetItemCount(); |
- TCITEMEXTRA tcix = { 0 }; |
- tcix.tciheader.mask = TCIF_TEXT; |
- tcix.tciheader.pszText = _T("NS"); |
- int nIndex = m_tab.InsertItem(nCount, tcix); |
- |
- RECT rect = { 0, 0, 1000, 1000 }; |
- m_tab.AdjustRect(FALSE, &rect); |
- |
- RECT rcWnd = { 0, 0, 1000, rect.top }; |
- ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle()); |
- |
- int nHeight = rcWnd.bottom - rcWnd.top; |
- |
- m_tab.DeleteItem(nIndex); |
- |
- return nHeight; |
- } |
- |
- void ShowTabControl(bool bShow) |
- { |
- m_tab.ShowWindow(bShow ? SW_SHOWNOACTIVATE : SW_HIDE); |
- } |
- |
- void UpdateLayout() |
- { |
- RECT rect; |
- GetClientRect(&rect); |
- |
- if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0)) |
- m_tab.SetWindowPos(NULL, 0, 0, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER); |
- |
- if(m_nActivePage != -1) |
- ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, m_cyTabHeight, rect.right - rect.left, rect.bottom - rect.top - m_cyTabHeight, SWP_NOZORDER); |
- } |
- |
- void UpdateMenu() |
- { |
- if(m_menu.m_hMenu != NULL) |
- BuildWindowMenu(m_menu, m_nMenuItemsCount, m_bEmptyMenuItem, m_bWindowsMenuItem, m_bActivePageMenuItem, m_bActiveAsDefaultMenuItem); |
- } |
- |
- void UpdateTitleBar() |
- { |
- if(!m_wndTitleBar.IsWindow() || m_lpstrTitleBarBase == NULL) |
- return; // nothing to do |
- |
- if(m_nActivePage != -1) |
- { |
- T* pT = static_cast<T*>(this); |
- LPCTSTR lpstrTitle = pT->GetPageTitle(m_nActivePage); |
- LPCTSTR lpstrDivider = pT->GetTitleDividerText(); |
- int cchBuffer = m_cchTitleBarLength + lstrlen(lpstrDivider) + lstrlen(m_lpstrTitleBarBase) + 1; |
- CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff; |
- LPTSTR lpstrPageTitle = buff.Allocate(cchBuffer); |
- ATLASSERT(lpstrPageTitle != NULL); |
- if(lpstrPageTitle != NULL) |
- { |
- pT->ShortenTitle(lpstrTitle, lpstrPageTitle, m_cchTitleBarLength + 1); |
- SecureHelper::strcat_x(lpstrPageTitle, cchBuffer, lpstrDivider); |
- SecureHelper::strcat_x(lpstrPageTitle, cchBuffer, m_lpstrTitleBarBase); |
- } |
- else |
- { |
- lpstrPageTitle = m_lpstrTitleBarBase; |
- } |
- |
- m_wndTitleBar.SetWindowText(lpstrPageTitle); |
- } |
- else |
- { |
- m_wndTitleBar.SetWindowText(m_lpstrTitleBarBase); |
- } |
- } |
- |
- void DrawMoveMark(int nItem) |
- { |
- T* pT = static_cast<T*>(this); |
- |
- if(m_nInsertItem != -1) |
- { |
- RECT rect = { 0 }; |
- pT->GetMoveMarkRect(rect); |
- m_tab.InvalidateRect(&rect); |
- } |
- |
- m_nInsertItem = nItem; |
- |
- if(m_nInsertItem != -1) |
- { |
- CClientDC dc(m_tab.m_hWnd); |
- |
- RECT rect = { 0 }; |
- pT->GetMoveMarkRect(rect); |
- |
- CPen pen; |
- pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEXT)); |
- CBrush brush; |
- brush.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT)); |
- |
- HPEN hPenOld = dc.SelectPen(pen); |
- HBRUSH hBrushOld = dc.SelectBrush(brush); |
- |
- int x = rect.left; |
- int y = rect.top; |
- POINT ptsTop[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y + m_cyMoveMark } }; |
- dc.Polygon(ptsTop, 3); |
- |
- y = rect.bottom - 1; |
- POINT ptsBottom[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y - m_cyMoveMark } }; |
- dc.Polygon(ptsBottom, 3); |
- |
- dc.SelectPen(hPenOld); |
- dc.SelectBrush(hBrushOld); |
- } |
- } |
- |
- void GetMoveMarkRect(RECT& rect) const |
- { |
- m_tab.GetClientRect(&rect); |
- |
- RECT rcItem = { 0 }; |
- m_tab.GetItemRect(m_nInsertItem, &rcItem); |
- |
- if(m_nInsertItem <= m_nActivePage) |
- { |
- rect.left = rcItem.left - m_cxMoveMark / 2 - 1; |
- rect.right = rcItem.left + m_cxMoveMark / 2; |
- } |
- else |
- { |
- rect.left = rcItem.right - m_cxMoveMark / 2 - 1; |
- rect.right = rcItem.right + m_cxMoveMark / 2; |
- } |
- } |
- |
- void SetMoveCursor(bool bCanMove) |
- { |
- ::SetCursor(::LoadCursor(NULL, bCanMove ? IDC_ARROW : IDC_NO)); |
- } |
- |
- void GenerateDragImage(int nItem) |
- { |
- ATLASSERT(IsValidPageIndex(nItem)); |
- |
-#ifndef _WIN32_WCE |
- RECT rcItem = { 0 }; |
- m_tab.GetItemRect(nItem, &rcItem); |
- ::InflateRect(&rcItem, 2, 2); // make bigger to cover selected item |
-#else // CE specific |
- nItem; // avoid level 4 warning |
- RECT rcItem = { 0, 0, 40, 20 }; |
-#endif // _WIN32_WCE |
- |
- ATLASSERT(m_ilDrag.m_hImageList == NULL); |
- m_ilDrag.Create(rcItem.right - rcItem.left, rcItem.bottom - rcItem.top, ILC_COLORDDB | ILC_MASK, 1, 1); |
- |
- CClientDC dc(m_hWnd); |
- CDC dcMem; |
- dcMem.CreateCompatibleDC(dc); |
- ATLASSERT(dcMem.m_hDC != NULL); |
- dcMem.SetViewportOrg(-rcItem.left, -rcItem.top); |
- |
- CBitmap bmp; |
- bmp.CreateCompatibleBitmap(dc, rcItem.right - rcItem.left, rcItem.bottom - rcItem.top); |
- ATLASSERT(bmp.m_hBitmap != NULL); |
- |
- HBITMAP hBmpOld = dcMem.SelectBitmap(bmp); |
-#ifndef _WIN32_WCE |
- m_tab.SendMessage(WM_PRINTCLIENT, (WPARAM)dcMem.m_hDC); |
-#else // CE specific |
- dcMem.Rectangle(&rcItem); |
-#endif // _WIN32_WCE |
- dcMem.SelectBitmap(hBmpOld); |
- |
- ATLVERIFY(m_ilDrag.Add(bmp.m_hBitmap, RGB(255, 0, 255)) != -1); |
- } |
- |
- void ShortenTitle(LPCTSTR lpstrTitle, LPTSTR lpstrShortTitle, int cchShortTitle) |
- { |
- if(lstrlen(lpstrTitle) >= cchShortTitle) |
- { |
- LPCTSTR lpstrEllipsis = _T("..."); |
- int cchEllipsis = lstrlen(lpstrEllipsis); |
- SecureHelper::strncpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle, cchShortTitle - cchEllipsis - 1); |
- SecureHelper::strcat_x(lpstrShortTitle, cchShortTitle, lpstrEllipsis); |
- } |
- else |
- { |
- SecureHelper::strcpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle); |
- } |
- } |
- |
-#ifndef _WIN32_WCE |
- void UpdateTooltipText(LPNMTTDISPINFO pTTDI) |
- { |
- ATLASSERT(pTTDI != NULL); |
- pTTDI->lpszText = (LPTSTR)GetPageTitle((int)pTTDI->hdr.idFrom); |
- } |
-#endif // !_WIN32_WCE |
- |
-// Text for menu items and title bar - override to provide different strings |
- static LPCTSTR GetEmptyListText() |
- { |
- return _T("(Empty)"); |
- } |
- |
- static LPCTSTR GetWindowsMenuItemText() |
- { |
- return _T("&Windows..."); |
- } |
- |
- static LPCTSTR GetTitleDividerText() |
- { |
- return _T(" - "); |
- } |
- |
-// Notifications - override to provide different behavior |
- void OnPageActivated(int nPage) |
- { |
- NMHDR nmhdr = { 0 }; |
- nmhdr.hwndFrom = m_hWnd; |
- nmhdr.idFrom = nPage; |
- nmhdr.code = TBVN_PAGEACTIVATED; |
- ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr); |
- } |
- |
- void OnContextMenu(int nPage, POINT pt) |
- { |
- m_tab.ClientToScreen(&pt); |
- |
- TBVCONTEXTMENUINFO cmi = { 0 }; |
- cmi.hdr.hwndFrom = m_hWnd; |
- cmi.hdr.idFrom = nPage; |
- cmi.hdr.code = TBVN_CONTEXTMENU; |
- cmi.pt = pt; |
- ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&cmi); |
- } |
-}; |
- |
- |
-class CTabView : public CTabViewImpl<CTabView> |
-{ |
-public: |
- DECLARE_WND_CLASS_EX(_T("WTL_TabView"), 0, COLOR_APPWORKSPACE) |
-}; |
- |
-}; // namespace WTL |
- |
-#endif // __ATLCTRLX_H__ |