1 // Windows Template Library - WTL version 8.0
2 // Copyright (C) Microsoft Corporation. All rights reserved.
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Permissive License (Ms-PL) which can be found in the file
7 // Ms-PL.txt at the root of this distribution.
10 #define __ATLCTRLX_H__
15 #error ATL requires C++ compilation (use a .cpp suffix)
19 #error atlctrlx.h requires atlapp.h to be included first
22 #ifndef __ATLCTRLS_H__
23 #error atlctrlx.h requires atlctrls.h to be included first
26 #ifndef WM_UPDATEUISTATE
27 #define WM_UPDATEUISTATE 0x0128
28 #endif // !WM_UPDATEUISTATE
31 ///////////////////////////////////////////////////////////////////////////////
32 // Classes in this file:
34 // CBitmapButtonImpl<T, TBase, TWinTraits>
36 // CCheckListViewCtrlImpl<T, TBase, TWinTraits>
38 // CHyperLinkImpl<T, TBase, TWinTraits>
42 // CMultiPaneStatusBarCtrlImpl<T, TBase>
43 // CMultiPaneStatusBarCtrl
44 // CPaneContainerImpl<T, TBase, TWinTraits>
46 // CSortListViewImpl<T>
47 // CSortListViewCtrlImpl<T, TBase, TWinTraits>
49 // CTabViewImpl<T, TBase, TWinTraits>
55 ///////////////////////////////////////////////////////////////////////////////
56 // CBitmapButton - bitmap button implementation
60 // bitmap button extended styles
61 #define BMPBTN_HOVER 0x00000001
62 #define BMPBTN_AUTO3D_SINGLE 0x00000002
63 #define BMPBTN_AUTO3D_DOUBLE 0x00000004
64 #define BMPBTN_AUTOSIZE 0x00000008
65 #define BMPBTN_SHAREIMAGELISTS 0x00000010
66 #define BMPBTN_AUTOFIRE 0x00000020
68 template <class T
, class TBase
= CButton
, class TWinTraits
= ATL::CControlWinTraits
>
69 class ATL_NO_VTABLE CBitmapButtonImpl
: public ATL::CWindowImpl
< T
, TBase
, TWinTraits
>
72 DECLARE_WND_SUPERCLASS(NULL
, TBase::GetWndClassName())
86 ID_TIMER_FIRST
= 1000,
87 ID_TIMER_REPEAT
= 1001
90 // Bitmap button specific extended styles
91 DWORD m_dwExtendedStyle
;
93 CImageList m_ImageList
;
94 int m_nImage
[_nImageCount
];
97 LPTSTR m_lpstrToolTipText
;
100 unsigned m_fMouseOver
:1;
102 unsigned m_fPressed
:1;
105 // Constructor/Destructor
106 CBitmapButtonImpl(DWORD dwExtendedStyle
= BMPBTN_AUTOSIZE
, HIMAGELIST hImageList
= NULL
) :
107 m_ImageList(hImageList
), m_dwExtendedStyle(dwExtendedStyle
),
108 m_lpstrToolTipText(NULL
),
109 m_fMouseOver(0), m_fFocus(0), m_fPressed(0)
111 m_nImage
[_nImageNormal
] = -1;
112 m_nImage
[_nImagePushed
] = -1;
113 m_nImage
[_nImageFocusOrHover
] = -1;
114 m_nImage
[_nImageDisabled
] = -1;
119 if((m_dwExtendedStyle
& BMPBTN_SHAREIMAGELISTS
) == 0)
120 m_ImageList
.Destroy();
121 delete [] m_lpstrToolTipText
;
124 // overridden to provide proper initialization
125 BOOL
SubclassWindow(HWND hWnd
)
127 #if (_MSC_VER >= 1300)
128 BOOL bRet
= ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::SubclassWindow(hWnd
);
129 #else // !(_MSC_VER >= 1300)
130 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
131 BOOL bRet
= _baseClass::SubclassWindow(hWnd
);
132 #endif // !(_MSC_VER >= 1300)
139 DWORD
GetBitmapButtonExtendedStyle() const
141 return m_dwExtendedStyle
;
144 DWORD
SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle
, DWORD dwMask
= 0)
146 DWORD dwPrevStyle
= m_dwExtendedStyle
;
148 m_dwExtendedStyle
= dwExtendedStyle
;
150 m_dwExtendedStyle
= (m_dwExtendedStyle
& ~dwMask
) | (dwExtendedStyle
& dwMask
);
154 HIMAGELIST
GetImageList() const
159 HIMAGELIST
SetImageList(HIMAGELIST hImageList
)
161 HIMAGELIST hImageListPrev
= m_ImageList
;
162 m_ImageList
= hImageList
;
163 if((m_dwExtendedStyle
& BMPBTN_AUTOSIZE
) != 0 && ::IsWindow(m_hWnd
))
165 return hImageListPrev
;
168 int GetToolTipTextLength() const
170 return (m_lpstrToolTipText
== NULL
) ? -1 : lstrlen(m_lpstrToolTipText
);
173 bool GetToolTipText(LPTSTR lpstrText
, int nLength
) const
175 ATLASSERT(lpstrText
!= NULL
);
176 if(m_lpstrToolTipText
== NULL
)
179 errno_t nRet
= SecureHelper::strncpy_x(lpstrText
, nLength
, m_lpstrToolTipText
, _TRUNCATE
);
181 return (nRet
== 0 || nRet
== STRUNCATE
);
184 bool SetToolTipText(LPCTSTR lpstrText
)
186 if(m_lpstrToolTipText
!= NULL
)
188 delete [] m_lpstrToolTipText
;
189 m_lpstrToolTipText
= NULL
;
192 if(lpstrText
== NULL
)
195 m_tip
.Activate(FALSE
);
199 int cchLen
= lstrlen(lpstrText
) + 1;
200 ATLTRY(m_lpstrToolTipText
= new TCHAR
[cchLen
]);
201 if(m_lpstrToolTipText
== NULL
)
204 SecureHelper::strcpy_x(m_lpstrToolTipText
, cchLen
, lpstrText
);
207 m_tip
.Activate(TRUE
);
208 m_tip
.AddTool(m_hWnd
, m_lpstrToolTipText
);
215 void SetImages(int nNormal
, int nPushed
= -1, int nFocusOrHover
= -1, int nDisabled
= -1)
218 m_nImage
[_nImageNormal
] = nNormal
;
220 m_nImage
[_nImagePushed
] = nPushed
;
221 if(nFocusOrHover
!= -1)
222 m_nImage
[_nImageFocusOrHover
] = nFocusOrHover
;
224 m_nImage
[_nImageDisabled
] = nDisabled
;
229 ATLASSERT(::IsWindow(m_hWnd
) && m_ImageList
.m_hImageList
!= NULL
);
232 if(!m_ImageList
.GetIconSize(cx
, cy
))
234 return ResizeClient(cx
, cy
);
238 void DoPaint(CDCHandle dc
)
240 ATLASSERT(m_ImageList
.m_hImageList
!= NULL
); // image list must be set
241 ATLASSERT(m_nImage
[0] != -1); // main bitmap must be set
243 // set bitmap according to the current button state
245 bool bHover
= IsHoverMode();
246 if(!IsWindowEnabled())
247 nImage
= m_nImage
[_nImageDisabled
];
248 else if(m_fPressed
== 1)
249 nImage
= m_nImage
[_nImagePushed
];
250 else if((!bHover
&& m_fFocus
== 1) || (bHover
&& m_fMouseOver
== 1))
251 nImage
= m_nImage
[_nImageFocusOrHover
];
252 if(nImage
== -1) // not there, use default one
253 nImage
= m_nImage
[_nImageNormal
];
255 // draw the button image
257 if((m_fPressed
== 1) && ((m_dwExtendedStyle
& (BMPBTN_AUTO3D_SINGLE
| BMPBTN_AUTO3D_DOUBLE
)) != 0) && (m_nImage
[_nImagePushed
] == -1))
259 m_ImageList
.Draw(dc
, nImage
, xyPos
, xyPos
, ILD_NORMAL
);
261 // draw 3D border if required
262 if((m_dwExtendedStyle
& (BMPBTN_AUTO3D_SINGLE
| BMPBTN_AUTO3D_DOUBLE
)) != 0)
265 GetClientRect(&rect
);
268 dc
.DrawEdge(&rect
, ((m_dwExtendedStyle
& BMPBTN_AUTO3D_SINGLE
) != 0) ? BDR_SUNKENOUTER
: EDGE_SUNKEN
, BF_RECT
);
269 else if(!bHover
|| m_fMouseOver
== 1)
270 dc
.DrawEdge(&rect
, ((m_dwExtendedStyle
& BMPBTN_AUTO3D_SINGLE
) != 0) ? BDR_RAISEDINNER
: EDGE_RAISED
, BF_RECT
);
272 if(!bHover
&& m_fFocus
== 1)
274 ::InflateRect(&rect
, -2 * ::GetSystemMetrics(SM_CXEDGE
), -2 * ::GetSystemMetrics(SM_CYEDGE
));
275 dc
.DrawFocusRect(&rect
);
280 // Message map and handlers
281 BEGIN_MSG_MAP(CBitmapButtonImpl
)
282 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
283 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
284 MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST
, WM_MOUSELAST
, OnMouseMessage
)
285 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
286 MESSAGE_HANDLER(WM_PAINT
, OnPaint
)
287 MESSAGE_HANDLER(WM_PRINTCLIENT
, OnPaint
)
288 MESSAGE_HANDLER(WM_SETFOCUS
, OnFocus
)
289 MESSAGE_HANDLER(WM_KILLFOCUS
, OnFocus
)
290 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnLButtonDown
)
291 MESSAGE_HANDLER(WM_LBUTTONDBLCLK
, OnLButtonDblClk
)
292 MESSAGE_HANDLER(WM_LBUTTONUP
, OnLButtonUp
)
293 MESSAGE_HANDLER(WM_CAPTURECHANGED
, OnCaptureChanged
)
294 MESSAGE_HANDLER(WM_ENABLE
, OnEnable
)
295 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
296 MESSAGE_HANDLER(WM_MOUSELEAVE
, OnMouseLeave
)
297 MESSAGE_HANDLER(WM_KEYDOWN
, OnKeyDown
)
298 MESSAGE_HANDLER(WM_KEYUP
, OnKeyUp
)
299 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
300 MESSAGE_HANDLER(WM_UPDATEUISTATE
, OnUpdateUiState
)
303 LRESULT
OnCreate(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
310 LRESULT
OnDestroy(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
314 m_tip
.DestroyWindow();
321 LRESULT
OnMouseMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
323 MSG msg
= { m_hWnd
, uMsg
, wParam
, lParam
};
325 m_tip
.RelayEvent(&msg
);
330 LRESULT
OnEraseBackground(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
332 return 1; // no background needed
335 LRESULT
OnPaint(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
337 T
* pT
= static_cast<T
*>(this);
340 pT
->DoPaint((HDC
)wParam
);
345 pT
->DoPaint(dc
.m_hDC
);
350 LRESULT
OnFocus(UINT uMsg
, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
352 m_fFocus
= (uMsg
== WM_SETFOCUS
) ? 1 : 0;
359 LRESULT
OnLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
365 lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
366 if(::GetCapture() == m_hWnd
)
372 if((m_dwExtendedStyle
& BMPBTN_AUTOFIRE
) != 0)
376 if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY
, 0, &nDelay
, 0))
377 nElapse
+= nDelay
* 250; // all milli-seconds
378 SetTimer(ID_TIMER_FIRST
, nElapse
);
383 LRESULT
OnLButtonDblClk(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
387 lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
388 if(::GetCapture() != m_hWnd
)
399 LRESULT
OnLButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
402 bool bHover
= IsHoverMode();
404 lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
405 if(::GetCapture() == m_hWnd
)
407 if(bHover
&& m_fPressed
== 1)
408 ::SendMessage(GetParent(), WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED
), (LPARAM
)m_hWnd
);
414 LRESULT
OnCaptureChanged(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
426 LRESULT
OnEnable(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
434 LRESULT
OnMouseMove(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
436 if(::GetCapture() == m_hWnd
)
438 POINT ptCursor
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
439 ClientToScreen(&ptCursor
);
441 GetWindowRect(&rect
);
442 unsigned int uPressed
= ::PtInRect(&rect
, ptCursor
) ? 1 : 0;
443 if(m_fPressed
!= uPressed
)
445 m_fPressed
= uPressed
;
450 else if(IsHoverMode() && m_fMouseOver
== 0)
455 StartTrackMouseLeave();
461 LRESULT
OnMouseLeave(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
463 if(m_fMouseOver
== 1)
472 LRESULT
OnKeyDown(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
474 if(wParam
== VK_SPACE
&& IsHoverMode())
475 return 0; // ignore if in hover mode
476 if(wParam
== VK_SPACE
&& m_fPressed
== 0)
486 LRESULT
OnKeyUp(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
488 if(wParam
== VK_SPACE
&& IsHoverMode())
489 return 0; // ignore if in hover mode
490 if(wParam
== VK_SPACE
&& m_fPressed
== 1)
500 LRESULT
OnTimer(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
502 ATLASSERT((m_dwExtendedStyle
& BMPBTN_AUTOFIRE
) != 0);
503 switch(wParam
) // timer ID
506 KillTimer(ID_TIMER_FIRST
);
509 ::SendMessage(GetParent(), WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED
), (LPARAM
)m_hWnd
);
512 if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED
, 0, &nRepeat
, 0))
513 nElapse
= 10000 / (10 * nRepeat
+ 25); // milli-seconds, approximated
514 SetTimer(ID_TIMER_REPEAT
, nElapse
);
517 case ID_TIMER_REPEAT
:
519 ::SendMessage(GetParent(), WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED
), (LPARAM
)m_hWnd
);
520 else if(::GetCapture() != m_hWnd
)
521 KillTimer(ID_TIMER_REPEAT
);
523 default: // not our timer
529 LRESULT
OnUpdateUiState(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
531 // If the control is subclassed or superclassed, this message can cause
532 // repainting without WM_PAINT. We don't use this state, so just do nothing.
539 // We need this style to prevent Windows from painting the button
540 ModifyStyle(0, BS_OWNERDRAW
);
543 m_tip
.Create(m_hWnd
);
544 ATLASSERT(m_tip
.IsWindow());
545 if(m_tip
.IsWindow() && m_lpstrToolTipText
!= NULL
)
547 m_tip
.Activate(TRUE
);
548 m_tip
.AddTool(m_hWnd
, m_lpstrToolTipText
);
551 if(m_ImageList
.m_hImageList
!= NULL
&& (m_dwExtendedStyle
& BMPBTN_AUTOSIZE
) != 0)
555 BOOL
StartTrackMouseLeave()
557 TRACKMOUSEEVENT tme
= { 0 };
558 tme
.cbSize
= sizeof(tme
);
559 tme
.dwFlags
= TME_LEAVE
;
560 tme
.hwndTrack
= m_hWnd
;
561 return _TrackMouseEvent(&tme
);
564 bool IsHoverMode() const
566 return ((m_dwExtendedStyle
& BMPBTN_HOVER
) != 0);
571 class CBitmapButton
: public CBitmapButtonImpl
<CBitmapButton
>
574 DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName())
576 CBitmapButton(DWORD dwExtendedStyle
= BMPBTN_AUTOSIZE
, HIMAGELIST hImageList
= NULL
) :
577 CBitmapButtonImpl
<CBitmapButton
>(dwExtendedStyle
, hImageList
)
581 #endif // !_WIN32_WCE
584 ///////////////////////////////////////////////////////////////////////////////
585 // CCheckListCtrlView - list view control with check boxes
587 template <DWORD t_dwStyle
, DWORD t_dwExStyle
, DWORD t_dwExListViewStyle
>
588 class CCheckListViewCtrlImplTraits
591 static DWORD
GetWndStyle(DWORD dwStyle
)
593 return (dwStyle
== 0) ? t_dwStyle
: dwStyle
;
596 static DWORD
GetWndExStyle(DWORD dwExStyle
)
598 return (dwExStyle
== 0) ? t_dwExStyle
: dwExStyle
;
601 static DWORD
GetExtendedLVStyle()
603 return t_dwExListViewStyle
;
607 typedef CCheckListViewCtrlImplTraits
<WS_CHILD
| WS_VISIBLE
| LVS_REPORT
| LVS_SHOWSELALWAYS
, WS_EX_CLIENTEDGE
, LVS_EX_CHECKBOXES
| LVS_EX_FULLROWSELECT
> CCheckListViewCtrlTraits
;
609 template <class T
, class TBase
= CListViewCtrl
, class TWinTraits
= CCheckListViewCtrlTraits
>
610 class ATL_NO_VTABLE CCheckListViewCtrlImpl
: public ATL::CWindowImpl
<T
, TBase
, TWinTraits
>
613 DECLARE_WND_SUPERCLASS(NULL
, TBase::GetWndClassName())
616 static DWORD
GetExtendedLVStyle()
618 return TWinTraits::GetExtendedLVStyle();
622 BOOL
SubclassWindow(HWND hWnd
)
624 #if (_MSC_VER >= 1300)
625 BOOL bRet
= ATL::CWindowImplBaseT
< TBase
, TWinTraits
>::SubclassWindow(hWnd
);
626 #else // !(_MSC_VER >= 1300)
627 typedef ATL::CWindowImplBaseT
< TBase
, TWinTraits
> _baseClass
;
628 BOOL bRet
= _baseClass::SubclassWindow(hWnd
);
629 #endif // !(_MSC_VER >= 1300)
632 T
* pT
= static_cast<T
*>(this);
634 ATLASSERT((pT
->GetExtendedLVStyle() & LVS_EX_CHECKBOXES
) != 0);
635 SetExtendedListViewStyle(pT
->GetExtendedLVStyle());
640 void CheckSelectedItems(int nCurrItem
)
642 // first check if this item is selected
644 lvi
.iItem
= nCurrItem
;
646 lvi
.mask
= LVIF_STATE
;
647 lvi
.stateMask
= LVIS_SELECTED
;
649 // if item is not selected, don't do anything
650 if(!(lvi
.state
& LVIS_SELECTED
))
652 // new check state will be reverse of the current state,
653 BOOL bCheck
= !GetCheckState(nCurrItem
);
656 while((nItem
= GetNextItem(nOldItem
, LVNI_SELECTED
)) != -1)
658 if(nItem
!= nCurrItem
)
659 SetCheckState(nItem
, bCheck
);
665 BEGIN_MSG_MAP(CCheckListViewCtrlImpl
)
666 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
667 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnLButtonDown
)
668 MESSAGE_HANDLER(WM_LBUTTONDBLCLK
, OnLButtonDown
)
669 MESSAGE_HANDLER(WM_KEYDOWN
, OnKeyDown
)
672 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
674 // first let list view control initialize everything
675 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
676 T
* pT
= static_cast<T
*>(this);
678 ATLASSERT((pT
->GetExtendedLVStyle() & LVS_EX_CHECKBOXES
) != 0);
679 SetExtendedListViewStyle(pT
->GetExtendedLVStyle());
683 LRESULT
OnLButtonDown(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
685 POINT ptMsg
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
686 LVHITTESTINFO lvh
= { 0 };
688 if(HitTest(&lvh
) != -1 && lvh
.flags
== LVHT_ONITEMSTATEICON
&& ::GetKeyState(VK_CONTROL
) >= 0)
690 T
* pT
= static_cast<T
*>(this);
691 pT
->CheckSelectedItems(lvh
.iItem
);
697 LRESULT
OnKeyDown(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
699 if(wParam
== VK_SPACE
)
701 int nCurrItem
= GetNextItem(-1, LVNI_FOCUSED
);
702 if(nCurrItem
!= -1 && ::GetKeyState(VK_CONTROL
) >= 0)
704 T
* pT
= static_cast<T
*>(this);
705 pT
->CheckSelectedItems(nCurrItem
);
713 class CCheckListViewCtrl
: public CCheckListViewCtrlImpl
<CCheckListViewCtrl
>
716 DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName())
720 ///////////////////////////////////////////////////////////////////////////////
721 // CHyperLink - hyper link control implementation
723 #if (WINVER < 0x0500) && !defined(_WIN32_WCE)
724 __declspec(selectany
) struct
726 enum { cxWidth
= 32, cyHeight
= 32 };
729 unsigned char arrANDPlane
[cxWidth
* cyHeight
/ 8];
730 unsigned char arrXORPlane
[cxWidth
* cyHeight
/ 8];
731 } _AtlHyperLink_CursorData
=
735 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF,
736 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF,
737 0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF,
738 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF,
739 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF,
740 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
741 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
742 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
745 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
746 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00,
747 0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00,
748 0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00,
749 0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00,
750 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
755 #endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)
757 #define HLINK_UNDERLINED 0x00000000
758 #define HLINK_NOTUNDERLINED 0x00000001
759 #define HLINK_UNDERLINEHOVER 0x00000002
760 #define HLINK_COMMANDBUTTON 0x00000004
761 #define HLINK_NOTIFYBUTTON 0x0000000C
762 #define HLINK_USETAGS 0x00000010
763 #define HLINK_USETAGSBOLD 0x00000030
764 #define HLINK_NOTOOLTIP 0x00000040
767 // - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned
768 // - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored
770 template <class T
, class TBase
= ATL::CWindow
, class TWinTraits
= ATL::CControlWinTraits
>
771 class ATL_NO_VTABLE CHyperLinkImpl
: public ATL::CWindowImpl
< T
, TBase
, TWinTraits
>
775 LPTSTR m_lpstrHyperLink
;
784 #endif // !_WIN32_WCE
787 COLORREF m_clrVisited
;
789 DWORD m_dwExtendedStyle
; // Hyper Link specific extended styles
791 bool m_bPaintLabel
:1;
794 bool m_bInternalLinkFont
:1;
797 // Constructor/Destructor
798 CHyperLinkImpl(DWORD dwExtendedStyle
= HLINK_UNDERLINED
) :
799 m_lpstrLabel(NULL
), m_lpstrHyperLink(NULL
),
800 m_hCursor(NULL
), m_hFont(NULL
), m_hFontNormal(NULL
),
801 m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128)),
802 m_dwExtendedStyle(dwExtendedStyle
),
803 m_bPaintLabel(true), m_bVisited(false),
804 m_bHover(false), m_bInternalLinkFont(false)
806 ::SetRectEmpty(&m_rcLink
);
811 delete [] m_lpstrLabel
;
812 delete [] m_lpstrHyperLink
;
813 if(m_bInternalLinkFont
&& m_hFont
!= NULL
)
814 ::DeleteObject(m_hFont
);
815 #if (WINVER < 0x0500) && !defined(_WIN32_WCE)
816 // It was created, not loaded, so we have to destroy it
817 if(m_hCursor
!= NULL
)
818 ::DestroyCursor(m_hCursor
);
819 #endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)
823 DWORD
GetHyperLinkExtendedStyle() const
825 return m_dwExtendedStyle
;
828 DWORD
SetHyperLinkExtendedStyle(DWORD dwExtendedStyle
, DWORD dwMask
= 0)
830 DWORD dwPrevStyle
= m_dwExtendedStyle
;
832 m_dwExtendedStyle
= dwExtendedStyle
;
834 m_dwExtendedStyle
= (m_dwExtendedStyle
& ~dwMask
) | (dwExtendedStyle
& dwMask
);
838 bool GetLabel(LPTSTR lpstrBuffer
, int nLength
) const
840 if(m_lpstrLabel
== NULL
)
842 ATLASSERT(lpstrBuffer
!= NULL
);
843 if(nLength
<= lstrlen(m_lpstrLabel
))
846 SecureHelper::strcpy_x(lpstrBuffer
, nLength
, m_lpstrLabel
);
851 bool SetLabel(LPCTSTR lpstrLabel
)
853 delete [] m_lpstrLabel
;
855 int cchLen
= lstrlen(lpstrLabel
) + 1;
856 ATLTRY(m_lpstrLabel
= new TCHAR
[cchLen
]);
857 if(m_lpstrLabel
== NULL
)
860 SecureHelper::strcpy_x(m_lpstrLabel
, cchLen
, lpstrLabel
);
861 T
* pT
= static_cast<T
*>(this);
865 SetWindowText(lpstrLabel
); // Set this for accessibility
870 bool GetHyperLink(LPTSTR lpstrBuffer
, int nLength
) const
872 if(m_lpstrHyperLink
== NULL
)
874 ATLASSERT(lpstrBuffer
!= NULL
);
875 if(nLength
<= lstrlen(m_lpstrHyperLink
))
878 SecureHelper::strcpy_x(lpstrBuffer
, nLength
, m_lpstrHyperLink
);
883 bool SetHyperLink(LPCTSTR lpstrLink
)
885 delete [] m_lpstrHyperLink
;
886 m_lpstrHyperLink
= NULL
;
887 int cchLen
= lstrlen(lpstrLink
) + 1;
888 ATLTRY(m_lpstrHyperLink
= new TCHAR
[cchLen
]);
889 if(m_lpstrHyperLink
== NULL
)
892 SecureHelper::strcpy_x(m_lpstrHyperLink
, cchLen
, lpstrLink
);
893 if(m_lpstrLabel
== NULL
)
895 T
* pT
= static_cast<T
*>(this);
901 m_tip
.Activate(TRUE
);
902 m_tip
.AddTool(m_hWnd
, m_lpstrHyperLink
, &m_rcLink
, 1);
904 #endif // !_WIN32_WCE
908 HFONT
GetLinkFont() const
913 void SetLinkFont(HFONT hFont
)
915 if(m_bInternalLinkFont
&& m_hFont
!= NULL
)
917 ::DeleteObject(m_hFont
);
918 m_bInternalLinkFont
= false;
923 int GetIdealHeight() const
925 ATLASSERT(::IsWindow(m_hWnd
));
926 if(m_lpstrLabel
== NULL
&& m_lpstrHyperLink
== NULL
)
931 CClientDC
dc(m_hWnd
);
933 GetClientRect(&rect
);
934 HFONT hFontOld
= dc
.SelectFont(m_hFontNormal
);
936 dc
.DrawText(_T("NS"), -1, &rcText
, DT_LEFT
| DT_WORDBREAK
| DT_CALCRECT
);
937 dc
.SelectFont(m_hFont
);
939 dc
.DrawText(_T("NS"), -1, &rcLink
, DT_LEFT
| DT_WORDBREAK
| DT_CALCRECT
);
940 dc
.SelectFont(hFontOld
);
941 return __max(rcText
.bottom
- rcText
.top
, rcLink
.bottom
- rcLink
.top
);
944 bool GetIdealSize(SIZE
& size
) const
947 bool bRet
= GetIdealSize(cx
, cy
);
956 bool GetIdealSize(int& cx
, int& cy
) const
958 ATLASSERT(::IsWindow(m_hWnd
));
959 if(m_lpstrLabel
== NULL
&& m_lpstrHyperLink
== NULL
)
964 CClientDC
dc(m_hWnd
);
965 RECT rcClient
= { 0 };
966 GetClientRect(&rcClient
);
967 RECT rcAll
= rcClient
;
971 // find tags and label parts
972 LPTSTR lpstrLeft
= NULL
;
974 LPTSTR lpstrLink
= NULL
;
976 LPTSTR lpstrRight
= NULL
;
979 const T
* pT
= static_cast<const T
*>(this);
980 pT
->CalcLabelParts(lpstrLeft
, cchLeft
, lpstrLink
, cchLink
, lpstrRight
, cchRight
);
982 // get label part rects
983 HFONT hFontOld
= dc
.SelectFont(m_hFontNormal
);
984 RECT rcLeft
= rcClient
;
985 dc
.DrawText(lpstrLeft
, cchLeft
, &rcLeft
, DT_LEFT
| DT_WORDBREAK
| DT_CALCRECT
);
987 dc
.SelectFont(m_hFont
);
988 RECT rcLink
= { rcLeft
.right
, rcLeft
.top
, rcClient
.right
, rcClient
.bottom
};
989 dc
.DrawText(lpstrLink
, cchLink
, &rcLink
, DT_LEFT
| DT_WORDBREAK
| DT_CALCRECT
);
991 dc
.SelectFont(m_hFontNormal
);
992 RECT rcRight
= { rcLink
.right
, rcLink
.top
, rcClient
.right
, rcClient
.bottom
};
993 dc
.DrawText(lpstrRight
, cchRight
, &rcRight
, DT_LEFT
| DT_WORDBREAK
| DT_CALCRECT
);
995 dc
.SelectFont(hFontOld
);
997 int cyMax
= __max(rcLeft
.bottom
, max(rcLink
.bottom
, rcRight
.bottom
));
998 ::SetRect(&rcAll
, rcLeft
.left
, rcLeft
.top
, rcRight
.right
, cyMax
);
1002 HFONT hOldFont
= NULL
;
1004 hOldFont
= dc
.SelectFont(m_hFont
);
1005 LPTSTR lpstrText
= (m_lpstrLabel
!= NULL
) ? m_lpstrLabel
: m_lpstrHyperLink
;
1006 DWORD dwStyle
= GetStyle();
1007 int nDrawStyle
= DT_LEFT
;
1008 if (dwStyle
& SS_CENTER
)
1009 nDrawStyle
= DT_CENTER
;
1010 else if (dwStyle
& SS_RIGHT
)
1011 nDrawStyle
= DT_RIGHT
;
1012 dc
.DrawText(lpstrText
, -1, &rcAll
, nDrawStyle
| DT_WORDBREAK
| DT_CALCRECT
);
1014 dc
.SelectFont(hOldFont
);
1015 if (dwStyle
& SS_CENTER
)
1017 int dx
= (rcClient
.right
- rcAll
.right
) / 2;
1018 ::OffsetRect(&rcAll
, dx
, 0);
1020 else if (dwStyle
& SS_RIGHT
)
1022 int dx
= rcClient
.right
- rcAll
.right
;
1023 ::OffsetRect(&rcAll
, dx
, 0);
1027 cx
= rcAll
.right
- rcAll
.left
;
1028 cy
= rcAll
.bottom
- rcAll
.top
;
1033 // for command buttons only
1034 bool GetToolTipText(LPTSTR lpstrBuffer
, int nLength
) const
1036 ATLASSERT(IsCommandButton());
1037 return GetHyperLink(lpstrBuffer
, nLength
);
1040 bool SetToolTipText(LPCTSTR lpstrToolTipText
)
1042 ATLASSERT(IsCommandButton());
1043 return SetHyperLink(lpstrToolTipText
);
1047 BOOL
SubclassWindow(HWND hWnd
)
1049 ATLASSERT(m_hWnd
== NULL
);
1050 ATLASSERT(::IsWindow(hWnd
));
1051 #if (_MSC_VER >= 1300)
1052 BOOL bRet
= ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::SubclassWindow(hWnd
);
1053 #else // !(_MSC_VER >= 1300)
1054 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
1055 BOOL bRet
= _baseClass::SubclassWindow(hWnd
);
1056 #endif // !(_MSC_VER >= 1300)
1059 T
* pT
= static_cast<T
*>(this);
1067 ATLASSERT(::IsWindow(m_hWnd
));
1069 if(IsNotifyButton())
1071 NMHDR nmhdr
= { m_hWnd
, GetDlgCtrlID(), NM_CLICK
};
1072 ::SendMessage(GetParent(), WM_NOTIFY
, GetDlgCtrlID(), (LPARAM
)&nmhdr
);
1074 else if(IsCommandButton())
1076 ::SendMessage(GetParent(), WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED
), (LPARAM
)m_hWnd
);
1080 ATLASSERT(m_lpstrHyperLink
!= NULL
);
1082 DWORD_PTR dwRet
= (DWORD_PTR
)::ShellExecute(0, _T("open"), m_lpstrHyperLink
, 0, 0, SW_SHOWNORMAL
);
1083 bRet
= (dwRet
> 32);
1084 #else // CE specific
1085 SHELLEXECUTEINFO shExeInfo
= { sizeof(SHELLEXECUTEINFO
), 0, 0, L
"open", m_lpstrHyperLink
, 0, 0, SW_SHOWNORMAL
, 0, 0, 0, 0, 0, 0, 0 };
1086 ::ShellExecuteEx(&shExeInfo
);
1087 DWORD_PTR dwRet
= (DWORD_PTR
)shExeInfo
.hInstApp
;
1088 bRet
= (dwRet
== 0) || (dwRet
> 32);
1089 #endif // _WIN32_WCE
1100 // Message map and handlers
1101 BEGIN_MSG_MAP(CHyperLinkImpl
)
1102 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
1104 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
1105 MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST
, WM_MOUSELAST
, OnMouseMessage
)
1106 #endif // !_WIN32_WCE
1107 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
1108 MESSAGE_HANDLER(WM_PAINT
, OnPaint
)
1110 MESSAGE_HANDLER(WM_PRINTCLIENT
, OnPaint
)
1111 #endif // !_WIN32_WCE
1112 MESSAGE_HANDLER(WM_SETFOCUS
, OnFocus
)
1113 MESSAGE_HANDLER(WM_KILLFOCUS
, OnFocus
)
1114 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
1116 MESSAGE_HANDLER(WM_MOUSELEAVE
, OnMouseLeave
)
1117 #endif // !_WIN32_WCE
1118 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnLButtonDown
)
1119 MESSAGE_HANDLER(WM_LBUTTONUP
, OnLButtonUp
)
1120 MESSAGE_HANDLER(WM_CHAR
, OnChar
)
1121 MESSAGE_HANDLER(WM_GETDLGCODE
, OnGetDlgCode
)
1122 MESSAGE_HANDLER(WM_SETCURSOR
, OnSetCursor
)
1123 MESSAGE_HANDLER(WM_ENABLE
, OnEnable
)
1124 MESSAGE_HANDLER(WM_GETFONT
, OnGetFont
)
1125 MESSAGE_HANDLER(WM_SETFONT
, OnSetFont
)
1126 MESSAGE_HANDLER(WM_UPDATEUISTATE
, OnUpdateUiState
)
1127 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
1130 LRESULT
OnCreate(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1132 T
* pT
= static_cast<T
*>(this);
1138 LRESULT
OnDestroy(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1140 if(m_tip
.IsWindow())
1142 m_tip
.DestroyWindow();
1143 m_tip
.m_hWnd
= NULL
;
1149 LRESULT
OnMouseMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1151 MSG msg
= { m_hWnd
, uMsg
, wParam
, lParam
};
1152 if(m_tip
.IsWindow() && IsUsingToolTip())
1153 m_tip
.RelayEvent(&msg
);
1157 #endif // !_WIN32_WCE
1159 LRESULT
OnEraseBackground(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1161 return 1; // no background painting needed (we do it all during WM_PAINT)
1164 LRESULT
OnPaint(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1172 T
* pT
= static_cast<T
*>(this);
1175 pT
->DoEraseBackground((HDC
)wParam
);
1176 pT
->DoPaint((HDC
)wParam
);
1180 CPaintDC
dc(m_hWnd
);
1181 pT
->DoEraseBackground(dc
.m_hDC
);
1182 pT
->DoPaint(dc
.m_hDC
);
1188 LRESULT
OnFocus(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1197 LRESULT
OnMouseMove(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
1199 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
1200 if((m_lpstrHyperLink
!= NULL
|| IsCommandButton()) && ::PtInRect(&m_rcLink
, pt
))
1202 ::SetCursor(m_hCursor
);
1203 if(IsUnderlineHover())
1208 InvalidateRect(&m_rcLink
);
1211 StartTrackMouseLeave();
1212 #endif // !_WIN32_WCE
1218 if(IsUnderlineHover())
1223 InvalidateRect(&m_rcLink
);
1233 LRESULT
OnMouseLeave(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1235 if(IsUnderlineHover() && m_bHover
)
1238 InvalidateRect(&m_rcLink
);
1243 #endif // !_WIN32_WCE
1245 LRESULT
OnLButtonDown(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& /*bHandled*/)
1247 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
1248 if(::PtInRect(&m_rcLink
, pt
))
1256 LRESULT
OnLButtonUp(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& /*bHandled*/)
1258 if(GetCapture() == m_hWnd
)
1261 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
1262 if(::PtInRect(&m_rcLink
, pt
))
1264 T
* pT
= static_cast<T
*>(this);
1271 LRESULT
OnChar(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1273 if(wParam
== VK_RETURN
|| wParam
== VK_SPACE
)
1275 T
* pT
= static_cast<T
*>(this);
1281 LRESULT
OnGetDlgCode(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1283 return DLGC_WANTCHARS
;
1286 LRESULT
OnSetCursor(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1288 POINT pt
= { 0, 0 };
1290 ScreenToClient(&pt
);
1291 if((m_lpstrHyperLink
!= NULL
|| IsCommandButton()) && ::PtInRect(&m_rcLink
, pt
))
1299 LRESULT
OnEnable(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1306 LRESULT
OnGetFont(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1308 return (LRESULT
)m_hFontNormal
;
1311 LRESULT
OnSetFont(UINT
/*uMsg*/, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
1313 m_hFontNormal
= (HFONT
)wParam
;
1322 LRESULT
OnUpdateUiState(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1324 // If the control is subclassed or superclassed, this message can cause
1325 // repainting without WM_PAINT. We don't use this state, so just do nothing.
1329 LRESULT
OnSize(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1331 T
* pT
= static_cast<T
*>(this);
1332 pT
->CalcLabelRect();
1340 ATLASSERT(::IsWindow(m_hWnd
));
1342 // Check if we should paint a label
1343 const int cchBuff
= 8;
1344 TCHAR szBuffer
[cchBuff
] = { 0 };
1345 if(::GetClassName(m_hWnd
, szBuffer
, cchBuff
))
1347 if(lstrcmpi(szBuffer
, _T("static")) == 0)
1349 ModifyStyle(0, SS_NOTIFY
); // we need this
1350 DWORD dwStyle
= GetStyle() & 0x000000FF;
1352 if(dwStyle
== SS_ICON
|| dwStyle
== SS_BLACKRECT
|| dwStyle
== SS_GRAYRECT
||
1353 dwStyle
== SS_WHITERECT
|| dwStyle
== SS_BLACKFRAME
|| dwStyle
== SS_GRAYFRAME
||
1354 dwStyle
== SS_WHITEFRAME
|| dwStyle
== SS_OWNERDRAW
||
1355 dwStyle
== SS_BITMAP
|| dwStyle
== SS_ENHMETAFILE
)
1356 #else // CE specific
1357 if(dwStyle
== SS_ICON
|| dwStyle
== SS_BITMAP
)
1358 #endif // _WIN32_WCE
1359 m_bPaintLabel
= false;
1363 // create or load a cursor
1364 #if (WINVER >= 0x0500) || defined(_WIN32_WCE)
1365 m_hCursor
= ::LoadCursor(NULL
, IDC_HAND
);
1367 m_hCursor
= ::CreateCursor(ModuleHelper::GetModuleInstance(), _AtlHyperLink_CursorData
.xHotSpot
, _AtlHyperLink_CursorData
.yHotSpot
, _AtlHyperLink_CursorData
.cxWidth
, _AtlHyperLink_CursorData
.cyHeight
, _AtlHyperLink_CursorData
.arrANDPlane
, _AtlHyperLink_CursorData
.arrXORPlane
);
1369 ATLASSERT(m_hCursor
!= NULL
);
1374 ATL::CWindow wnd
= GetParent();
1375 m_hFontNormal
= wnd
.GetFont();
1376 if(m_hFontNormal
== NULL
)
1377 m_hFontNormal
= (HFONT
)::GetStockObject(SYSTEM_FONT
);
1378 if(m_hFontNormal
!= NULL
&& m_hFont
== NULL
)
1381 CFontHandle font
= m_hFontNormal
;
1382 font
.GetLogFont(&lf
);
1383 if(IsUsingTagsBold())
1384 lf
.lfWeight
= FW_BOLD
;
1385 else if(!IsNotUnderlined())
1386 lf
.lfUnderline
= TRUE
;
1387 m_hFont
= ::CreateFontIndirect(&lf
);
1388 m_bInternalLinkFont
= true;
1389 ATLASSERT(m_hFont
!= NULL
);
1394 // create a tool tip
1395 m_tip
.Create(m_hWnd
);
1396 ATLASSERT(m_tip
.IsWindow());
1397 #endif // !_WIN32_WCE
1399 // set label (defaults to window text)
1400 if(m_lpstrLabel
== NULL
)
1402 int nLen
= GetWindowTextLength();
1405 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
1406 LPTSTR lpstrText
= buff
.Allocate(nLen
+ 1);
1407 ATLASSERT(lpstrText
!= NULL
);
1408 if((lpstrText
!= NULL
) && (GetWindowText(lpstrText
, nLen
+ 1) > 0))
1409 SetLabel(lpstrText
);
1413 T
* pT
= static_cast<T
*>(this);
1414 pT
->CalcLabelRect();
1416 // set hyperlink (defaults to label), or just activate tool tip if already set
1417 if(m_lpstrHyperLink
== NULL
&& !IsCommandButton())
1419 if(m_lpstrLabel
!= NULL
)
1420 SetHyperLink(m_lpstrLabel
);
1425 m_tip
.Activate(TRUE
);
1426 m_tip
.AddTool(m_hWnd
, m_lpstrHyperLink
, &m_rcLink
, 1);
1428 #endif // !_WIN32_WCE
1434 LONG lRet
= rk
.Open(HKEY_CURRENT_USER
, _T("Software\\Microsoft\\Internet Explorer\\Settings"));
1437 const int cchValue
= 12;
1438 TCHAR szValue
[cchValue
] = { 0 };
1439 #if (_ATL_VER >= 0x0700)
1440 ULONG ulCount
= cchValue
;
1441 lRet
= rk
.QueryStringValue(_T("Anchor Color"), szValue
, &ulCount
);
1443 DWORD dwCount
= cchValue
* sizeof(TCHAR
);
1444 lRet
= rk
.QueryValue(szValue
, _T("Anchor Color"), &dwCount
);
1448 COLORREF clr
= pT
->_ParseColorString(szValue
);
1449 ATLASSERT(clr
!= CLR_INVALID
);
1450 if(clr
!= CLR_INVALID
)
1454 #if (_ATL_VER >= 0x0700)
1456 lRet
= rk
.QueryStringValue(_T("Anchor Color Visited"), szValue
, &ulCount
);
1458 dwCount
= cchValue
* sizeof(TCHAR
);
1459 lRet
= rk
.QueryValue(szValue
, _T("Anchor Color Visited"), &dwCount
);
1463 COLORREF clr
= pT
->_ParseColorString(szValue
);
1464 ATLASSERT(clr
!= CLR_INVALID
);
1465 if(clr
!= CLR_INVALID
)
1472 static COLORREF
_ParseColorString(LPTSTR lpstr
)
1474 int c
[3] = { -1, -1, -1 };
1476 for(int i
= 0; i
< 2; i
++)
1478 for(p
= lpstr
; *p
!= _T('\0'); p
= ::CharNext(p
))
1483 c
[i
] = T::_xttoi(lpstr
);
1491 if(*lpstr
== _T('\0'))
1493 c
[2] = T::_xttoi(lpstr
);
1495 return RGB(c
[0], c
[1], c
[2]);
1498 bool CalcLabelRect()
1500 if(!::IsWindow(m_hWnd
))
1502 if(m_lpstrLabel
== NULL
&& m_lpstrHyperLink
== NULL
)
1505 CClientDC
dc(m_hWnd
);
1506 RECT rcClient
= { 0 };
1507 GetClientRect(&rcClient
);
1508 m_rcLink
= rcClient
;
1514 // find tags and label parts
1515 LPTSTR lpstrLeft
= NULL
;
1517 LPTSTR lpstrLink
= NULL
;
1519 LPTSTR lpstrRight
= NULL
;
1522 T
* pT
= static_cast<T
*>(this);
1523 pT
->CalcLabelParts(lpstrLeft
, cchLeft
, lpstrLink
, cchLink
, lpstrRight
, cchRight
);
1524 ATLASSERT(lpstrLink
!= NULL
);
1525 ATLASSERT(cchLink
> 0);
1527 // get label part rects
1528 HFONT hFontOld
= dc
.SelectFont(m_hFontNormal
);
1530 RECT rcLeft
= rcClient
;
1531 if(lpstrLeft
!= NULL
)
1532 dc
.DrawText(lpstrLeft
, cchLeft
, &rcLeft
, DT_LEFT
| DT_WORDBREAK
| DT_CALCRECT
);
1534 dc
.SelectFont(m_hFont
);
1535 RECT rcLink
= rcClient
;
1536 if(lpstrLeft
!= NULL
)
1537 rcLink
.left
= rcLeft
.right
;
1538 dc
.DrawText(lpstrLink
, cchLink
, &rcLink
, DT_LEFT
| DT_WORDBREAK
| DT_CALCRECT
);
1540 dc
.SelectFont(hFontOld
);
1546 HFONT hOldFont
= NULL
;
1548 hOldFont
= dc
.SelectFont(m_hFont
);
1549 LPTSTR lpstrText
= (m_lpstrLabel
!= NULL
) ? m_lpstrLabel
: m_lpstrHyperLink
;
1550 DWORD dwStyle
= GetStyle();
1551 int nDrawStyle
= DT_LEFT
;
1552 if (dwStyle
& SS_CENTER
)
1553 nDrawStyle
= DT_CENTER
;
1554 else if (dwStyle
& SS_RIGHT
)
1555 nDrawStyle
= DT_RIGHT
;
1556 dc
.DrawText(lpstrText
, -1, &m_rcLink
, nDrawStyle
| DT_WORDBREAK
| DT_CALCRECT
);
1558 dc
.SelectFont(hOldFont
);
1559 if (dwStyle
& SS_CENTER
)
1561 int dx
= (rcClient
.right
- m_rcLink
.right
) / 2;
1562 ::OffsetRect(&m_rcLink
, dx
, 0);
1564 else if (dwStyle
& SS_RIGHT
)
1566 int dx
= rcClient
.right
- m_rcLink
.right
;
1567 ::OffsetRect(&m_rcLink
, dx
, 0);
1574 void CalcLabelParts(LPTSTR
& lpstrLeft
, int& cchLeft
, LPTSTR
& lpstrLink
, int& cchLink
, LPTSTR
& lpstrRight
, int& cchRight
) const
1583 LPTSTR lpstrText
= (m_lpstrLabel
!= NULL
) ? m_lpstrLabel
: m_lpstrHyperLink
;
1584 int cchText
= lstrlen(lpstrText
);
1585 bool bOutsideLink
= true;
1586 for(int i
= 0; i
< cchText
; i
++)
1588 if(lpstrText
[i
] != _T('<'))
1593 if(::CompareString(LOCALE_USER_DEFAULT
, NORM_IGNORECASE
, &lpstrText
[i
], 3, _T("<A>"), 3) == CSTR_EQUAL
)
1597 lpstrLeft
= lpstrText
;
1600 lpstrLink
= &lpstrText
[i
+ 3];
1601 bOutsideLink
= false;
1606 if(::CompareString(LOCALE_USER_DEFAULT
, NORM_IGNORECASE
, &lpstrText
[i
], 4, _T("</A>"), 4) == CSTR_EQUAL
)
1608 cchLink
= i
- 3 - cchLeft
;
1609 if(lpstrText
[i
+ 4] != 0)
1611 lpstrRight
= &lpstrText
[i
+ 4];
1612 cchRight
= cchText
- (i
+ 4);
1621 void DoEraseBackground(CDCHandle dc
)
1623 HBRUSH hBrush
= (HBRUSH
)::SendMessage(GetParent(), WM_CTLCOLORSTATIC
, (WPARAM
)dc
.m_hDC
, (LPARAM
)m_hWnd
);
1627 GetClientRect(&rect
);
1628 dc
.FillRect(&rect
, hBrush
);
1632 void DoPaint(CDCHandle dc
)
1636 // find tags and label parts
1637 LPTSTR lpstrLeft
= NULL
;
1639 LPTSTR lpstrLink
= NULL
;
1641 LPTSTR lpstrRight
= NULL
;
1644 T
* pT
= static_cast<T
*>(this);
1645 pT
->CalcLabelParts(lpstrLeft
, cchLeft
, lpstrLink
, cchLink
, lpstrRight
, cchRight
);
1647 // get label part rects
1648 RECT rcClient
= { 0 };
1649 GetClientRect(&rcClient
);
1651 dc
.SetBkMode(TRANSPARENT
);
1652 HFONT hFontOld
= dc
.SelectFont(m_hFontNormal
);
1654 if(lpstrLeft
!= NULL
)
1655 dc
.DrawText(lpstrLeft
, cchLeft
, &rcClient
, DT_LEFT
| DT_WORDBREAK
);
1657 COLORREF clrOld
= dc
.SetTextColor(IsWindowEnabled() ? (m_bVisited
? m_clrVisited
: m_clrLink
) : (::GetSysColor(COLOR_GRAYTEXT
)));
1658 if(m_hFont
!= NULL
&& (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover
)))
1659 dc
.SelectFont(m_hFont
);
1661 dc
.SelectFont(m_hFontNormal
);
1663 dc
.DrawText(lpstrLink
, cchLink
, &m_rcLink
, DT_LEFT
| DT_WORDBREAK
);
1665 dc
.SetTextColor(clrOld
);
1666 dc
.SelectFont(m_hFontNormal
);
1667 if(lpstrRight
!= NULL
)
1669 RECT rcRight
= { m_rcLink
.right
, m_rcLink
.top
, rcClient
.right
, rcClient
.bottom
};
1670 dc
.DrawText(lpstrRight
, cchRight
, &rcRight
, DT_LEFT
| DT_WORDBREAK
);
1673 if(GetFocus() == m_hWnd
)
1674 dc
.DrawFocusRect(&m_rcLink
);
1676 dc
.SelectFont(hFontOld
);
1680 dc
.SetBkMode(TRANSPARENT
);
1681 COLORREF clrOld
= dc
.SetTextColor(IsWindowEnabled() ? (m_bVisited
? m_clrVisited
: m_clrLink
) : (::GetSysColor(COLOR_GRAYTEXT
)));
1683 HFONT hFontOld
= NULL
;
1684 if(m_hFont
!= NULL
&& (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover
)))
1685 hFontOld
= dc
.SelectFont(m_hFont
);
1687 hFontOld
= dc
.SelectFont(m_hFontNormal
);
1689 LPTSTR lpstrText
= (m_lpstrLabel
!= NULL
) ? m_lpstrLabel
: m_lpstrHyperLink
;
1691 DWORD dwStyle
= GetStyle();
1692 int nDrawStyle
= DT_LEFT
;
1693 if (dwStyle
& SS_CENTER
)
1694 nDrawStyle
= DT_CENTER
;
1695 else if (dwStyle
& SS_RIGHT
)
1696 nDrawStyle
= DT_RIGHT
;
1698 dc
.DrawText(lpstrText
, -1, &m_rcLink
, nDrawStyle
| DT_WORDBREAK
);
1700 if(GetFocus() == m_hWnd
)
1701 dc
.DrawFocusRect(&m_rcLink
);
1703 dc
.SetTextColor(clrOld
);
1704 dc
.SelectFont(hFontOld
);
1709 BOOL
StartTrackMouseLeave()
1711 TRACKMOUSEEVENT tme
= { 0 };
1712 tme
.cbSize
= sizeof(tme
);
1713 tme
.dwFlags
= TME_LEAVE
;
1714 tme
.hwndTrack
= m_hWnd
;
1715 return _TrackMouseEvent(&tme
);
1717 #endif // !_WIN32_WCE
1719 // Implementation helpers
1720 bool IsUnderlined() const
1722 return ((m_dwExtendedStyle
& (HLINK_NOTUNDERLINED
| HLINK_UNDERLINEHOVER
)) == 0);
1725 bool IsNotUnderlined() const
1727 return ((m_dwExtendedStyle
& HLINK_NOTUNDERLINED
) != 0);
1730 bool IsUnderlineHover() const
1732 return ((m_dwExtendedStyle
& HLINK_UNDERLINEHOVER
) != 0);
1735 bool IsCommandButton() const
1737 return ((m_dwExtendedStyle
& HLINK_COMMANDBUTTON
) != 0);
1740 bool IsNotifyButton() const
1742 return ((m_dwExtendedStyle
& HLINK_NOTIFYBUTTON
) == HLINK_NOTIFYBUTTON
);
1745 bool IsUsingTags() const
1747 return ((m_dwExtendedStyle
& HLINK_USETAGS
) != 0);
1750 bool IsUsingTagsBold() const
1752 return ((m_dwExtendedStyle
& HLINK_USETAGSBOLD
) == HLINK_USETAGSBOLD
);
1755 bool IsUsingToolTip() const
1757 return ((m_dwExtendedStyle
& HLINK_NOTOOLTIP
) == 0);
1760 static int _xttoi(const TCHAR
* nptr
)
1762 #ifndef _ATL_MIN_CRT
1764 #else // _ATL_MIN_CRT
1765 while(*nptr
== _T(' ')) // skip spaces
1768 int c
= (int)(_TUCHAR
)*nptr
++;
1769 int sign
= c
; // save sign indication
1770 if (c
== _T('-') || c
== _T('+'))
1771 c
= (int)(_TUCHAR
)*nptr
++; // skip sign
1774 while((TCHAR
)c
>= _T('0') && (TCHAR
)c
<= _T('9'))
1776 total
= 10 * total
+ ((TCHAR
)c
- _T('0')); // accumulate digit
1777 c
= (int)(_TUCHAR
)*nptr
++; // get next char
1780 // return result, negated if necessary
1781 return ((TCHAR
)sign
!= _T('-')) ? total
: -total
;
1782 #endif // _ATL_MIN_CRT
1787 class CHyperLink
: public CHyperLinkImpl
<CHyperLink
>
1790 DECLARE_WND_CLASS(_T("WTL_HyperLink"))
1794 ///////////////////////////////////////////////////////////////////////////////
1795 // CWaitCursor - displays a wait cursor
1801 HCURSOR m_hWaitCursor
;
1802 HCURSOR m_hOldCursor
;
1805 // Constructor/destructor
1806 CWaitCursor(bool bSet
= true, LPCTSTR lpstrCursor
= IDC_WAIT
, bool bSys
= true) : m_hOldCursor(NULL
), m_bInUse(false)
1808 HINSTANCE hInstance
= bSys
? NULL
: ModuleHelper::GetResourceInstance();
1809 m_hWaitCursor
= ::LoadCursor(hInstance
, lpstrCursor
);
1810 ATLASSERT(m_hWaitCursor
!= NULL
);
1826 m_hOldCursor
= ::SetCursor(m_hWaitCursor
);
1835 ::SetCursor(m_hOldCursor
);
1842 ///////////////////////////////////////////////////////////////////////////////
1843 // CCustomWaitCursor - for custom and animated cursors
1845 class CCustomWaitCursor
: public CWaitCursor
1848 // Constructor/destructor
1849 CCustomWaitCursor(ATL::_U_STRINGorID cursor
, bool bSet
= true, HINSTANCE hInstance
= NULL
) :
1850 CWaitCursor(false, IDC_WAIT
, true)
1852 if(hInstance
== NULL
)
1853 hInstance
= ModuleHelper::GetResourceInstance();
1854 m_hWaitCursor
= (HCURSOR
)::LoadImage(hInstance
, cursor
.m_lpstr
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
);
1860 ~CCustomWaitCursor()
1863 #if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))
1864 ::DestroyCursor(m_hWaitCursor
);
1865 #endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))
1870 ///////////////////////////////////////////////////////////////////////////////
1871 // CMultiPaneStatusBarCtrl - Status Bar with multiple panes
1873 template <class T
, class TBase
= CStatusBarCtrl
>
1874 class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl
: public ATL::CWindowImpl
< T
, TBase
>
1877 DECLARE_WND_SUPERCLASS(NULL
, TBase::GetWndClassName())
1880 enum { m_cxPaneMargin
= 3 };
1885 // Constructor/destructor
1886 CMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL
)
1889 ~CMultiPaneStatusBarCtrlImpl()
1895 HWND
Create(HWND hWndParent
, LPCTSTR lpstrText
, DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| SBARS_SIZEGRIP
, UINT nID
= ATL_IDW_STATUS_BAR
)
1897 #if (_MSC_VER >= 1300)
1898 return ATL::CWindowImpl
< T
, TBase
>::Create(hWndParent
, rcDefault
, lpstrText
, dwStyle
, 0, nID
);
1899 #else // !(_MSC_VER >= 1300)
1900 typedef ATL::CWindowImpl
< T
, TBase
> _baseClass
;
1901 return _baseClass::Create(hWndParent
, rcDefault
, lpstrText
, dwStyle
, 0, nID
);
1902 #endif // !(_MSC_VER >= 1300)
1905 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
)
1907 const int cchMax
= 128; // max text length is 127 for status bars (+1 for null)
1908 TCHAR szText
[cchMax
];
1910 ::LoadString(ModuleHelper::GetResourceInstance(), nTextID
, szText
, cchMax
);
1911 return Create(hWndParent
, szText
, dwStyle
, nID
);
1914 BOOL
SetPanes(int* pPanes
, int nPanes
, bool bSetText
= true)
1916 ATLASSERT(::IsWindow(m_hWnd
));
1917 ATLASSERT(nPanes
> 0);
1923 ATLTRY(m_pPane
= new int[nPanes
]);
1924 ATLASSERT(m_pPane
!= NULL
);
1928 CTempBuffer
<int, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
1929 int* pPanesPos
= buff
.Allocate(nPanes
);
1930 ATLASSERT(pPanesPos
!= NULL
);
1931 if(pPanesPos
== NULL
)
1934 SecureHelper::memcpy_x(m_pPane
, nPanes
* sizeof(int), pPanes
, nPanes
* sizeof(int));
1936 // get status bar DC and set font
1937 CClientDC
dc(m_hWnd
);
1938 HFONT hOldFont
= dc
.SelectFont(GetFont());
1940 // get status bar borders
1941 int arrBorders
[3] = { 0 };
1942 GetBorders(arrBorders
);
1944 const int cchBuff
= 128;
1945 TCHAR szBuff
[cchBuff
] = { 0 };
1946 SIZE size
= { 0, 0 };
1947 int cxLeft
= arrBorders
[0];
1949 // calculate right edge of each part
1950 for(int i
= 0; i
< nPanes
; i
++)
1952 if(pPanes
[i
] == ID_DEFAULT_PANE
)
1954 // make very large, will be resized later
1955 pPanesPos
[i
] = INT_MAX
/ 2;
1959 ::LoadString(ModuleHelper::GetResourceInstance(), pPanes
[i
], szBuff
, cchBuff
);
1960 dc
.GetTextExtent(szBuff
, lstrlen(szBuff
), &size
);
1961 T
* pT
= static_cast<T
*>(this);
1963 pPanesPos
[i
] = cxLeft
+ size
.cx
+ arrBorders
[2] + 2 * pT
->m_cxPaneMargin
;
1965 cxLeft
= pPanesPos
[i
];
1968 BOOL bRet
= SetParts(nPanes
, pPanesPos
);
1970 if(bRet
&& bSetText
)
1972 for(int i
= 0; i
< nPanes
; i
++)
1974 if(pPanes
[i
] != ID_DEFAULT_PANE
)
1976 ::LoadString(ModuleHelper::GetResourceInstance(), pPanes
[i
], szBuff
, cchBuff
);
1977 SetPaneText(m_pPane
[i
], szBuff
);
1982 dc
.SelectFont(hOldFont
);
1986 bool GetPaneTextLength(int nPaneID
, int* pcchLength
= NULL
, int* pnType
= NULL
) const
1988 ATLASSERT(::IsWindow(m_hWnd
));
1989 int nIndex
= GetPaneIndexFromID(nPaneID
);
1993 int nLength
= GetTextLength(nIndex
, pnType
);
1994 if(pcchLength
!= NULL
)
1995 *pcchLength
= nLength
;
2000 BOOL
GetPaneText(int nPaneID
, LPTSTR lpstrText
, int* pcchLength
= NULL
, int* pnType
= NULL
) const
2002 ATLASSERT(::IsWindow(m_hWnd
));
2003 int nIndex
= GetPaneIndexFromID(nPaneID
);
2007 int nLength
= GetText(nIndex
, lpstrText
, pnType
);
2008 if(pcchLength
!= NULL
)
2009 *pcchLength
= nLength
;
2014 BOOL
SetPaneText(int nPaneID
, LPCTSTR lpstrText
, int nType
= 0)
2016 ATLASSERT(::IsWindow(m_hWnd
));
2017 int nIndex
= GetPaneIndexFromID(nPaneID
);
2021 return SetText(nIndex
, lpstrText
, nType
);
2024 BOOL
GetPaneRect(int nPaneID
, LPRECT lpRect
) const
2026 ATLASSERT(::IsWindow(m_hWnd
));
2027 int nIndex
= GetPaneIndexFromID(nPaneID
);
2031 return GetRect(nIndex
, lpRect
);
2034 BOOL
SetPaneWidth(int nPaneID
, int cxWidth
)
2036 ATLASSERT(::IsWindow(m_hWnd
));
2037 ATLASSERT(nPaneID
!= ID_DEFAULT_PANE
); // Can't resize this one
2038 int nIndex
= GetPaneIndexFromID(nPaneID
);
2042 // get pane positions
2043 CTempBuffer
<int, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
2044 int* pPanesPos
= buff
.Allocate(m_nPanes
);
2045 if(pPanesPos
== NULL
)
2047 GetParts(m_nPanes
, pPanesPos
);
2049 int cxPaneWidth
= pPanesPos
[nIndex
] - ((nIndex
== 0) ? 0 : pPanesPos
[nIndex
- 1]);
2050 int cxOff
= cxWidth
- cxPaneWidth
;
2051 // find variable width pane
2052 int nDef
= m_nPanes
;
2053 for(int i
= 0; i
< m_nPanes
; i
++)
2055 if(m_pPane
[i
] == ID_DEFAULT_PANE
)
2062 if(nIndex
< nDef
) // before default pane
2064 for(int i
= nIndex
; i
< nDef
; i
++)
2065 pPanesPos
[i
] += cxOff
;
2068 else // after default one
2070 for(int i
= nDef
; i
< nIndex
; i
++)
2071 pPanesPos
[i
] -= cxOff
;
2073 // set pane postions
2074 return SetParts(m_nPanes
, pPanesPos
);
2077 #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
2078 BOOL
GetPaneTipText(int nPaneID
, LPTSTR lpstrText
, int nSize
) const
2080 ATLASSERT(::IsWindow(m_hWnd
));
2081 int nIndex
= GetPaneIndexFromID(nPaneID
);
2085 GetTipText(nIndex
, lpstrText
, nSize
);
2089 BOOL
SetPaneTipText(int nPaneID
, LPCTSTR lpstrText
)
2091 ATLASSERT(::IsWindow(m_hWnd
));
2092 int nIndex
= GetPaneIndexFromID(nPaneID
);
2096 SetTipText(nIndex
, lpstrText
);
2099 #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
2101 #if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))
2102 BOOL
GetPaneIcon(int nPaneID
, HICON
& hIcon
) const
2104 ATLASSERT(::IsWindow(m_hWnd
));
2105 int nIndex
= GetPaneIndexFromID(nPaneID
);
2109 hIcon
= GetIcon(nIndex
);
2113 BOOL
SetPaneIcon(int nPaneID
, HICON hIcon
)
2115 ATLASSERT(::IsWindow(m_hWnd
));
2116 int nIndex
= GetPaneIndexFromID(nPaneID
);
2120 return SetIcon(nIndex
, hIcon
);
2122 #endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))
2124 // Message map and handlers
2125 BEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl
< T
>)
2126 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2129 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
2131 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
2132 if(wParam
!= SIZE_MINIMIZED
&& m_nPanes
> 0)
2134 T
* pT
= static_cast<T
*>(this);
2135 pT
->UpdatePanesLayout();
2141 BOOL
UpdatePanesLayout()
2143 // get pane positions
2144 CTempBuffer
<int, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
2145 int* pPanesPos
= buff
.Allocate(m_nPanes
);
2146 ATLASSERT(pPanesPos
!= NULL
);
2147 if(pPanesPos
== NULL
)
2149 int nRet
= GetParts(m_nPanes
, pPanesPos
);
2150 ATLASSERT(nRet
== m_nPanes
);
2151 if(nRet
!= m_nPanes
)
2154 RECT rcClient
= { 0 };
2155 GetClientRect(&rcClient
);
2156 int cxOff
= rcClient
.right
- pPanesPos
[m_nPanes
- 1];
2158 // Move panes left if size grip box is present
2159 if((GetStyle() & SBARS_SIZEGRIP
) != 0)
2160 cxOff
-= ::GetSystemMetrics(SM_CXVSCROLL
) + ::GetSystemMetrics(SM_CXEDGE
);
2161 #endif // !_WIN32_WCE
2162 // find variable width pane
2164 for(i
= 0; i
< m_nPanes
; i
++)
2166 if(m_pPane
[i
] == ID_DEFAULT_PANE
)
2169 // resize all panes from the variable one to the right
2170 if((i
< m_nPanes
) && (pPanesPos
[i
] + cxOff
) > ((i
== 0) ? 0 : pPanesPos
[i
- 1]))
2172 for(; i
< m_nPanes
; i
++)
2173 pPanesPos
[i
] += cxOff
;
2175 // set pane postions
2176 return SetParts(m_nPanes
, pPanesPos
);
2179 int GetPaneIndexFromID(int nPaneID
) const
2181 for(int i
= 0; i
< m_nPanes
; i
++)
2183 if(m_pPane
[i
] == nPaneID
)
2187 return -1; // not found
2191 class CMultiPaneStatusBarCtrl
: public CMultiPaneStatusBarCtrlImpl
<CMultiPaneStatusBarCtrl
>
2194 DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName())
2198 ///////////////////////////////////////////////////////////////////////////////
2199 // CPaneContainer - provides header with title and close button for panes
2201 // pane container extended styles
2202 #define PANECNT_NOCLOSEBUTTON 0x00000001
2203 #define PANECNT_VERTICAL 0x00000002
2204 #define PANECNT_FLATBORDER 0x00000004
2205 #define PANECNT_NOBORDER 0x00000008
2207 template <class T
, class TBase
= ATL::CWindow
, class TWinTraits
= ATL::CControlWinTraits
>
2208 class ATL_NO_VTABLE CPaneContainerImpl
: public ATL::CWindowImpl
< T
, TBase
, TWinTraits
>, public CCustomDraw
< T
>
2211 DECLARE_WND_CLASS_EX(NULL
, 0, -1)
2217 m_cxyTextOffset
= 4,
2226 m_cxToolBar
= m_cxImageTB
+ m_cxyBtnAddTB
+ m_cxyBorder
+ m_cxyBtnOffset
,
2228 m_xBtnImageLeft
= 6,
2230 m_xBtnImageRight
= 12,
2231 m_yBtnImageBottom
= 11,
2233 m_nCloseBtnID
= ID_PANE_CLOSE
2238 ATL::CWindow m_wndClient
;
2240 TCHAR m_szTitle
[m_cchTitle
];
2241 DWORD m_dwExtendedStyle
; // Pane container specific extended styles
2245 CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0)
2251 DWORD
GetPaneContainerExtendedStyle() const
2253 return m_dwExtendedStyle
;
2256 DWORD
SetPaneContainerExtendedStyle(DWORD dwExtendedStyle
, DWORD dwMask
= 0)
2258 DWORD dwPrevStyle
= m_dwExtendedStyle
;
2260 m_dwExtendedStyle
= dwExtendedStyle
;
2262 m_dwExtendedStyle
= (m_dwExtendedStyle
& ~dwMask
) | (dwExtendedStyle
& dwMask
);
2265 T
* pT
= static_cast<T
*>(this);
2266 bool bUpdate
= false;
2268 if(((dwPrevStyle
& PANECNT_NOCLOSEBUTTON
) != 0) && ((m_dwExtendedStyle
& PANECNT_NOCLOSEBUTTON
) == 0)) // add close button
2270 pT
->CreateCloseButton();
2273 else if(((dwPrevStyle
& PANECNT_NOCLOSEBUTTON
) == 0) && ((m_dwExtendedStyle
& PANECNT_NOCLOSEBUTTON
) != 0)) // remove close button
2275 pT
->DestroyCloseButton();
2279 if((dwPrevStyle
& PANECNT_VERTICAL
) != (m_dwExtendedStyle
& PANECNT_VERTICAL
)) // change orientation
2285 if((dwPrevStyle
& (PANECNT_FLATBORDER
| PANECNT_NOBORDER
)) !=
2286 (m_dwExtendedStyle
& (PANECNT_FLATBORDER
| PANECNT_NOBORDER
))) // change border
2297 HWND
GetClient() const
2302 HWND
SetClient(HWND hWndClient
)
2304 HWND hWndOldClient
= m_wndClient
;
2305 m_wndClient
= hWndClient
;
2308 T
* pT
= static_cast<T
*>(this);
2311 return hWndOldClient
;
2314 BOOL
GetTitle(LPTSTR lpstrTitle
, int cchLength
) const
2316 ATLASSERT(lpstrTitle
!= NULL
);
2318 errno_t nRet
= SecureHelper::strncpy_x(lpstrTitle
, cchLength
, m_szTitle
, _TRUNCATE
);
2320 return (nRet
== 0 || nRet
== STRUNCATE
);
2323 BOOL
SetTitle(LPCTSTR lpstrTitle
)
2325 ATLASSERT(lpstrTitle
!= NULL
);
2327 errno_t nRet
= SecureHelper::strncpy_x(m_szTitle
, m_cchTitle
, lpstrTitle
, _TRUNCATE
);
2328 bool bRet
= (nRet
== 0 || nRet
== STRUNCATE
);
2329 if(bRet
&& m_hWnd
!= NULL
)
2331 T
* pT
= static_cast<T
*>(this);
2338 int GetTitleLength() const
2340 return lstrlen(m_szTitle
);
2344 HWND
Create(HWND hWndParent
, LPCTSTR lpstrTitle
= NULL
, DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
,
2345 DWORD dwExStyle
= 0, UINT nID
= 0, LPVOID lpCreateParam
= NULL
)
2347 if(lpstrTitle
!= NULL
)
2348 SecureHelper::strncpy_x(m_szTitle
, m_cchTitle
, lpstrTitle
, _TRUNCATE
);
2349 #if (_MSC_VER >= 1300)
2350 return ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::Create(hWndParent
, rcDefault
, NULL
, dwStyle
, dwExStyle
, nID
, lpCreateParam
);
2351 #else // !(_MSC_VER >= 1300)
2352 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
2353 return _baseClass::Create(hWndParent
, rcDefault
, NULL
, dwStyle
, dwExStyle
, nID
, lpCreateParam
);
2354 #endif // !(_MSC_VER >= 1300)
2357 HWND
Create(HWND hWndParent
, UINT uTitleID
, DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
,
2358 DWORD dwExStyle
= 0, UINT nID
= 0, LPVOID lpCreateParam
= NULL
)
2361 ::LoadString(ModuleHelper::GetResourceInstance(), uTitleID
, m_szTitle
, m_cchTitle
);
2362 #if (_MSC_VER >= 1300)
2363 return ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::Create(hWndParent
, rcDefault
, NULL
, dwStyle
, dwExStyle
, nID
, lpCreateParam
);
2364 #else // !(_MSC_VER >= 1300)
2365 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
2366 return _baseClass::Create(hWndParent
, rcDefault
, NULL
, dwStyle
, dwExStyle
, nID
, lpCreateParam
);
2367 #endif // !(_MSC_VER >= 1300)
2370 BOOL
EnableCloseButton(BOOL bEnable
)
2372 ATLASSERT(::IsWindow(m_hWnd
));
2373 T
* pT
= static_cast<T
*>(this);
2374 pT
; // avoid level 4 warning
2375 return (m_tb
.m_hWnd
!= NULL
) ? m_tb
.EnableButton(pT
->m_nCloseBtnID
, bEnable
) : FALSE
;
2380 RECT rcClient
= { 0 };
2381 GetClientRect(&rcClient
);
2382 T
* pT
= static_cast<T
*>(this);
2383 pT
->UpdateLayout(rcClient
.right
, rcClient
.bottom
);
2386 // Message map and handlers
2387 BEGIN_MSG_MAP(CPaneContainerImpl
)
2388 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2389 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2390 MESSAGE_HANDLER(WM_SETFOCUS
, OnSetFocus
)
2391 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2392 MESSAGE_HANDLER(WM_PAINT
, OnPaint
)
2394 MESSAGE_HANDLER(WM_PRINTCLIENT
, OnPaint
)
2395 #endif // !_WIN32_WCE
2396 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2397 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2398 FORWARD_NOTIFICATIONS()
2401 LRESULT
OnCreate(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
2403 T
* pT
= static_cast<T
*>(this);
2406 if((m_dwExtendedStyle
& PANECNT_NOCLOSEBUTTON
) == 0)
2407 pT
->CreateCloseButton();
2412 LRESULT
OnSize(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& /*bHandled*/)
2414 T
* pT
= static_cast<T
*>(this);
2415 pT
->UpdateLayout(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
2419 LRESULT
OnSetFocus(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
2421 if(m_wndClient
.m_hWnd
!= NULL
)
2422 m_wndClient
.SetFocus();
2426 LRESULT
OnEraseBackground(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
2428 return 1; // no background needed
2431 LRESULT
OnPaint(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
2433 T
* pT
= static_cast<T
*>(this);
2436 pT
->DrawPaneTitle((HDC
)wParam
);
2438 if(m_wndClient
.m_hWnd
== NULL
) // no client window
2439 pT
->DrawPane((HDC
)wParam
);
2443 CPaintDC
dc(m_hWnd
);
2444 pT
->DrawPaneTitle(dc
.m_hDC
);
2446 if(m_wndClient
.m_hWnd
== NULL
) // no client window
2447 pT
->DrawPane(dc
.m_hDC
);
2453 LRESULT
OnNotify(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
2455 if(m_tb
.m_hWnd
== NULL
)
2461 T
* pT
= static_cast<T
*>(this);
2463 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
2466 // pass toolbar custom draw notifications to the base class
2467 if(lpnmh
->code
== NM_CUSTOMDRAW
&& lpnmh
->hwndFrom
== m_tb
.m_hWnd
)
2468 lRet
= CCustomDraw
< T
>::OnCustomDraw(0, lpnmh
, bHandled
);
2470 // tooltip notifications come with the tooltip window handle and button ID,
2471 // pass them to the parent if we don't handle them
2472 else if(lpnmh
->code
== TTN_GETDISPINFO
&& lpnmh
->idFrom
== pT
->m_nCloseBtnID
)
2473 bHandled
= pT
->GetToolTipText(lpnmh
);
2474 #endif // !_WIN32_WCE
2475 // only let notifications not from the toolbar go to the parent
2476 else if(lpnmh
->hwndFrom
!= m_tb
.m_hWnd
&& lpnmh
->idFrom
!= pT
->m_nCloseBtnID
)
2482 LRESULT
OnCommand(UINT
/*uMsg*/, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2484 // if command comes from the close button, substitute HWND of the pane container instead
2485 if(m_tb
.m_hWnd
!= NULL
&& (HWND
)lParam
== m_tb
.m_hWnd
)
2486 return ::SendMessage(GetParent(), WM_COMMAND
, wParam
, (LPARAM
)m_hWnd
);
2492 // Custom draw overrides
2493 DWORD
OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW
/*lpNMCustomDraw*/)
2495 return CDRF_NOTIFYITEMDRAW
; // we need per-item notifications
2498 DWORD
OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw
)
2500 CDCHandle dc
= lpNMCustomDraw
->hdc
;
2501 #if (_WIN32_IE >= 0x0400)
2502 RECT
& rc
= lpNMCustomDraw
->rc
;
2503 #else // !(_WIN32_IE >= 0x0400)
2505 m_tb
.GetItemRect(0, &rc
);
2506 #endif // !(_WIN32_IE >= 0x0400)
2508 dc
.FillRect(&rc
, COLOR_3DFACE
);
2510 return CDRF_NOTIFYPOSTPAINT
;
2513 DWORD
OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw
)
2515 CDCHandle dc
= lpNMCustomDraw
->hdc
;
2516 #if (_WIN32_IE >= 0x0400)
2517 RECT
& rc
= lpNMCustomDraw
->rc
;
2518 #else // !(_WIN32_IE >= 0x0400)
2520 m_tb
.GetItemRect(0, &rc
);
2521 #endif // !(_WIN32_IE >= 0x0400)
2523 RECT rcImage
= { m_xBtnImageLeft
, m_yBtnImageTop
, m_xBtnImageRight
+ 1, m_yBtnImageBottom
+ 1 };
2524 ::OffsetRect(&rcImage
, rc
.left
, rc
.top
);
2525 T
* pT
= static_cast<T
*>(this);
2527 if((lpNMCustomDraw
->uItemState
& CDIS_DISABLED
) != 0)
2529 RECT rcShadow
= rcImage
;
2530 ::OffsetRect(&rcShadow
, 1, 1);
2532 pen1
.CreatePen(PS_SOLID
, 0, ::GetSysColor(COLOR_3DHILIGHT
));
2533 pT
->DrawButtonImage(dc
, rcShadow
, pen1
);
2535 pen2
.CreatePen(PS_SOLID
, 0, ::GetSysColor(COLOR_3DSHADOW
));
2536 pT
->DrawButtonImage(dc
, rcImage
, pen2
);
2540 if((lpNMCustomDraw
->uItemState
& CDIS_SELECTED
) != 0)
2541 ::OffsetRect(&rcImage
, 1, 1);
2543 pen
.CreatePen(PS_SOLID
, 0, ::GetSysColor(COLOR_BTNTEXT
));
2544 pT
->DrawButtonImage(dc
, rcImage
, pen
);
2547 return CDRF_DODEFAULT
; // continue with the default item painting
2550 // Implementation - overrideable methods
2551 void UpdateLayout(int cxWidth
, int cyHeight
)
2553 ATLASSERT(::IsWindow(m_hWnd
));
2558 ::SetRect(&rect
, 0, 0, m_cxyHeader
, cyHeight
);
2559 if(m_tb
.m_hWnd
!= NULL
)
2560 m_tb
.SetWindowPos(NULL
, m_cxyBorder
, m_cxyBorder
+ m_cxyBtnOffset
, 0, 0, SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
2562 if(m_wndClient
.m_hWnd
!= NULL
)
2563 m_wndClient
.SetWindowPos(NULL
, m_cxyHeader
, 0, cxWidth
- m_cxyHeader
, cyHeight
, SWP_NOZORDER
);
2565 rect
.right
= cxWidth
;
2569 ::SetRect(&rect
, 0, 0, cxWidth
, m_cxyHeader
);
2570 if(m_tb
.m_hWnd
!= NULL
)
2571 m_tb
.SetWindowPos(NULL
, rect
.right
- m_cxToolBar
, m_cxyBorder
+ m_cxyBtnOffset
, 0, 0, SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
2573 if(m_wndClient
.m_hWnd
!= NULL
)
2574 m_wndClient
.SetWindowPos(NULL
, 0, m_cxyHeader
, cxWidth
, cyHeight
- m_cxyHeader
, SWP_NOZORDER
);
2576 rect
.bottom
= cyHeight
;
2579 InvalidateRect(&rect
);
2582 void CreateCloseButton()
2584 ATLASSERT(m_tb
.m_hWnd
== NULL
);
2585 // create toolbar for the "x" button
2586 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);
2587 ATLASSERT(m_tb
.IsWindow());
2589 if(m_tb
.m_hWnd
!= NULL
)
2591 T
* pT
= static_cast<T
*>(this);
2592 pT
; // avoid level 4 warning
2594 m_tb
.SetButtonStructSize();
2596 TBBUTTON tbbtn
= { 0 };
2597 tbbtn
.idCommand
= pT
->m_nCloseBtnID
;
2598 tbbtn
.fsState
= TBSTATE_ENABLED
;
2599 tbbtn
.fsStyle
= TBSTYLE_BUTTON
;
2600 m_tb
.AddButtons(1, &tbbtn
);
2602 m_tb
.SetBitmapSize(m_cxImageTB
, m_cyImageTB
);
2603 m_tb
.SetButtonSize(m_cxImageTB
+ m_cxyBtnAddTB
, m_cyImageTB
+ m_cxyBtnAddTB
);
2606 m_tb
.SetWindowPos(NULL
, m_cxyBorder
+ m_cxyBtnOffset
, m_cxyBorder
+ m_cxyBtnOffset
, m_cxImageTB
+ m_cxyBtnAddTB
, m_cyImageTB
+ m_cxyBtnAddTB
, SWP_NOZORDER
| SWP_NOACTIVATE
);
2608 m_tb
.SetWindowPos(NULL
, 0, 0, m_cxImageTB
+ m_cxyBtnAddTB
, m_cyImageTB
+ m_cxyBtnAddTB
, SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
);
2612 void DestroyCloseButton()
2614 if(m_tb
.m_hWnd
!= NULL
)
2615 m_tb
.DestroyWindow();
2620 T
* pT
= static_cast<T
*>(this);
2621 CFontHandle font
= pT
->GetTitleFont();
2623 font
.GetLogFont(lf
);
2626 m_cxyHeader
= m_cxImageTB
+ m_cxyBtnAddTB
+ m_cxyBorder
;
2630 int cyFont
= abs(lf
.lfHeight
) + m_cxyBorder
+ 2 * m_cxyTextOffset
;
2631 int cyBtn
= m_cyImageTB
+ m_cxyBtnAddTB
+ m_cxyBorder
+ 2 * m_cxyBtnOffset
;
2632 m_cxyHeader
= __max(cyFont
, cyBtn
);
2636 HFONT
GetTitleFont() const
2638 return AtlGetDefaultGuiFont();
2642 BOOL
GetToolTipText(LPNMHDR
/*lpnmh*/)
2646 #endif // !_WIN32_WCE
2648 void DrawPaneTitle(CDCHandle dc
)
2651 GetClientRect(&rect
);
2653 UINT uBorder
= BF_LEFT
| BF_TOP
| BF_ADJUST
;
2656 rect
.right
= rect
.left
+ m_cxyHeader
;
2657 uBorder
|= BF_BOTTOM
;
2661 rect
.bottom
= rect
.top
+ m_cxyHeader
;
2662 uBorder
|= BF_RIGHT
;
2665 if((m_dwExtendedStyle
& PANECNT_NOBORDER
) == 0)
2667 if((m_dwExtendedStyle
& PANECNT_FLATBORDER
) != 0)
2669 dc
.DrawEdge(&rect
, EDGE_ETCHED
, uBorder
);
2671 dc
.FillRect(&rect
, COLOR_3DFACE
);
2673 if(!IsVertical()) // draw title only for horizontal pane container
2675 dc
.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT
));
2676 dc
.SetBkMode(TRANSPARENT
);
2677 T
* pT
= static_cast<T
*>(this);
2678 HFONT hFontOld
= dc
.SelectFont(pT
->GetTitleFont());
2679 rect
.left
+= m_cxyTextOffset
;
2680 rect
.right
-= m_cxyTextOffset
;
2681 if(m_tb
.m_hWnd
!= NULL
)
2682 rect
.right
-= m_cxToolBar
;;
2684 dc
.DrawText(m_szTitle
, -1, &rect
, DT_LEFT
| DT_SINGLELINE
| DT_VCENTER
| DT_END_ELLIPSIS
);
2685 #else // CE specific
2686 dc
.DrawText(m_szTitle
, -1, &rect
, DT_LEFT
| DT_SINGLELINE
| DT_VCENTER
);
2687 #endif // _WIN32_WCE
2688 dc
.SelectFont(hFontOld
);
2692 // called only if pane is empty
2693 void DrawPane(CDCHandle dc
)
2696 GetClientRect(&rect
);
2698 rect
.left
+= m_cxyHeader
;
2700 rect
.top
+= m_cxyHeader
;
2701 if((GetExStyle() & WS_EX_CLIENTEDGE
) == 0)
2702 dc
.DrawEdge(&rect
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
2703 dc
.FillRect(&rect
, COLOR_APPWORKSPACE
);
2706 // drawing helper - draws "x" button image
2707 void DrawButtonImage(CDCHandle dc
, RECT
& rcImage
, HPEN hPen
)
2709 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
2710 HPEN hPenOld
= dc
.SelectPen(hPen
);
2712 dc
.MoveTo(rcImage
.left
, rcImage
.top
);
2713 dc
.LineTo(rcImage
.right
, rcImage
.bottom
);
2714 dc
.MoveTo(rcImage
.left
+ 1, rcImage
.top
);
2715 dc
.LineTo(rcImage
.right
+ 1, rcImage
.bottom
);
2717 dc
.MoveTo(rcImage
.left
, rcImage
.bottom
- 1);
2718 dc
.LineTo(rcImage
.right
, rcImage
.top
- 1);
2719 dc
.MoveTo(rcImage
.left
+ 1, rcImage
.bottom
- 1);
2720 dc
.LineTo(rcImage
.right
+ 1, rcImage
.top
- 1);
2722 dc
.SelectPen(hPenOld
);
2723 #else // (_WIN32_WCE < 400)
2726 // no support for the "x" button image
2727 #endif // (_WIN32_WCE < 400)
2730 bool IsVertical() const
2732 return ((m_dwExtendedStyle
& PANECNT_VERTICAL
) != 0);
2736 class CPaneContainer
: public CPaneContainerImpl
<CPaneContainer
>
2739 DECLARE_WND_CLASS_EX(_T("WTL_PaneContainer"), 0, -1)
2743 ///////////////////////////////////////////////////////////////////////////////
2744 // CSortListViewCtrl - implements sorting for a listview control
2746 // sort listview extended styles
2747 #define SORTLV_USESHELLBITMAPS 0x00000001
2749 // Notification sent to parent when sort column is changed by user clicking header.
2750 #define SLVN_SORTCHANGED LVN_LAST
2752 // A LPNMSORTLISTVIEW is sent with the SLVN_SORTCHANGED notification
2753 typedef struct tagNMSORTLISTVIEW
2758 } NMSORTLISTVIEW
, *LPNMSORTLISTVIEW
;
2760 // Column sort types. Can be set on a per-column basis with the SetColumnSortType method.
2764 LVCOLSORT_TEXT
, // default
2765 LVCOLSORT_TEXTNOCASE
,
2773 LVCOLSORT_LAST
= LVCOLSORT_CUSTOM
2778 class CSortListViewImpl
2783 m_cchCmpTextMax
= 32, // overrideable
2788 m_iSortUp
= 0, // index of sort bitmaps
2790 m_nShellSortUpID
= 133
2793 // passed to LVCompare functions as lParam1 and lParam2
2794 struct LVCompareParam
2797 DWORD_PTR dwItemData
;
2807 // passed to LVCompare functions as the lParamSort parameter
2815 bool m_bSortDescending
;
2818 CBitmap m_bmSort
[2];
2819 int m_fmtOldSortCol
;
2820 HBITMAP m_hbmOldSortCol
;
2821 DWORD m_dwSortLVExtendedStyle
;
2822 ATL::CSimpleArray
<WORD
> m_arrColSortType
;
2823 bool m_bUseWaitCursor
;
2825 CSortListViewImpl() :
2826 m_bSortDescending(false),
2827 m_bCommCtrl6(false),
2830 m_hbmOldSortCol(NULL
),
2831 m_dwSortLVExtendedStyle(SORTLV_USESHELLBITMAPS
),
2832 m_bUseWaitCursor(true)
2837 HRESULT hRet
= ATL::AtlGetCommCtrlVersion(&dwMajor
, &dwMinor
);
2838 m_bCommCtrl6
= SUCCEEDED(hRet
) && dwMajor
>= 6;
2839 #endif // !_WIN32_WCE
2843 void SetSortColumn(int iCol
)
2845 T
* pT
= static_cast<T
*>(this);
2846 ATLASSERT(::IsWindow(pT
->m_hWnd
));
2847 CHeaderCtrl header
= pT
->GetHeader();
2848 ATLASSERT(header
.m_hWnd
!= NULL
);
2849 ATLASSERT(iCol
>= -1 && iCol
< m_arrColSortType
.GetSize());
2851 int iOldSortCol
= m_iSortColumn
;
2852 m_iSortColumn
= iCol
;
2856 const int HDF_SORTUP
= 0x0400;
2857 #endif // HDF_SORTUP
2858 #ifndef HDF_SORTDOWN
2859 const int HDF_SORTDOWN
= 0x0200;
2860 #endif // HDF_SORTDOWN
2861 const int nMask
= HDF_SORTUP
| HDF_SORTDOWN
;
2862 HDITEM hditem
= { HDI_FORMAT
};
2863 if(iOldSortCol
!= iCol
&& iOldSortCol
>= 0 && header
.GetItem(iOldSortCol
, &hditem
))
2865 hditem
.fmt
&= ~nMask
;
2866 header
.SetItem(iOldSortCol
, &hditem
);
2868 if(iCol
>= 0 && header
.GetItem(iCol
, &hditem
))
2870 hditem
.fmt
&= ~nMask
;
2871 hditem
.fmt
|= m_bSortDescending
? HDF_SORTDOWN
: HDF_SORTUP
;
2872 header
.SetItem(iCol
, &hditem
);
2877 if(m_bmSort
[m_iSortUp
].IsNull())
2878 pT
->CreateSortBitmaps();
2880 // restore previous sort column's bitmap, if any, and format
2881 HDITEM hditem
= { HDI_BITMAP
| HDI_FORMAT
};
2882 if(iOldSortCol
!= iCol
&& iOldSortCol
>= 0)
2884 hditem
.hbm
= m_hbmOldSortCol
;
2885 hditem
.fmt
= m_fmtOldSortCol
;
2886 header
.SetItem(iOldSortCol
, &hditem
);
2889 // save new sort column's bitmap and format, and add our sort bitmap
2890 if(iCol
>= 0 && header
.GetItem(iCol
, &hditem
))
2892 if(iOldSortCol
!= iCol
)
2894 m_fmtOldSortCol
= hditem
.fmt
;
2895 m_hbmOldSortCol
= hditem
.hbm
;
2897 hditem
.fmt
&= ~HDF_IMAGE
;
2898 hditem
.fmt
|= HDF_BITMAP
| HDF_BITMAP_ON_RIGHT
;
2899 int i
= m_bSortDescending
? m_iSortDown
: m_iSortUp
;
2900 hditem
.hbm
= m_bmSort
[i
];
2901 header
.SetItem(iCol
, &hditem
);
2905 int GetSortColumn() const
2907 return m_iSortColumn
;
2910 void SetColumnSortType(int iCol
, WORD wType
)
2912 ATLASSERT(iCol
>= 0 && iCol
< m_arrColSortType
.GetSize());
2913 ATLASSERT(wType
>= LVCOLSORT_NONE
&& wType
<= LVCOLSORT_LAST
);
2914 m_arrColSortType
[iCol
] = wType
;
2917 WORD
GetColumnSortType(int iCol
) const
2919 ATLASSERT((iCol
>= 0) && iCol
< m_arrColSortType
.GetSize());
2920 return m_arrColSortType
[iCol
];
2923 int GetColumnCount() const
2925 const T
* pT
= static_cast<const T
*>(this);
2926 ATLASSERT(::IsWindow(pT
->m_hWnd
));
2927 CHeaderCtrl header
= pT
->GetHeader();
2928 return header
.m_hWnd
!= NULL
? header
.GetItemCount() : 0;
2931 bool IsSortDescending() const
2933 return m_bSortDescending
;
2936 DWORD
GetSortListViewExtendedStyle() const
2938 return m_dwSortLVExtendedStyle
;
2941 DWORD
SetSortListViewExtendedStyle(DWORD dwExtendedStyle
, DWORD dwMask
= 0)
2943 DWORD dwPrevStyle
= m_dwSortLVExtendedStyle
;
2945 m_dwSortLVExtendedStyle
= dwExtendedStyle
;
2947 m_dwSortLVExtendedStyle
= (m_dwSortLVExtendedStyle
& ~dwMask
) | (dwExtendedStyle
& dwMask
);
2952 bool DoSortItems(int iCol
, bool bDescending
= false)
2954 T
* pT
= static_cast<T
*>(this);
2955 ATLASSERT(::IsWindow(pT
->m_hWnd
));
2956 ATLASSERT(iCol
>= 0 && iCol
< m_arrColSortType
.GetSize());
2958 WORD wType
= m_arrColSortType
[iCol
];
2959 if(wType
== LVCOLSORT_NONE
)
2962 int nCount
= pT
->GetItemCount();
2965 m_bSortDescending
= bDescending
;
2966 SetSortColumn(iCol
);
2970 CWaitCursor
waitCursor(false);
2971 if(m_bUseWaitCursor
)
2974 LVCompareParam
* pParam
= NULL
;
2975 ATLTRY(pParam
= new LVCompareParam
[nCount
]);
2976 PFNLVCOMPARE pFunc
= NULL
;
2977 TCHAR pszTemp
[pT
->m_cchCmpTextMax
];
2978 bool bStrValue
= false;
2982 case LVCOLSORT_TEXT
:
2983 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareText
;
2984 case LVCOLSORT_TEXTNOCASE
:
2986 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareTextNoCase
;
2987 case LVCOLSORT_CUSTOM
:
2990 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareCustom
;
2992 for(int i
= 0; i
< nCount
; i
++)
2994 pParam
[i
].iItem
= i
;
2995 pParam
[i
].dwItemData
= pT
->GetItemData(i
);
2996 pParam
[i
].pszValue
= new TCHAR
[pT
->m_cchCmpTextMax
];
2997 pT
->GetItemText(i
, iCol
, (LPTSTR
)pParam
[i
].pszValue
, pT
->m_cchCmpTextMax
);
2998 pT
->SetItemData(i
, (DWORD_PTR
)&pParam
[i
]);
3003 case LVCOLSORT_LONG
:
3005 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareLong
;
3006 for(int i
= 0; i
< nCount
; i
++)
3008 pParam
[i
].iItem
= i
;
3009 pParam
[i
].dwItemData
= pT
->GetItemData(i
);
3010 pT
->GetItemText(i
, iCol
, pszTemp
, pT
->m_cchCmpTextMax
);
3011 pParam
[i
].lValue
= pT
->StrToLong(pszTemp
);
3012 pT
->SetItemData(i
, (DWORD_PTR
)&pParam
[i
]);
3016 case LVCOLSORT_DOUBLE
:
3018 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareDouble
;
3019 for(int i
= 0; i
< nCount
; i
++)
3021 pParam
[i
].iItem
= i
;
3022 pParam
[i
].dwItemData
= pT
->GetItemData(i
);
3023 pT
->GetItemText(i
, iCol
, pszTemp
, pT
->m_cchCmpTextMax
);
3024 pParam
[i
].dblValue
= pT
->StrToDouble(pszTemp
);
3025 pT
->SetItemData(i
, (DWORD_PTR
)&pParam
[i
]);
3029 case LVCOLSORT_DECIMAL
:
3031 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareDecimal
;
3032 for(int i
= 0; i
< nCount
; i
++)
3034 pParam
[i
].iItem
= i
;
3035 pParam
[i
].dwItemData
= pT
->GetItemData(i
);
3036 pT
->GetItemText(i
, iCol
, pszTemp
, pT
->m_cchCmpTextMax
);
3037 pT
->StrToDecimal(pszTemp
, &pParam
[i
].decValue
);
3038 pT
->SetItemData(i
, (DWORD_PTR
)&pParam
[i
]);
3042 case LVCOLSORT_DATETIME
:
3043 case LVCOLSORT_DATE
:
3044 case LVCOLSORT_TIME
:
3046 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareDouble
;
3047 DWORD dwFlags
= LOCALE_NOUSEROVERRIDE
;
3048 if(wType
== LVCOLSORT_DATE
)
3049 dwFlags
|= VAR_DATEVALUEONLY
;
3050 else if(wType
== LVCOLSORT_TIME
)
3051 dwFlags
|= VAR_TIMEVALUEONLY
;
3052 for(int i
= 0; i
< nCount
; i
++)
3054 pParam
[i
].iItem
= i
;
3055 pParam
[i
].dwItemData
= pT
->GetItemData(i
);
3056 pT
->GetItemText(i
, iCol
, pszTemp
, pT
->m_cchCmpTextMax
);
3057 pParam
[i
].dblValue
= pT
->DateStrToDouble(pszTemp
, dwFlags
);
3058 pT
->SetItemData(i
, (DWORD_PTR
)&pParam
[i
]);
3063 ATLTRACE2(atlTraceUI
, 0, _T("Unknown value for sort type in CSortListViewImpl::DoSortItems()\n"));
3067 ATLASSERT(pFunc
!= NULL
);
3068 LVSortInfo lvsi
= { pT
, iCol
, bDescending
};
3069 bool bRet
= ((BOOL
)pT
->DefWindowProc(LVM_SORTITEMS
, (WPARAM
)&lvsi
, (LPARAM
)pFunc
) != FALSE
);
3070 for(int i
= 0; i
< nCount
; i
++)
3072 DWORD_PTR dwItemData
= pT
->GetItemData(i
);
3073 LVCompareParam
* p
= (LVCompareParam
*)dwItemData
;
3074 ATLASSERT(p
!= NULL
);
3076 delete [] (TCHAR
*)p
->pszValue
;
3077 pT
->SetItemData(i
, p
->dwItemData
);
3083 m_bSortDescending
= bDescending
;
3084 SetSortColumn(iCol
);
3087 if(m_bUseWaitCursor
)
3088 waitCursor
.Restore();
3093 void CreateSortBitmaps()
3095 if((m_dwSortLVExtendedStyle
& SORTLV_USESHELLBITMAPS
) != 0)
3098 LPCTSTR pszModule
= _T("shell32.dll");
3099 HINSTANCE hShell
= ::GetModuleHandle(pszModule
);
3103 hShell
= ::LoadLibrary(pszModule
);
3109 bool bSuccess
= true;
3110 for(int i
= m_iSortUp
; i
<= m_iSortDown
; i
++)
3112 if(!m_bmSort
[i
].IsNull())
3113 m_bmSort
[i
].DeleteObject();
3114 m_bmSort
[i
] = (HBITMAP
)::LoadImage(hShell
, MAKEINTRESOURCE(m_nShellSortUpID
+ i
),
3116 IMAGE_BITMAP
, 0, 0, LR_LOADMAP3DCOLORS
);
3117 #else // CE specific
3118 IMAGE_BITMAP
, 0, 0, 0);
3119 #endif // _WIN32_WCE
3120 if(m_bmSort
[i
].IsNull())
3127 ::FreeLibrary(hShell
);
3133 T
* pT
= static_cast<T
*>(this);
3134 for(int i
= m_iSortUp
; i
<= m_iSortDown
; i
++)
3136 if(!m_bmSort
[i
].IsNull())
3137 m_bmSort
[i
].DeleteObject();
3140 CClientDC
dc(::GetDesktopWindow());
3141 dcMem
.CreateCompatibleDC(dc
.m_hDC
);
3142 m_bmSort
[i
].CreateCompatibleBitmap(dc
.m_hDC
, m_cxSortImage
, m_cySortImage
);
3143 HBITMAP hbmOld
= dcMem
.SelectBitmap(m_bmSort
[i
]);
3144 RECT rc
= {0,0,m_cxSortImage
, m_cySortImage
};
3145 pT
->DrawSortBitmap(dcMem
.m_hDC
, i
, &rc
);
3146 dcMem
.SelectBitmap(hbmOld
);
3151 void NotifyParentSortChanged(int iNewSortCol
, int iOldSortCol
)
3153 T
* pT
= static_cast<T
*>(this);
3154 int nID
= pT
->GetDlgCtrlID();
3155 NMSORTLISTVIEW nm
= { { pT
->m_hWnd
, nID
, SLVN_SORTCHANGED
}, iNewSortCol
, iOldSortCol
};
3156 ::SendMessage(pT
->GetParent(), WM_NOTIFY
, (WPARAM
)nID
, (LPARAM
)&nm
);
3160 int CompareItemsCustom(LVCompareParam
* /*pItem1*/, LVCompareParam
* /*pItem2*/, int /*iSortCol*/)
3162 // pItem1 and pItem2 contain valid iItem, dwItemData, and pszValue members.
3163 // If item1 > item2 return 1, if item1 < item2 return -1, else return 0.
3167 void DrawSortBitmap(CDCHandle dc
, int iBitmap
, LPRECT prc
)
3169 dc
.FillRect(prc
, ::GetSysColorBrush(COLOR_BTNFACE
));
3170 HBRUSH hbrOld
= dc
.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW
));
3172 pen
.CreatePen(PS_SOLID
, 0, ::GetSysColor(COLOR_BTNSHADOW
));
3173 HPEN hpenOld
= dc
.SelectPen(pen
);
3174 POINT ptOrg
= { (m_cxSortImage
- m_cxSortArrow
) / 2, (m_cySortImage
- m_cySortArrow
) / 2 };
3175 if(iBitmap
== m_iSortUp
)
3179 { ptOrg
.x
+ m_cxSortArrow
/ 2, ptOrg
.y
},
3180 { ptOrg
.x
, ptOrg
.y
+ m_cySortArrow
- 1 },
3181 { ptOrg
.x
+ m_cxSortArrow
- 1, ptOrg
.y
+ m_cySortArrow
- 1 }
3189 { ptOrg
.x
, ptOrg
.y
},
3190 { ptOrg
.x
+ m_cxSortArrow
/ 2, ptOrg
.y
+ m_cySortArrow
- 1 },
3191 { ptOrg
.x
+ m_cxSortArrow
- 1, ptOrg
.y
}
3195 dc
.SelectBrush(hbrOld
);
3196 dc
.SelectPen(hpenOld
);
3199 double DateStrToDouble(LPCTSTR lpstr
, DWORD dwFlags
)
3201 ATLASSERT(lpstr
!= NULL
);
3202 if(lpstr
== NULL
|| lpstr
[0] == _T('\0'))
3206 HRESULT hRet
= E_FAIL
;
3208 if (FAILED(hRet
= ::VarDateFromStr((LPOLESTR
)T2COLE(lpstr
), LANG_USER_DEFAULT
, dwFlags
, &dRet
)))
3210 ATLTRACE2(atlTraceUI
, 0, _T("VarDateFromStr failed with result of 0x%8.8X\n"), hRet
);
3216 long StrToLong(LPCTSTR lpstr
)
3218 ATLASSERT(lpstr
!= NULL
);
3219 if(lpstr
== NULL
|| lpstr
[0] == _T('\0'))
3223 HRESULT hRet
= E_FAIL
;
3225 if (FAILED(hRet
= ::VarI4FromStr((LPOLESTR
)T2COLE(lpstr
), LANG_USER_DEFAULT
, LOCALE_NOUSEROVERRIDE
, &lRet
)))
3227 ATLTRACE2(atlTraceUI
, 0, _T("VarI4FromStr failed with result of 0x%8.8X\n"), hRet
);
3233 double StrToDouble(LPCTSTR lpstr
)
3235 ATLASSERT(lpstr
!= NULL
);
3236 if(lpstr
== NULL
|| lpstr
[0] == _T('\0'))
3240 HRESULT hRet
= E_FAIL
;
3242 if (FAILED(hRet
= ::VarR8FromStr((LPOLESTR
)T2COLE(lpstr
), LANG_USER_DEFAULT
, LOCALE_NOUSEROVERRIDE
, &dblRet
)))
3244 ATLTRACE2(atlTraceUI
, 0, _T("VarR8FromStr failed with result of 0x%8.8X\n"), hRet
);
3250 bool StrToDecimal(LPCTSTR lpstr
, DECIMAL
* pDecimal
)
3252 ATLASSERT(lpstr
!= NULL
);
3253 ATLASSERT(pDecimal
!= NULL
);
3254 if(lpstr
== NULL
|| pDecimal
== NULL
)
3258 HRESULT hRet
= E_FAIL
;
3259 if (FAILED(hRet
= ::VarDecFromStr((LPOLESTR
)T2COLE(lpstr
), LANG_USER_DEFAULT
, LOCALE_NOUSEROVERRIDE
, pDecimal
)))
3261 ATLTRACE2(atlTraceUI
, 0, _T("VarDecFromStr failed with result of 0x%8.8X\n"), hRet
);
3264 pDecimal
->signscale
= 0;
3270 // Overrideable PFNLVCOMPARE functions
3271 static int CALLBACK
LVCompareText(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3273 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3275 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3276 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3277 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3279 int nRet
= lstrcmp(pParam1
->pszValue
, pParam2
->pszValue
);
3280 return pInfo
->bDescending
? -nRet
: nRet
;
3283 static int CALLBACK
LVCompareTextNoCase(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3285 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3287 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3288 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3289 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3291 int nRet
= lstrcmpi(pParam1
->pszValue
, pParam2
->pszValue
);
3292 return pInfo
->bDescending
? -nRet
: nRet
;
3295 static int CALLBACK
LVCompareLong(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3297 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3299 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3300 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3301 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3304 if(pParam1
->lValue
> pParam2
->lValue
)
3306 else if(pParam1
->lValue
< pParam2
->lValue
)
3308 return pInfo
->bDescending
? -nRet
: nRet
;
3311 static int CALLBACK
LVCompareDouble(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3313 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3315 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3316 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3317 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3320 if(pParam1
->dblValue
> pParam2
->dblValue
)
3322 else if(pParam1
->dblValue
< pParam2
->dblValue
)
3324 return pInfo
->bDescending
? -nRet
: nRet
;
3327 static int CALLBACK
LVCompareCustom(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3329 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3331 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3332 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3333 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3335 int nRet
= pInfo
->pT
->CompareItemsCustom(pParam1
, pParam2
, pInfo
->iSortCol
);
3336 return pInfo
->bDescending
? -nRet
: nRet
;
3340 static int CALLBACK
LVCompareDecimal(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3342 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3344 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3345 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3346 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3348 int nRet
= (int)::VarDecCmp(&pParam1
->decValue
, &pParam2
->decValue
);
3350 return pInfo
->bDescending
? -nRet
: nRet
;
3353 // Compare mantissas, ignore sign and scale
3354 static int CompareMantissas(const DECIMAL
& decLeft
, const DECIMAL
& decRight
)
3356 if (decLeft
.Hi32
< decRight
.Hi32
)
3360 if (decLeft
.Hi32
> decRight
.Hi32
)
3364 // Here, decLeft.Hi32 == decRight.Hi32
3365 if (decLeft
.Lo64
< decRight
.Lo64
)
3369 if (decLeft
.Lo64
> decRight
.Lo64
)
3376 // return values: VARCMP_LT, VARCMP_EQ, VARCMP_GT, VARCMP_NULL
3377 static HRESULT
VarDecCmp(const DECIMAL
* pdecLeft
, const DECIMAL
* pdecRight
)
3379 static const ULONG powersOfTen
[] =
3391 static const int largestPower
= sizeof(powersOfTen
) / sizeof(powersOfTen
[0]);
3392 if (!pdecLeft
|| !pdecRight
)
3397 // Degenerate case - at least one comparand is of the form
3398 // [+-]0*10^N (denormalized zero)
3399 bool bLeftZero
= (!pdecLeft
->Lo64
&& !pdecLeft
->Hi32
);
3400 bool bRightZero
= (!pdecRight
->Lo64
&& !pdecRight
->Hi32
);
3401 if (bLeftZero
&& bRightZero
)
3405 bool bLeftNeg
= ((pdecLeft
->sign
& DECIMAL_NEG
) != 0);
3406 bool bRightNeg
= ((pdecRight
->sign
& DECIMAL_NEG
) != 0);
3409 return (bRightNeg
? VARCMP_GT
: VARCMP_LT
);
3411 // This also covers the case where the comparands have different signs
3412 if (bRightZero
|| bLeftNeg
!= bRightNeg
)
3414 return (bLeftNeg
? VARCMP_LT
: VARCMP_GT
);
3417 // Here both comparands have the same sign and need to be compared
3418 // on mantissa and scale. The result is obvious when
3419 // 1. Scales are equal (then compare mantissas)
3420 // 2. A number with smaller scale is also the one with larger mantissa
3421 // (then this number is obviously larger)
3422 // In the remaining case, we would multiply the number with smaller
3423 // scale by 10 and simultaneously increment its scale (which amounts to
3424 // adding trailing zeros after decimal point), until the numbers fall under
3425 // one of the two cases above
3427 bool bInvert
= bLeftNeg
; // the final result needs to be inverted
3428 if (pdecLeft
->scale
< pdecRight
->scale
)
3435 pdecRight
= pdecLeft
;
3439 // Now temp is the number with smaller (or equal) scale, and
3440 // we can modify it freely without touching original parameters
3442 while ((comp
= CompareMantissas(temp
, *pdecRight
)) < 0 &&
3443 temp
.scale
< pdecRight
->scale
)
3445 // Multiply by an appropriate power of 10
3446 int scaleDiff
= pdecRight
->scale
- temp
.scale
;
3447 if (scaleDiff
> largestPower
)
3449 // Keep the multiplier representable in 32bit
3450 scaleDiff
= largestPower
;
3452 DWORDLONG power
= powersOfTen
[scaleDiff
- 1];
3453 // Multiply temp's mantissa by power
3454 DWORDLONG product
= temp
.Lo32
* power
;
3455 ULONG carry
= static_cast<ULONG
>(product
>> 32);
3456 temp
.Lo32
= static_cast<ULONG
>(product
);
3457 product
= temp
.Mid32
* power
+ carry
;
3458 carry
= static_cast<ULONG
>(product
>> 32);
3459 temp
.Mid32
= static_cast<ULONG
>(product
);
3460 product
= temp
.Hi32
* power
+ carry
;
3461 if (static_cast<ULONG
>(product
>> 32))
3463 // Multiplication overflowed - pdecLeft is clearly larger
3466 temp
.Hi32
= static_cast<ULONG
>(product
);
3467 temp
.scale
= (BYTE
)(temp
.scale
+ scaleDiff
);
3469 if (temp
.scale
< pdecRight
->scale
)
3477 return (comp
> 0 ? VARCMP_GT
: comp
< 0 ? VARCMP_LT
: VARCMP_EQ
);
3480 static int CALLBACK
LVCompareDecimal(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3482 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3484 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3485 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3486 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3488 int nRet
= (int)VarDecCmp(&pParam1
->decValue
, &pParam2
->decValue
);
3490 return pInfo
->bDescending
? -nRet
: nRet
;
3492 #endif // !_WIN32_WCE
3494 BEGIN_MSG_MAP(CSortListViewImpl
)
3495 MESSAGE_HANDLER(LVM_INSERTCOLUMN
, OnInsertColumn
)
3496 MESSAGE_HANDLER(LVM_DELETECOLUMN
, OnDeleteColumn
)
3497 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA
, OnHeaderItemClick
)
3498 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW
, OnHeaderItemClick
)
3499 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChange
)
3502 LRESULT
OnInsertColumn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
3504 T
* pT
= static_cast<T
*>(this);
3505 LRESULT lRet
= pT
->DefWindowProc(uMsg
, wParam
, lParam
);
3510 m_arrColSortType
.Add(wType
);
3511 int nCount
= m_arrColSortType
.GetSize();
3512 ATLASSERT(nCount
== GetColumnCount());
3514 for(int i
= nCount
- 1; i
> lRet
; i
--)
3515 m_arrColSortType
[i
] = m_arrColSortType
[i
- 1];
3516 m_arrColSortType
[(int)lRet
] = LVCOLSORT_TEXT
;
3518 if(lRet
<= m_iSortColumn
)
3524 LRESULT
OnDeleteColumn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
3526 T
* pT
= static_cast<T
*>(this);
3527 LRESULT lRet
= pT
->DefWindowProc(uMsg
, wParam
, lParam
);
3531 int iCol
= (int)wParam
;
3532 if(m_iSortColumn
== iCol
)
3534 else if(m_iSortColumn
> iCol
)
3536 m_arrColSortType
.RemoveAt(iCol
);
3541 LRESULT
OnHeaderItemClick(int /*idCtrl*/, LPNMHDR pnmh
, BOOL
& bHandled
)
3543 LPNMHEADER p
= (LPNMHEADER
)pnmh
;
3546 int iOld
= m_iSortColumn
;
3547 bool bDescending
= (m_iSortColumn
== p
->iItem
) ? !m_bSortDescending
: false;
3548 if(DoSortItems(p
->iItem
, bDescending
))
3549 NotifyParentSortChanged(p
->iItem
, iOld
);
3555 LRESULT
OnSettingChange(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
3558 if(wParam
== SPI_SETNONCLIENTMETRICS
)
3559 GetSystemSettings();
3560 #else // CE specific
3561 wParam
; // avoid level 4 warning
3562 GetSystemSettings();
3563 #endif // _WIN32_WCE
3568 void GetSystemSettings()
3570 if(!m_bCommCtrl6
&& !m_bmSort
[m_iSortUp
].IsNull())
3572 T
* pT
= static_cast<T
*>(this);
3573 pT
->CreateSortBitmaps();
3574 if(m_iSortColumn
!= -1)
3575 SetSortColumn(m_iSortColumn
);
3582 typedef ATL::CWinTraits
<WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| LVS_REPORT
| LVS_SHOWSELALWAYS
, WS_EX_CLIENTEDGE
> CSortListViewCtrlTraits
;
3584 template <class T
, class TBase
= CListViewCtrl
, class TWinTraits
= CSortListViewCtrlTraits
>
3585 class ATL_NO_VTABLE CSortListViewCtrlImpl
: public ATL::CWindowImpl
<T
, TBase
, TWinTraits
>, public CSortListViewImpl
<T
>
3588 DECLARE_WND_SUPERCLASS(NULL
, TBase::GetWndClassName())
3590 bool SortItems(int iCol
, bool bDescending
= false)
3592 return DoSortItems(iCol
, bDescending
);
3595 BEGIN_MSG_MAP(CSortListViewCtrlImpl
)
3596 MESSAGE_HANDLER(LVM_INSERTCOLUMN
, CSortListViewImpl
<T
>::OnInsertColumn
)
3597 MESSAGE_HANDLER(LVM_DELETECOLUMN
, CSortListViewImpl
<T
>::OnDeleteColumn
)
3598 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA
, CSortListViewImpl
<T
>::OnHeaderItemClick
)
3599 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW
, CSortListViewImpl
<T
>::OnHeaderItemClick
)
3600 MESSAGE_HANDLER(WM_SETTINGCHANGE
, CSortListViewImpl
<T
>::OnSettingChange
)
3604 class CSortListViewCtrl
: public CSortListViewCtrlImpl
<CSortListViewCtrl
>
3607 DECLARE_WND_SUPERCLASS(_T("WTL_SortListViewCtrl"), GetWndClassName())
3611 ///////////////////////////////////////////////////////////////////////////////
3612 // CTabView - implements tab view window
3614 // TabView Notifications
3615 #define TBVN_PAGEACTIVATED (0U-741)
3616 #define TBVN_CONTEXTMENU (0U-742)
3618 // Notification data for TBVN_CONTEXTMENU
3619 struct TBVCONTEXTMENUINFO
3625 typedef TBVCONTEXTMENUINFO
* LPTBVCONTEXTMENUINFO
;
3628 template <class T
, class TBase
= ATL::CWindow
, class TWinTraits
= ATL::CControlWinTraits
>
3629 class ATL_NO_VTABLE CTabViewImpl
: public ATL::CWindowImpl
<T
, TBase
, TWinTraits
>
3632 DECLARE_WND_CLASS_EX(NULL
, 0, COLOR_APPWORKSPACE
)
3634 // Declarations and enums
3644 TCITEMHEADER tciheader
;
3647 operator LPTCITEM() { return (LPTCITEM
)this; }
3655 m_nMenuItemsMax
= (ID_WINDOW_TABLAST
- ID_WINDOW_TABFIRST
+ 1)
3659 ATL::CContainedWindowT
<CTabCtrl
> m_tab
;
3665 POINT m_ptStartDrag
;
3669 int m_cchTabTextLength
;
3671 int m_nMenuItemsCount
;
3673 ATL::CWindow m_wndTitleBar
;
3674 LPTSTR m_lpstrTitleBarBase
;
3675 int m_cchTitleBarLength
;
3677 CImageList m_ilDrag
;
3679 bool m_bDestroyPageOnRemove
:1;
3680 bool m_bDestroyImageList
:1;
3681 bool m_bActivePageMenuItem
:1;
3682 bool m_bActiveAsDefaultMenuItem
:1;
3683 bool m_bEmptyMenuItem
:1;
3684 bool m_bWindowsMenuItem
:1;
3686 bool m_bTabCapture
:1;
3689 // Constructor/destructor
3695 m_cchTabTextLength(30),
3696 m_nMenuItemsCount(10),
3697 m_lpstrTitleBarBase(NULL
),
3698 m_cchTitleBarLength(100),
3699 m_bDestroyPageOnRemove(true),
3700 m_bDestroyImageList(true),
3701 m_bActivePageMenuItem(true),
3702 m_bActiveAsDefaultMenuItem(false),
3703 m_bEmptyMenuItem(false),
3704 m_bWindowsMenuItem(false),
3705 m_bTabCapture(false),
3708 m_ptStartDrag
.x
= 0;
3709 m_ptStartDrag
.y
= 0;
3714 delete [] m_lpstrTitleBarBase
;
3717 // Message filter function - to be called from PreTranslateMessage of the main window
3718 BOOL
PreTranslateMessage(MSG
* pMsg
)
3720 if(IsWindow() == FALSE
)
3725 // Check for TabView built-in accelerators (Ctrl+Tab/Ctrl+Shift+Tab - next/previous page)
3726 int nCount
= GetPageCount();
3729 bool bControl
= (::GetKeyState(VK_CONTROL
) < 0);
3730 if((pMsg
->message
== WM_KEYDOWN
) && (pMsg
->wParam
== VK_TAB
) && bControl
)
3734 int nPage
= m_nActivePage
;
3735 bool bShift
= (::GetKeyState(VK_SHIFT
) < 0);
3737 nPage
= (nPage
> 0) ? (nPage
- 1) : (nCount
- 1);
3739 nPage
= ((nPage
>= 0) && (nPage
< (nCount
- 1))) ? (nPage
+ 1) : 0;
3741 SetActivePage(nPage
);
3742 T
* pT
= static_cast<T
*>(this);
3743 pT
->OnPageActivated(m_nActivePage
);
3750 // If we are doing drag-drop, check for Escape key that cancels it
3753 if(m_bTabCapture
&& pMsg
->message
== WM_KEYDOWN
&& pMsg
->wParam
== VK_ESCAPE
)
3760 // Pass the message to the active page
3763 if(m_nActivePage
!= -1)
3764 bRet
= (BOOL
)::SendMessage(GetPageHWND(m_nActivePage
), WM_FORWARDMSG
, 0, (LPARAM
)pMsg
);
3771 int GetPageCount() const
3773 ATLASSERT(::IsWindow(m_hWnd
));
3774 return m_tab
.GetItemCount();
3777 int GetActivePage() const
3779 return m_nActivePage
;
3782 void SetActivePage(int nPage
)
3784 ATLASSERT(::IsWindow(m_hWnd
));
3785 ATLASSERT(IsValidPageIndex(nPage
));
3787 T
* pT
= static_cast<T
*>(this);
3791 if(m_nActivePage
!= -1)
3792 ::ShowWindow(GetPageHWND(m_nActivePage
), FALSE
);
3793 m_nActivePage
= nPage
;
3794 m_tab
.SetCurSel(m_nActivePage
);
3795 ::ShowWindow(GetPageHWND(m_nActivePage
), TRUE
);
3800 RedrawWindow(NULL
, NULL
, RDW_FRAME
| RDW_INVALIDATE
| RDW_UPDATENOW
| RDW_ALLCHILDREN
);
3802 if(::GetFocus() != m_tab
.m_hWnd
)
3803 ::SetFocus(GetPageHWND(m_nActivePage
));
3805 pT
->UpdateTitleBar();
3809 HIMAGELIST
GetImageList() const
3811 ATLASSERT(::IsWindow(m_hWnd
));
3812 return m_tab
.GetImageList();
3815 HIMAGELIST
SetImageList(HIMAGELIST hImageList
)
3817 ATLASSERT(::IsWindow(m_hWnd
));
3818 return m_tab
.SetImageList(hImageList
);
3821 void SetWindowMenu(HMENU hMenu
)
3823 ATLASSERT(::IsWindow(m_hWnd
));
3827 T
* pT
= static_cast<T
*>(this);
3831 void SetTitleBarWindow(HWND hWnd
)
3833 ATLASSERT(::IsWindow(m_hWnd
));
3835 delete [] m_lpstrTitleBarBase
;
3836 m_lpstrTitleBarBase
= NULL
;
3838 m_wndTitleBar
= hWnd
;
3842 int cchLen
= m_wndTitleBar
.GetWindowTextLength() + 1;
3843 ATLTRY(m_lpstrTitleBarBase
= new TCHAR
[cchLen
]);
3844 if(m_lpstrTitleBarBase
!= NULL
)
3846 m_wndTitleBar
.GetWindowText(m_lpstrTitleBarBase
, cchLen
);
3847 T
* pT
= static_cast<T
*>(this);
3848 pT
->UpdateTitleBar();
3853 HWND
GetPageHWND(int nPage
) const
3855 ATLASSERT(::IsWindow(m_hWnd
));
3856 ATLASSERT(IsValidPageIndex(nPage
));
3858 TCITEMEXTRA tcix
= { 0 };
3859 tcix
.tciheader
.mask
= TCIF_PARAM
;
3860 m_tab
.GetItem(nPage
, tcix
);
3862 return tcix
.tvpage
.hWnd
;
3865 LPCTSTR
GetPageTitle(int nPage
) const
3867 ATLASSERT(::IsWindow(m_hWnd
));
3868 ATLASSERT(IsValidPageIndex(nPage
));
3870 TCITEMEXTRA tcix
= { 0 };
3871 tcix
.tciheader
.mask
= TCIF_PARAM
;
3872 if(m_tab
.GetItem(nPage
, tcix
) == FALSE
)
3875 return tcix
.tvpage
.lpstrTitle
;
3878 bool SetPageTitle(int nPage
, LPCTSTR lpstrTitle
)
3880 ATLASSERT(::IsWindow(m_hWnd
));
3881 ATLASSERT(IsValidPageIndex(nPage
));
3883 T
* pT
= static_cast<T
*>(this);
3885 int cchBuff
= lstrlen(lpstrTitle
) + 1;
3886 LPTSTR lpstrBuff
= NULL
;
3887 ATLTRY(lpstrBuff
= new TCHAR
[cchBuff
]);
3888 if(lpstrBuff
== NULL
)
3891 SecureHelper::strcpy_x(lpstrBuff
, cchBuff
, lpstrTitle
);
3892 TCITEMEXTRA tcix
= { 0 };
3893 tcix
.tciheader
.mask
= TCIF_PARAM
;
3894 if(m_tab
.GetItem(nPage
, tcix
) == FALSE
)
3897 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
3898 LPTSTR lpstrTabText
= buff
.Allocate(m_cchTabTextLength
+ 1);
3899 if(lpstrTabText
== NULL
)
3902 delete [] tcix
.tvpage
.lpstrTitle
;
3904 pT
->ShortenTitle(lpstrTitle
, lpstrTabText
, m_cchTabTextLength
+ 1);
3906 tcix
.tciheader
.mask
= TCIF_TEXT
| TCIF_PARAM
;
3907 tcix
.tciheader
.pszText
= lpstrTabText
;
3908 tcix
.tvpage
.lpstrTitle
= lpstrBuff
;
3909 if(m_tab
.SetItem(nPage
, tcix
) == FALSE
)
3912 pT
->UpdateTitleBar();
3918 LPVOID
GetPageData(int nPage
) const
3920 ATLASSERT(::IsWindow(m_hWnd
));
3921 ATLASSERT(IsValidPageIndex(nPage
));
3923 TCITEMEXTRA tcix
= { 0 };
3924 tcix
.tciheader
.mask
= TCIF_PARAM
;
3925 m_tab
.GetItem(nPage
, tcix
);
3927 return tcix
.tvpage
.pData
;
3930 LPVOID
SetPageData(int nPage
, LPVOID pData
)
3932 ATLASSERT(::IsWindow(m_hWnd
));
3933 ATLASSERT(IsValidPageIndex(nPage
));
3935 TCITEMEXTRA tcix
= { 0 };
3936 tcix
.tciheader
.mask
= TCIF_PARAM
;
3937 m_tab
.GetItem(nPage
, tcix
);
3938 LPVOID pDataOld
= tcix
.tvpage
.pData
;
3940 tcix
.tvpage
.pData
= pData
;
3941 m_tab
.SetItem(nPage
, tcix
);
3946 int GetPageImage(int nPage
) const
3948 ATLASSERT(::IsWindow(m_hWnd
));
3949 ATLASSERT(IsValidPageIndex(nPage
));
3951 TCITEMEXTRA tcix
= { 0 };
3952 tcix
.tciheader
.mask
= TCIF_IMAGE
;
3953 m_tab
.GetItem(nPage
, tcix
);
3955 return tcix
.tciheader
.iImage
;
3958 int SetPageImage(int nPage
, int nImage
)
3960 ATLASSERT(::IsWindow(m_hWnd
));
3961 ATLASSERT(IsValidPageIndex(nPage
));
3963 TCITEMEXTRA tcix
= { 0 };
3964 tcix
.tciheader
.mask
= TCIF_IMAGE
;
3965 m_tab
.GetItem(nPage
, tcix
);
3966 int nImageOld
= tcix
.tciheader
.iImage
;
3968 tcix
.tciheader
.iImage
= nImage
;
3969 m_tab
.SetItem(nPage
, tcix
);
3975 bool AddPage(HWND hWndView
, LPCTSTR lpstrTitle
, int nImage
= -1, LPVOID pData
= NULL
)
3977 return InsertPage(GetPageCount(), hWndView
, lpstrTitle
, nImage
, pData
);
3980 bool InsertPage(int nPage
, HWND hWndView
, LPCTSTR lpstrTitle
, int nImage
= -1, LPVOID pData
= NULL
)
3982 ATLASSERT(::IsWindow(m_hWnd
));
3983 ATLASSERT(nPage
== GetPageCount() || IsValidPageIndex(nPage
));
3985 T
* pT
= static_cast<T
*>(this);
3987 int cchBuff
= lstrlen(lpstrTitle
) + 1;
3988 LPTSTR lpstrBuff
= NULL
;
3989 ATLTRY(lpstrBuff
= new TCHAR
[cchBuff
]);
3990 if(lpstrBuff
== NULL
)
3993 SecureHelper::strcpy_x(lpstrBuff
, cchBuff
, lpstrTitle
);
3995 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
3996 LPTSTR lpstrTabText
= buff
.Allocate(m_cchTabTextLength
+ 1);
3997 if(lpstrTabText
== NULL
)
4000 pT
->ShortenTitle(lpstrTitle
, lpstrTabText
, m_cchTabTextLength
+ 1);
4004 TCITEMEXTRA tcix
= { 0 };
4005 tcix
.tciheader
.mask
= TCIF_TEXT
| TCIF_IMAGE
| TCIF_PARAM
;
4006 tcix
.tciheader
.pszText
= lpstrTabText
;
4007 tcix
.tciheader
.iImage
= nImage
;
4008 tcix
.tvpage
.hWnd
= hWndView
;
4009 tcix
.tvpage
.lpstrTitle
= lpstrBuff
;
4010 tcix
.tvpage
.pData
= pData
;
4011 int nItem
= m_tab
.InsertItem(nPage
, tcix
);
4014 delete [] lpstrBuff
;
4019 SetActivePage(nItem
);
4020 pT
->OnPageActivated(m_nActivePage
);
4022 if(GetPageCount() == 1)
4023 pT
->ShowTabControl(true);
4028 RedrawWindow(NULL
, NULL
, RDW_FRAME
| RDW_INVALIDATE
| RDW_UPDATENOW
| RDW_ALLCHILDREN
);
4033 void RemovePage(int nPage
)
4035 ATLASSERT(::IsWindow(m_hWnd
));
4036 ATLASSERT(IsValidPageIndex(nPage
));
4038 T
* pT
= static_cast<T
*>(this);
4042 if(GetPageCount() == 1)
4043 pT
->ShowTabControl(false);
4045 if(m_bDestroyPageOnRemove
)
4046 ::DestroyWindow(GetPageHWND(nPage
));
4048 ::ShowWindow(GetPageHWND(nPage
), FALSE
);
4049 LPTSTR lpstrTitle
= (LPTSTR
)GetPageTitle(nPage
);
4050 delete [] lpstrTitle
;
4052 ATLVERIFY(m_tab
.DeleteItem(nPage
) != FALSE
);
4054 if(m_nActivePage
== nPage
)
4060 SetActivePage(nPage
- 1);
4062 else if(GetPageCount() > 0)
4064 SetActivePage(nPage
);
4071 pT
->UpdateTitleBar();
4077 nPage
= (nPage
< m_nActivePage
) ? (m_nActivePage
- 1) : m_nActivePage
;
4079 SetActivePage(nPage
);
4082 pT
->OnPageActivated(m_nActivePage
);
4085 void RemoveAllPages()
4087 ATLASSERT(::IsWindow(m_hWnd
));
4089 if(GetPageCount() == 0)
4092 T
* pT
= static_cast<T
*>(this);
4096 pT
->ShowTabControl(false);
4098 for(int i
= 0; i
< GetPageCount(); i
++)
4100 if(m_bDestroyPageOnRemove
)
4101 ::DestroyWindow(GetPageHWND(i
));
4103 ::ShowWindow(GetPageHWND(i
), FALSE
);
4104 LPTSTR lpstrTitle
= (LPTSTR
)GetPageTitle(i
);
4105 delete [] lpstrTitle
;
4107 m_tab
.DeleteAllItems();
4110 pT
->OnPageActivated(m_nActivePage
);
4116 pT
->UpdateTitleBar();
4120 int PageIndexFromHwnd(HWND hWnd
) const
4124 for(int i
= 0; i
< GetPageCount(); i
++)
4126 if(GetPageHWND(i
) == hWnd
)
4136 void BuildWindowMenu(HMENU hMenu
, int nMenuItemsCount
= 10, bool bEmptyMenuItem
= true, bool bWindowsMenuItem
= true, bool bActivePageMenuItem
= true, bool bActiveAsDefaultMenuItem
= false)
4138 ATLASSERT(::IsWindow(m_hWnd
));
4140 CMenuHandle menu
= hMenu
;
4141 T
* pT
= static_cast<T
*>(this);
4142 pT
; // avoid level 4 warning
4145 // Find first menu item in our range
4147 for(nFirstPos
= 0; nFirstPos
< menu
.GetMenuItemCount(); nFirstPos
++)
4149 UINT nID
= menu
.GetMenuItemID(nFirstPos
);
4150 if((nID
>= ID_WINDOW_TABFIRST
&& nID
<= ID_WINDOW_TABLAST
) || nID
== ID_WINDOW_SHOWTABLIST
)
4153 #else // CE specific
4154 for(nFirstPos
= 0; ; nFirstPos
++)
4157 mii
.fMask
= MIIM_ID
;
4158 BOOL bRet
= menu
.GetMenuItemInfo(nFirstPos
, TRUE
, &mii
);
4161 if((mii
.wID
>= ID_WINDOW_TABFIRST
&& mii
.wID
<= ID_WINDOW_TABLAST
) || mii
.wID
== ID_WINDOW_SHOWTABLIST
)
4164 #endif // _WIN32_WCE
4166 // Remove all menu items for tab pages
4168 while(bRet
!= FALSE
)
4169 bRet
= menu
.DeleteMenu(nFirstPos
, MF_BYPOSITION
);
4171 // Add separator if it's not already there
4172 int nPageCount
= GetPageCount();
4173 if((bWindowsMenuItem
|| (nPageCount
> 0)) && (nFirstPos
> 0))
4176 mii
.fMask
= MIIM_TYPE
;
4177 menu
.GetMenuItemInfo(nFirstPos
- 1, TRUE
, &mii
);
4178 if((nFirstPos
<= 0) || ((mii
.fType
& MFT_SEPARATOR
) == 0))
4180 menu
.AppendMenu(MF_SEPARATOR
);
4185 // Add menu items for all pages
4188 // Append menu items for all pages
4189 const int cchPrefix
= 3; // 2 digits + space
4190 nMenuItemsCount
= __min(min(nPageCount
, nMenuItemsCount
), (int)m_nMenuItemsMax
);
4191 ATLASSERT(nMenuItemsCount
< 100); // 2 digits only
4192 if(nMenuItemsCount
>= 100)
4193 nMenuItemsCount
= 99;
4195 for(int i
= 0; i
< nMenuItemsCount
; i
++)
4197 LPCTSTR lpstrTitle
= GetPageTitle(i
);
4198 int nLen
= lstrlen(lpstrTitle
);
4199 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
4200 LPTSTR lpstrText
= buff
.Allocate(cchPrefix
+ nLen
+ 1);
4201 ATLASSERT(lpstrText
!= NULL
);
4202 if(lpstrText
!= NULL
)
4204 LPCTSTR lpstrFormat
= (i
< 9) ? _T("&%i %s") : _T("%i %s");
4205 SecureHelper::wsprintf_x(lpstrText
, cchPrefix
+ nLen
+ 1, lpstrFormat
, i
+ 1, lpstrTitle
);
4206 menu
.AppendMenu(MF_STRING
, ID_WINDOW_TABFIRST
+ i
, lpstrText
);
4211 if(bActivePageMenuItem
&& (m_nActivePage
!= -1))
4214 if(bActiveAsDefaultMenuItem
)
4216 menu
.SetMenuDefaultItem((UINT
)-1, TRUE
);
4217 menu
.SetMenuDefaultItem(nFirstPos
+ m_nActivePage
, TRUE
);
4220 #else // CE specific
4221 bActiveAsDefaultMenuItem
; // avoid level 4 warning
4222 #endif // _WIN32_WCE
4224 menu
.CheckMenuRadioItem(nFirstPos
, nFirstPos
+ nMenuItemsCount
, nFirstPos
+ m_nActivePage
, MF_BYPOSITION
);
4232 menu
.AppendMenu(MF_BYPOSITION
| MF_STRING
, ID_WINDOW_TABFIRST
, pT
->GetEmptyListText());
4233 menu
.EnableMenuItem(ID_WINDOW_TABFIRST
, MF_GRAYED
);
4236 // Remove separator if nothing else is there
4237 if(!bEmptyMenuItem
&& !bWindowsMenuItem
&& (nFirstPos
> 0))
4240 mii
.fMask
= MIIM_TYPE
;
4241 menu
.GetMenuItemInfo(nFirstPos
- 1, TRUE
, &mii
);
4242 if((mii
.fType
& MFT_SEPARATOR
) != 0)
4243 menu
.DeleteMenu(nFirstPos
- 1, MF_BYPOSITION
);
4247 // Add "Windows..." menu item
4248 if(bWindowsMenuItem
)
4249 menu
.AppendMenu(MF_BYPOSITION
| MF_STRING
, ID_WINDOW_SHOWTABLIST
, pT
->GetWindowsMenuItemText());
4252 // Message map and handlers
4253 BEGIN_MSG_MAP(CTabViewImpl
)
4254 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
4255 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
4256 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
4257 MESSAGE_HANDLER(WM_SETFOCUS
, OnSetFocus
)
4258 NOTIFY_HANDLER(m_nTabID
, TCN_SELCHANGE
, OnTabChanged
)
4259 NOTIFY_ID_HANDLER(m_nTabID
, OnTabNotification
)
4261 NOTIFY_CODE_HANDLER(TTN_GETDISPINFO
, OnTabGetDispInfo
)
4262 #endif // !_WIN32_WCE
4263 FORWARD_NOTIFICATIONS()
4264 ALT_MSG_MAP(1) // tab control
4265 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnTabLButtonDown
)
4266 MESSAGE_HANDLER(WM_LBUTTONUP
, OnTabLButtonUp
)
4267 MESSAGE_HANDLER(WM_CAPTURECHANGED
, OnTabCaptureChanged
)
4268 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnTabMouseMove
)
4269 MESSAGE_HANDLER(WM_RBUTTONUP
, OnTabRButtonUp
)
4270 MESSAGE_HANDLER(WM_SYSKEYDOWN
, OnTabSysKeyDown
)
4273 LRESULT
OnCreate(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
4275 T
* pT
= static_cast<T
*>(this);
4276 pT
->CreateTabControl();
4281 LRESULT
OnDestroy(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
4285 if(m_bDestroyImageList
)
4287 CImageList il
= m_tab
.SetImageList(NULL
);
4288 if(il
.m_hImageList
!= NULL
)
4295 LRESULT
OnSize(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
4297 T
* pT
= static_cast<T
*>(this);
4302 LRESULT
OnSetFocus(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
4304 if(m_nActivePage
!= -1)
4305 ::SetFocus(GetPageHWND(m_nActivePage
));
4309 LRESULT
OnTabChanged(int /*idCtrl*/, LPNMHDR
/*pnmh*/, BOOL
& /*bHandled*/)
4311 SetActivePage(m_tab
.GetCurSel());
4312 T
* pT
= static_cast<T
*>(this);
4313 pT
->OnPageActivated(m_nActivePage
);
4318 LRESULT
OnTabNotification(int /*idCtrl*/, LPNMHDR
/*pnmh*/, BOOL
& /*bHandled*/)
4320 // nothing to do - this just blocks all tab control
4321 // notifications from being propagated further
4326 LRESULT
OnTabGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh
, BOOL
& bHandled
)
4328 LPNMTTDISPINFO pTTDI
= (LPNMTTDISPINFO
)pnmh
;
4329 if(pTTDI
->hdr
.hwndFrom
== m_tab
.GetTooltips())
4331 T
* pT
= static_cast<T
*>(this);
4332 pT
->UpdateTooltipText(pTTDI
);
4341 #endif // !_WIN32_WCE
4343 // Tab control message handlers
4344 LRESULT
OnTabLButtonDown(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
4346 if(m_tab
.GetItemCount() > 1)
4348 m_bTabCapture
= true;
4351 m_ptStartDrag
.x
= GET_X_LPARAM(lParam
);
4352 m_ptStartDrag
.y
= GET_Y_LPARAM(lParam
);
4359 LRESULT
OnTabLButtonUp(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
4365 TCHITTESTINFO hti
= { 0 };
4366 hti
.pt
.x
= GET_X_LPARAM(lParam
);
4367 hti
.pt
.y
= GET_Y_LPARAM(lParam
);
4368 int nItem
= m_tab
.HitTest(&hti
);
4370 MovePage(m_nActivePage
, nItem
);
4380 LRESULT
OnTabCaptureChanged(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
4384 m_bTabCapture
= false;
4389 T
* pT
= static_cast<T
*>(this);
4390 pT
->DrawMoveMark(-1);
4393 m_ilDrag
.DragLeave(GetDesktopWindow());
4394 #endif // !_WIN32_WCE
4398 m_ilDrag
.m_hImageList
= NULL
;
4406 LRESULT
OnTabMouseMove(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
4412 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
4417 if(abs(m_ptStartDrag
.x
- GET_X_LPARAM(lParam
)) >= ::GetSystemMetrics(SM_CXDRAG
) ||
4418 abs(m_ptStartDrag
.y
- GET_Y_LPARAM(lParam
)) >= ::GetSystemMetrics(SM_CYDRAG
))
4419 #else // CE specific
4420 if(abs(m_ptStartDrag
.x
- GET_X_LPARAM(lParam
)) >= 4 ||
4421 abs(m_ptStartDrag
.y
- GET_Y_LPARAM(lParam
)) >= 4)
4422 #endif // _WIN32_WCE
4424 T
* pT
= static_cast<T
*>(this);
4425 pT
->GenerateDragImage(m_nActivePage
);
4427 int cxCursor
= ::GetSystemMetrics(SM_CXCURSOR
);
4428 int cyCursor
= ::GetSystemMetrics(SM_CYCURSOR
);
4429 m_ilDrag
.BeginDrag(0, -(cxCursor
/ 2), -(cyCursor
/ 2));
4431 POINT ptEnter
= m_ptStartDrag
;
4432 m_tab
.ClientToScreen(&ptEnter
);
4433 m_ilDrag
.DragEnter(GetDesktopWindow(), ptEnter
);
4434 #endif // !_WIN32_WCE
4442 TCHITTESTINFO hti
= { 0 };
4444 int nItem
= m_tab
.HitTest(&hti
);
4446 T
* pT
= static_cast<T
*>(this);
4447 pT
->SetMoveCursor(nItem
!= -1);
4449 if(m_nInsertItem
!= nItem
)
4450 pT
->DrawMoveMark(nItem
);
4452 m_ilDrag
.DragShowNolock((nItem
!= -1) ? TRUE
: FALSE
);
4453 m_tab
.ClientToScreen(&pt
);
4454 m_ilDrag
.DragMove(pt
);
4463 LRESULT
OnTabRButtonUp(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& /*bHandled*/)
4465 TCHITTESTINFO hti
= { 0 };
4466 hti
.pt
.x
= GET_X_LPARAM(lParam
);
4467 hti
.pt
.y
= GET_Y_LPARAM(lParam
);
4468 int nItem
= m_tab
.HitTest(&hti
);
4471 T
* pT
= static_cast<T
*>(this);
4472 pT
->OnContextMenu(nItem
, hti
.pt
);
4478 LRESULT
OnTabSysKeyDown(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
4480 bool bShift
= (::GetKeyState(VK_SHIFT
) < 0);
4481 if(wParam
== VK_F10
&& bShift
)
4483 if(m_nActivePage
!= -1)
4486 m_tab
.GetItemRect(m_nActivePage
, &rect
);
4487 POINT pt
= { rect
.left
, rect
.bottom
};
4488 T
* pT
= static_cast<T
*>(this);
4489 pT
->OnContextMenu(m_nActivePage
, pt
);
4500 // Implementation helpers
4501 bool IsValidPageIndex(int nPage
) const
4503 return (nPage
>= 0 && nPage
< GetPageCount());
4506 bool MovePage(int nMovePage
, int nInsertBeforePage
)
4508 ATLASSERT(IsValidPageIndex(nMovePage
));
4509 ATLASSERT(IsValidPageIndex(nInsertBeforePage
));
4511 if(!IsValidPageIndex(nMovePage
) || !IsValidPageIndex(nInsertBeforePage
))
4514 if(nMovePage
== nInsertBeforePage
)
4515 return true; // nothing to do
4517 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
4518 LPTSTR lpstrTabText
= buff
.Allocate(m_cchTabTextLength
+ 1);
4519 if(lpstrTabText
== NULL
)
4521 TCITEMEXTRA tcix
= { 0 };
4522 tcix
.tciheader
.mask
= TCIF_TEXT
| TCIF_IMAGE
| TCIF_PARAM
;
4523 tcix
.tciheader
.pszText
= lpstrTabText
;
4524 tcix
.tciheader
.cchTextMax
= m_cchTabTextLength
+ 1;
4525 BOOL bRet
= m_tab
.GetItem(nMovePage
, tcix
);
4526 ATLASSERT(bRet
!= FALSE
);
4530 int nInsertItem
= (nInsertBeforePage
> nMovePage
) ? nInsertBeforePage
+ 1 : nInsertBeforePage
;
4531 int nNewItem
= m_tab
.InsertItem(nInsertItem
, tcix
);
4532 ATLASSERT(nNewItem
== nInsertItem
);
4533 if(nNewItem
!= nInsertItem
)
4535 ATLVERIFY(m_tab
.DeleteItem(nNewItem
));
4539 if(nMovePage
> nInsertBeforePage
)
4540 ATLVERIFY(m_tab
.DeleteItem(nMovePage
+ 1) != FALSE
);
4541 else if(nMovePage
< nInsertBeforePage
)
4542 ATLVERIFY(m_tab
.DeleteItem(nMovePage
) != FALSE
);
4544 SetActivePage(nInsertBeforePage
);
4545 T
* pT
= static_cast<T
*>(this);
4546 pT
->OnPageActivated(m_nActivePage
);
4551 // Implementation overrideables
4552 bool CreateTabControl()
4555 m_tab
.Create(m_hWnd
, rcDefault
, NULL
, WS_CHILD
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| TCS_TOOLTIPS
, 0, m_nTabID
);
4556 #else // CE specific
4557 m_tab
.Create(m_hWnd
, rcDefault
, NULL
, WS_CHILD
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
, 0, m_nTabID
);
4558 #endif // _WIN32_WCE
4559 ATLASSERT(m_tab
.m_hWnd
!= NULL
);
4560 if(m_tab
.m_hWnd
== NULL
)
4563 m_tab
.SetFont(AtlGetDefaultGuiFont());
4565 m_tab
.SetItemExtra(sizeof(TABVIEWPAGE
));
4567 T
* pT
= static_cast<T
*>(this);
4568 m_cyTabHeight
= pT
->CalcTabHeight();
4575 int nCount
= m_tab
.GetItemCount();
4576 TCITEMEXTRA tcix
= { 0 };
4577 tcix
.tciheader
.mask
= TCIF_TEXT
;
4578 tcix
.tciheader
.pszText
= _T("NS");
4579 int nIndex
= m_tab
.InsertItem(nCount
, tcix
);
4581 RECT rect
= { 0, 0, 1000, 1000 };
4582 m_tab
.AdjustRect(FALSE
, &rect
);
4584 RECT rcWnd
= { 0, 0, 1000, rect
.top
};
4585 ::AdjustWindowRectEx(&rcWnd
, m_tab
.GetStyle(), FALSE
, m_tab
.GetExStyle());
4587 int nHeight
= rcWnd
.bottom
- rcWnd
.top
;
4589 m_tab
.DeleteItem(nIndex
);
4594 void ShowTabControl(bool bShow
)
4596 m_tab
.ShowWindow(bShow
? SW_SHOWNOACTIVATE
: SW_HIDE
);
4602 GetClientRect(&rect
);
4604 if(m_tab
.IsWindow() && ((m_tab
.GetStyle() & WS_VISIBLE
) != 0))
4605 m_tab
.SetWindowPos(NULL
, 0, 0, rect
.right
- rect
.left
, m_cyTabHeight
, SWP_NOZORDER
);
4607 if(m_nActivePage
!= -1)
4608 ::SetWindowPos(GetPageHWND(m_nActivePage
), NULL
, 0, m_cyTabHeight
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
- m_cyTabHeight
, SWP_NOZORDER
);
4613 if(m_menu
.m_hMenu
!= NULL
)
4614 BuildWindowMenu(m_menu
, m_nMenuItemsCount
, m_bEmptyMenuItem
, m_bWindowsMenuItem
, m_bActivePageMenuItem
, m_bActiveAsDefaultMenuItem
);
4617 void UpdateTitleBar()
4619 if(!m_wndTitleBar
.IsWindow() || m_lpstrTitleBarBase
== NULL
)
4620 return; // nothing to do
4622 if(m_nActivePage
!= -1)
4624 T
* pT
= static_cast<T
*>(this);
4625 LPCTSTR lpstrTitle
= pT
->GetPageTitle(m_nActivePage
);
4626 LPCTSTR lpstrDivider
= pT
->GetTitleDividerText();
4627 int cchBuffer
= m_cchTitleBarLength
+ lstrlen(lpstrDivider
) + lstrlen(m_lpstrTitleBarBase
) + 1;
4628 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
4629 LPTSTR lpstrPageTitle
= buff
.Allocate(cchBuffer
);
4630 ATLASSERT(lpstrPageTitle
!= NULL
);
4631 if(lpstrPageTitle
!= NULL
)
4633 pT
->ShortenTitle(lpstrTitle
, lpstrPageTitle
, m_cchTitleBarLength
+ 1);
4634 SecureHelper::strcat_x(lpstrPageTitle
, cchBuffer
, lpstrDivider
);
4635 SecureHelper::strcat_x(lpstrPageTitle
, cchBuffer
, m_lpstrTitleBarBase
);
4639 lpstrPageTitle
= m_lpstrTitleBarBase
;
4642 m_wndTitleBar
.SetWindowText(lpstrPageTitle
);
4646 m_wndTitleBar
.SetWindowText(m_lpstrTitleBarBase
);
4650 void DrawMoveMark(int nItem
)
4652 T
* pT
= static_cast<T
*>(this);
4654 if(m_nInsertItem
!= -1)
4657 pT
->GetMoveMarkRect(rect
);
4658 m_tab
.InvalidateRect(&rect
);
4661 m_nInsertItem
= nItem
;
4663 if(m_nInsertItem
!= -1)
4665 CClientDC
dc(m_tab
.m_hWnd
);
4668 pT
->GetMoveMarkRect(rect
);
4671 pen
.CreatePen(PS_SOLID
, 1, ::GetSysColor(COLOR_WINDOWTEXT
));
4673 brush
.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT
));
4675 HPEN hPenOld
= dc
.SelectPen(pen
);
4676 HBRUSH hBrushOld
= dc
.SelectBrush(brush
);
4680 POINT ptsTop
[3] = { { x
, y
}, { x
+ m_cxMoveMark
, y
}, { x
+ (m_cxMoveMark
/ 2), y
+ m_cyMoveMark
} };
4681 dc
.Polygon(ptsTop
, 3);
4683 y
= rect
.bottom
- 1;
4684 POINT ptsBottom
[3] = { { x
, y
}, { x
+ m_cxMoveMark
, y
}, { x
+ (m_cxMoveMark
/ 2), y
- m_cyMoveMark
} };
4685 dc
.Polygon(ptsBottom
, 3);
4687 dc
.SelectPen(hPenOld
);
4688 dc
.SelectBrush(hBrushOld
);
4692 void GetMoveMarkRect(RECT
& rect
) const
4694 m_tab
.GetClientRect(&rect
);
4696 RECT rcItem
= { 0 };
4697 m_tab
.GetItemRect(m_nInsertItem
, &rcItem
);
4699 if(m_nInsertItem
<= m_nActivePage
)
4701 rect
.left
= rcItem
.left
- m_cxMoveMark
/ 2 - 1;
4702 rect
.right
= rcItem
.left
+ m_cxMoveMark
/ 2;
4706 rect
.left
= rcItem
.right
- m_cxMoveMark
/ 2 - 1;
4707 rect
.right
= rcItem
.right
+ m_cxMoveMark
/ 2;
4711 void SetMoveCursor(bool bCanMove
)
4713 ::SetCursor(::LoadCursor(NULL
, bCanMove
? IDC_ARROW
: IDC_NO
));
4716 void GenerateDragImage(int nItem
)
4718 ATLASSERT(IsValidPageIndex(nItem
));
4721 RECT rcItem
= { 0 };
4722 m_tab
.GetItemRect(nItem
, &rcItem
);
4723 ::InflateRect(&rcItem
, 2, 2); // make bigger to cover selected item
4724 #else // CE specific
4725 nItem
; // avoid level 4 warning
4726 RECT rcItem
= { 0, 0, 40, 20 };
4727 #endif // _WIN32_WCE
4729 ATLASSERT(m_ilDrag
.m_hImageList
== NULL
);
4730 m_ilDrag
.Create(rcItem
.right
- rcItem
.left
, rcItem
.bottom
- rcItem
.top
, ILC_COLORDDB
| ILC_MASK
, 1, 1);
4732 CClientDC
dc(m_hWnd
);
4734 dcMem
.CreateCompatibleDC(dc
);
4735 ATLASSERT(dcMem
.m_hDC
!= NULL
);
4736 dcMem
.SetViewportOrg(-rcItem
.left
, -rcItem
.top
);
4739 bmp
.CreateCompatibleBitmap(dc
, rcItem
.right
- rcItem
.left
, rcItem
.bottom
- rcItem
.top
);
4740 ATLASSERT(bmp
.m_hBitmap
!= NULL
);
4742 HBITMAP hBmpOld
= dcMem
.SelectBitmap(bmp
);
4744 m_tab
.SendMessage(WM_PRINTCLIENT
, (WPARAM
)dcMem
.m_hDC
);
4745 #else // CE specific
4746 dcMem
.Rectangle(&rcItem
);
4747 #endif // _WIN32_WCE
4748 dcMem
.SelectBitmap(hBmpOld
);
4750 ATLVERIFY(m_ilDrag
.Add(bmp
.m_hBitmap
, RGB(255, 0, 255)) != -1);
4753 void ShortenTitle(LPCTSTR lpstrTitle
, LPTSTR lpstrShortTitle
, int cchShortTitle
)
4755 if(lstrlen(lpstrTitle
) >= cchShortTitle
)
4757 LPCTSTR lpstrEllipsis
= _T("...");
4758 int cchEllipsis
= lstrlen(lpstrEllipsis
);
4759 SecureHelper::strncpy_x(lpstrShortTitle
, cchShortTitle
, lpstrTitle
, cchShortTitle
- cchEllipsis
- 1);
4760 SecureHelper::strcat_x(lpstrShortTitle
, cchShortTitle
, lpstrEllipsis
);
4764 SecureHelper::strcpy_x(lpstrShortTitle
, cchShortTitle
, lpstrTitle
);
4769 void UpdateTooltipText(LPNMTTDISPINFO pTTDI
)
4771 ATLASSERT(pTTDI
!= NULL
);
4772 pTTDI
->lpszText
= (LPTSTR
)GetPageTitle((int)pTTDI
->hdr
.idFrom
);
4774 #endif // !_WIN32_WCE
4776 // Text for menu items and title bar - override to provide different strings
4777 static LPCTSTR
GetEmptyListText()
4779 return _T("(Empty)");
4782 static LPCTSTR
GetWindowsMenuItemText()
4784 return _T("&Windows...");
4787 static LPCTSTR
GetTitleDividerText()
4792 // Notifications - override to provide different behavior
4793 void OnPageActivated(int nPage
)
4795 NMHDR nmhdr
= { 0 };
4796 nmhdr
.hwndFrom
= m_hWnd
;
4797 nmhdr
.idFrom
= nPage
;
4798 nmhdr
.code
= TBVN_PAGEACTIVATED
;
4799 ::SendMessage(GetParent(), WM_NOTIFY
, GetDlgCtrlID(), (LPARAM
)&nmhdr
);
4802 void OnContextMenu(int nPage
, POINT pt
)
4804 m_tab
.ClientToScreen(&pt
);
4806 TBVCONTEXTMENUINFO cmi
= { 0 };
4807 cmi
.hdr
.hwndFrom
= m_hWnd
;
4808 cmi
.hdr
.idFrom
= nPage
;
4809 cmi
.hdr
.code
= TBVN_CONTEXTMENU
;
4811 ::SendMessage(GetParent(), WM_NOTIFY
, GetDlgCtrlID(), (LPARAM
)&cmi
);
4816 class CTabView
: public CTabViewImpl
<CTabView
>
4819 DECLARE_WND_CLASS_EX(_T("WTL_TabView"), 0, COLOR_APPWORKSPACE
)
4824 #endif // __ATLCTRLX_H__