1 // Windows Template Library - WTL version 9.0
2 // Copyright (C) Microsoft Corporation, WTL Team. 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 // Common Public License 1.0 (http://opensource.org/licenses/cpl1.0.php)
7 // which can be found in the file CPL.TXT at the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by
9 // the terms of this license. You must not remove this notice, or
10 // any other, from this software.
12 #ifndef __ATLCTRLX_H__
13 #define __ATLCTRLX_H__
18 #error atlctrlx.h requires atlapp.h to be included first
21 #ifndef __ATLCTRLS_H__
22 #error atlctrlx.h requires atlctrls.h to be included first
25 #ifndef WM_UPDATEUISTATE
26 #define WM_UPDATEUISTATE 0x0128
27 #endif // !WM_UPDATEUISTATE
30 ///////////////////////////////////////////////////////////////////////////////
31 // Classes in this file:
33 // CBitmapButtonImpl<T, TBase, TWinTraits>
35 // CCheckListViewCtrlImpl<T, TBase, TWinTraits>
37 // CHyperLinkImpl<T, TBase, TWinTraits>
41 // CMultiPaneStatusBarCtrlImpl<T, TBase>
42 // CMultiPaneStatusBarCtrl
43 // CPaneContainerImpl<T, TBase, TWinTraits>
45 // CSortListViewImpl<T>
46 // CSortListViewCtrlImpl<T, TBase, TWinTraits>
48 // CTabViewImpl<T, TBase, TWinTraits>
54 ///////////////////////////////////////////////////////////////////////////////
55 // CBitmapButton - bitmap button implementation
59 // bitmap button extended styles
60 #define BMPBTN_HOVER 0x00000001
61 #define BMPBTN_AUTO3D_SINGLE 0x00000002
62 #define BMPBTN_AUTO3D_DOUBLE 0x00000004
63 #define BMPBTN_AUTOSIZE 0x00000008
64 #define BMPBTN_SHAREIMAGELISTS 0x00000010
65 #define BMPBTN_AUTOFIRE 0x00000020
66 #define BMPBTN_CHECK 0x00000040
67 #define BMPBTN_AUTOCHECK 0x00000080
69 // Note: BMPBTN_CHECK/BMPBTN_AUTOCHECK disables BN_DOUBLECLICKED,
70 // BMPBTN_AUTOFIRE doesn't work with BMPBTN_CHECK/BMPBTN_AUTOCHECK
72 template <class T
, class TBase
= CButton
, class TWinTraits
= ATL::CControlWinTraits
>
73 class ATL_NO_VTABLE CBitmapButtonImpl
: public ATL::CWindowImpl
< T
, TBase
, TWinTraits
>
76 DECLARE_WND_SUPERCLASS(NULL
, TBase::GetWndClassName())
90 ID_TIMER_FIRST
= 1000,
91 ID_TIMER_REPEAT
= 1001
94 // Bitmap button specific extended styles
95 DWORD m_dwExtendedStyle
;
97 CImageList m_ImageList
;
98 int m_nImage
[_nImageCount
];
101 LPTSTR m_lpstrToolTipText
;
104 unsigned m_fMouseOver
:1;
106 unsigned m_fPressed
:1;
107 unsigned m_fChecked
:1;
110 // Constructor/Destructor
111 CBitmapButtonImpl(DWORD dwExtendedStyle
= BMPBTN_AUTOSIZE
, HIMAGELIST hImageList
= NULL
) :
112 m_dwExtendedStyle(dwExtendedStyle
), m_ImageList(hImageList
),
113 m_lpstrToolTipText(NULL
),
114 m_fMouseOver(0), m_fFocus(0), m_fPressed(0), m_fChecked(0)
116 m_nImage
[_nImageNormal
] = -1;
117 m_nImage
[_nImagePushed
] = -1;
118 m_nImage
[_nImageFocusOrHover
] = -1;
119 m_nImage
[_nImageDisabled
] = -1;
122 if(((m_dwExtendedStyle
& BMPBTN_AUTOFIRE
) != 0) && IsCheckMode())
123 ATLTRACE2(atlTraceUI
, 0, _T("CBitmapButtonImpl - Check mode and BMPBTN_AUTOFIRE cannot be used together, BMPBTN_AUTOFIRE will be ignored.\n"));
129 if((m_dwExtendedStyle
& BMPBTN_SHAREIMAGELISTS
) == 0)
130 m_ImageList
.Destroy();
131 delete [] m_lpstrToolTipText
;
134 // overridden to provide proper initialization
135 BOOL
SubclassWindow(HWND hWnd
)
137 #if (_MSC_VER >= 1300)
138 BOOL bRet
= ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::SubclassWindow(hWnd
);
139 #else // !(_MSC_VER >= 1300)
140 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
141 BOOL bRet
= _baseClass::SubclassWindow(hWnd
);
142 #endif // !(_MSC_VER >= 1300)
145 T
* pT
= static_cast<T
*>(this);
153 DWORD
GetBitmapButtonExtendedStyle() const
155 return m_dwExtendedStyle
;
158 DWORD
SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle
, DWORD dwMask
= 0)
160 DWORD dwPrevStyle
= m_dwExtendedStyle
;
162 m_dwExtendedStyle
= dwExtendedStyle
;
164 m_dwExtendedStyle
= (m_dwExtendedStyle
& ~dwMask
) | (dwExtendedStyle
& dwMask
);
167 if(((m_dwExtendedStyle
& BMPBTN_AUTOFIRE
) != 0) && IsCheckMode())
168 ATLTRACE2(atlTraceUI
, 0, _T("CBitmapButtonImpl - Check mode and BMPBTN_AUTOFIRE cannot be used together, BMPBTN_AUTOFIRE will be ignored.\n"));
174 HIMAGELIST
GetImageList() const
179 HIMAGELIST
SetImageList(HIMAGELIST hImageList
)
181 HIMAGELIST hImageListPrev
= m_ImageList
;
182 m_ImageList
= hImageList
;
183 if((m_dwExtendedStyle
& BMPBTN_AUTOSIZE
) != 0 && ::IsWindow(m_hWnd
))
186 return hImageListPrev
;
189 int GetToolTipTextLength() const
191 return (m_lpstrToolTipText
== NULL
) ? -1 : lstrlen(m_lpstrToolTipText
);
194 bool GetToolTipText(LPTSTR lpstrText
, int nLength
) const
196 ATLASSERT(lpstrText
!= NULL
);
197 if(m_lpstrToolTipText
== NULL
)
200 errno_t nRet
= SecureHelper::strncpy_x(lpstrText
, nLength
, m_lpstrToolTipText
, _TRUNCATE
);
202 return (nRet
== 0 || nRet
== STRUNCATE
);
205 bool SetToolTipText(LPCTSTR lpstrText
)
207 if(m_lpstrToolTipText
!= NULL
)
209 delete [] m_lpstrToolTipText
;
210 m_lpstrToolTipText
= NULL
;
213 if(lpstrText
== NULL
)
216 m_tip
.Activate(FALSE
);
220 int cchLen
= lstrlen(lpstrText
) + 1;
221 ATLTRY(m_lpstrToolTipText
= new TCHAR
[cchLen
]);
222 if(m_lpstrToolTipText
== NULL
)
225 SecureHelper::strcpy_x(m_lpstrToolTipText
, cchLen
, lpstrText
);
228 m_tip
.Activate(TRUE
);
229 m_tip
.AddTool(m_hWnd
, m_lpstrToolTipText
);
235 bool GetCheck() const
237 return (m_fChecked
== 1);
240 void SetCheck(bool bCheck
, bool bUpdate
= true)
242 m_fChecked
= bCheck
? 1 : 0;
252 void SetImages(int nNormal
, int nPushed
= -1, int nFocusOrHover
= -1, int nDisabled
= -1)
255 m_nImage
[_nImageNormal
] = nNormal
;
257 m_nImage
[_nImagePushed
] = nPushed
;
258 if(nFocusOrHover
!= -1)
259 m_nImage
[_nImageFocusOrHover
] = nFocusOrHover
;
261 m_nImage
[_nImageDisabled
] = nDisabled
;
266 ATLASSERT(::IsWindow(m_hWnd
) && m_ImageList
.m_hImageList
!= NULL
);
269 if(!m_ImageList
.GetIconSize(cx
, cy
))
271 return ResizeClient(cx
, cy
);
275 void DoPaint(CDCHandle dc
)
277 ATLASSERT(m_ImageList
.m_hImageList
!= NULL
); // image list must be set
278 ATLASSERT(m_nImage
[0] != -1); // main bitmap must be set
280 // set bitmap according to the current button state
281 bool bHover
= IsHoverMode();
282 bool bPressed
= (m_fPressed
== 1) || (IsCheckMode() && (m_fChecked
== 1));
284 if(!IsWindowEnabled())
285 nImage
= m_nImage
[_nImageDisabled
];
287 nImage
= m_nImage
[_nImagePushed
];
288 else if((!bHover
&& (m_fFocus
== 1)) || (bHover
&& (m_fMouseOver
== 1)))
289 nImage
= m_nImage
[_nImageFocusOrHover
];
291 // if none is set, use default one
293 nImage
= m_nImage
[_nImageNormal
];
295 // draw the button image
296 bool bAuto3D
= (m_dwExtendedStyle
& (BMPBTN_AUTO3D_SINGLE
| BMPBTN_AUTO3D_DOUBLE
)) != 0;
297 int xyPos
= (bPressed
&& bAuto3D
&& (m_nImage
[_nImagePushed
] == -1)) ? 1 : 0;
298 m_ImageList
.Draw(dc
, nImage
, xyPos
, xyPos
, ILD_NORMAL
);
300 // draw 3D border if required
304 GetClientRect(&rect
);
307 dc
.DrawEdge(&rect
, ((m_dwExtendedStyle
& BMPBTN_AUTO3D_SINGLE
) != 0) ? BDR_SUNKENOUTER
: EDGE_SUNKEN
, BF_RECT
);
308 else if(!bHover
|| (m_fMouseOver
== 1))
309 dc
.DrawEdge(&rect
, ((m_dwExtendedStyle
& BMPBTN_AUTO3D_SINGLE
) != 0) ? BDR_RAISEDINNER
: EDGE_RAISED
, BF_RECT
);
311 if(!bHover
&& (m_fFocus
== 1))
313 ::InflateRect(&rect
, -2 * ::GetSystemMetrics(SM_CXEDGE
), -2 * ::GetSystemMetrics(SM_CYEDGE
));
314 dc
.DrawFocusRect(&rect
);
319 // Message map and handlers
320 BEGIN_MSG_MAP(CBitmapButtonImpl
)
321 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
322 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
323 MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST
, WM_MOUSELAST
, OnMouseMessage
)
324 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
325 MESSAGE_HANDLER(WM_PAINT
, OnPaint
)
326 MESSAGE_HANDLER(WM_PRINTCLIENT
, OnPaint
)
327 MESSAGE_HANDLER(WM_SETFOCUS
, OnFocus
)
328 MESSAGE_HANDLER(WM_KILLFOCUS
, OnFocus
)
329 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnLButtonDown
)
330 MESSAGE_HANDLER(WM_LBUTTONDBLCLK
, OnLButtonDblClk
)
331 MESSAGE_HANDLER(WM_LBUTTONUP
, OnLButtonUp
)
332 MESSAGE_HANDLER(WM_CAPTURECHANGED
, OnCaptureChanged
)
333 MESSAGE_HANDLER(WM_ENABLE
, OnEnable
)
334 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
335 MESSAGE_HANDLER(WM_MOUSELEAVE
, OnMouseLeave
)
336 MESSAGE_HANDLER(WM_KEYDOWN
, OnKeyDown
)
337 MESSAGE_HANDLER(WM_KEYUP
, OnKeyUp
)
338 MESSAGE_HANDLER(WM_TIMER
, OnTimer
)
339 MESSAGE_HANDLER(WM_UPDATEUISTATE
, OnUpdateUiState
)
342 LRESULT
OnCreate(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
344 T
* pT
= static_cast<T
*>(this);
351 LRESULT
OnDestroy(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
355 m_tip
.DestroyWindow();
362 LRESULT
OnMouseMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
364 MSG msg
= { m_hWnd
, uMsg
, wParam
, lParam
};
366 m_tip
.RelayEvent(&msg
);
371 LRESULT
OnEraseBackground(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
373 return 1; // no background needed
376 LRESULT
OnPaint(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
378 T
* pT
= static_cast<T
*>(this);
381 pT
->DoPaint((HDC
)wParam
);
386 pT
->DoPaint(dc
.m_hDC
);
391 LRESULT
OnFocus(UINT uMsg
, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
393 m_fFocus
= (uMsg
== WM_SETFOCUS
) ? 1 : 0;
400 LRESULT
OnLButtonDown(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
406 lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
407 if(::GetCapture() == m_hWnd
)
413 if(((m_dwExtendedStyle
& BMPBTN_AUTOFIRE
) != 0) && !IsCheckMode())
417 if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY
, 0, &nDelay
, 0))
418 nElapse
+= nDelay
* 250; // all milli-seconds
419 SetTimer(ID_TIMER_FIRST
, nElapse
);
424 LRESULT
OnLButtonDblClk(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
427 if(!IsHoverMode() && !IsCheckMode())
428 lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
429 if(::GetCapture() != m_hWnd
)
440 LRESULT
OnLButtonUp(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
442 if(((m_dwExtendedStyle
& BMPBTN_AUTOCHECK
) != 0) && (m_fPressed
== 1))
443 SetCheck(!GetCheck(), false);
446 if(!IsHoverMode() && !IsCheckMode())
447 lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
448 if(::GetCapture() == m_hWnd
)
450 if((IsHoverMode() || IsCheckMode()) && (m_fPressed
== 1))
451 ::SendMessage(GetParent(), WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED
), (LPARAM
)m_hWnd
);
457 LRESULT
OnCaptureChanged(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
469 LRESULT
OnEnable(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
477 LRESULT
OnMouseMove(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
479 if(::GetCapture() == m_hWnd
)
481 POINT ptCursor
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
482 ClientToScreen(&ptCursor
);
484 GetWindowRect(&rect
);
485 unsigned int uPressed
= ::PtInRect(&rect
, ptCursor
) ? 1 : 0;
486 if(m_fPressed
!= uPressed
)
488 m_fPressed
= uPressed
;
493 else if(IsHoverMode() && m_fMouseOver
== 0)
498 StartTrackMouseLeave();
504 LRESULT
OnMouseLeave(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
506 if(m_fMouseOver
== 1)
515 LRESULT
OnKeyDown(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
517 if(wParam
== VK_SPACE
&& IsHoverMode())
518 return 0; // ignore if in hover mode
519 if(wParam
== VK_SPACE
&& m_fPressed
== 0)
529 LRESULT
OnKeyUp(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
531 if(wParam
== VK_SPACE
&& IsHoverMode())
532 return 0; // ignore if in hover mode
533 if(wParam
== VK_SPACE
&& m_fPressed
== 1)
536 if((m_dwExtendedStyle
& BMPBTN_AUTOCHECK
) != 0)
537 SetCheck(!GetCheck(), false);
545 LRESULT
OnTimer(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
547 ATLASSERT((m_dwExtendedStyle
& BMPBTN_AUTOFIRE
) != 0);
548 switch(wParam
) // timer ID
551 KillTimer(ID_TIMER_FIRST
);
554 ::SendMessage(GetParent(), WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED
), (LPARAM
)m_hWnd
);
557 if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED
, 0, &nRepeat
, 0))
558 nElapse
= 10000 / (10 * nRepeat
+ 25); // milli-seconds, approximated
559 SetTimer(ID_TIMER_REPEAT
, nElapse
);
562 case ID_TIMER_REPEAT
:
564 ::SendMessage(GetParent(), WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED
), (LPARAM
)m_hWnd
);
565 else if(::GetCapture() != m_hWnd
)
566 KillTimer(ID_TIMER_REPEAT
);
568 default: // not our timer
574 LRESULT
OnUpdateUiState(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
576 // If the control is subclassed or superclassed, this message can cause
577 // repainting without WM_PAINT. We don't use this state, so just do nothing.
584 // We need this style to prevent Windows from painting the button
585 ModifyStyle(0, BS_OWNERDRAW
);
588 m_tip
.Create(m_hWnd
);
589 ATLASSERT(m_tip
.IsWindow());
590 if(m_tip
.IsWindow() && m_lpstrToolTipText
!= NULL
)
592 m_tip
.Activate(TRUE
);
593 m_tip
.AddTool(m_hWnd
, m_lpstrToolTipText
);
596 if(m_ImageList
.m_hImageList
!= NULL
&& (m_dwExtendedStyle
& BMPBTN_AUTOSIZE
) != 0)
600 BOOL
StartTrackMouseLeave()
602 TRACKMOUSEEVENT tme
= { 0 };
603 tme
.cbSize
= sizeof(tme
);
604 tme
.dwFlags
= TME_LEAVE
;
605 tme
.hwndTrack
= m_hWnd
;
606 return _TrackMouseEvent(&tme
);
609 bool IsHoverMode() const
611 return ((m_dwExtendedStyle
& BMPBTN_HOVER
) != 0);
614 bool IsCheckMode() const
616 return ((m_dwExtendedStyle
& (BMPBTN_CHECK
| BMPBTN_AUTOCHECK
)) != 0);
620 class CBitmapButton
: public CBitmapButtonImpl
<CBitmapButton
>
623 DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName())
625 CBitmapButton(DWORD dwExtendedStyle
= BMPBTN_AUTOSIZE
, HIMAGELIST hImageList
= NULL
) :
626 CBitmapButtonImpl
<CBitmapButton
>(dwExtendedStyle
, hImageList
)
630 #endif // !_WIN32_WCE
633 ///////////////////////////////////////////////////////////////////////////////
634 // CCheckListCtrlView - list view control with check boxes
636 template <DWORD t_dwStyle
, DWORD t_dwExStyle
, DWORD t_dwExListViewStyle
>
637 class CCheckListViewCtrlImplTraits
640 static DWORD
GetWndStyle(DWORD dwStyle
)
642 return (dwStyle
== 0) ? t_dwStyle
: dwStyle
;
645 static DWORD
GetWndExStyle(DWORD dwExStyle
)
647 return (dwExStyle
== 0) ? t_dwExStyle
: dwExStyle
;
650 static DWORD
GetExtendedLVStyle()
652 return t_dwExListViewStyle
;
656 typedef CCheckListViewCtrlImplTraits
<WS_CHILD
| WS_VISIBLE
| LVS_REPORT
| LVS_SHOWSELALWAYS
, WS_EX_CLIENTEDGE
, LVS_EX_CHECKBOXES
| LVS_EX_FULLROWSELECT
> CCheckListViewCtrlTraits
;
658 template <class T
, class TBase
= CListViewCtrl
, class TWinTraits
= CCheckListViewCtrlTraits
>
659 class ATL_NO_VTABLE CCheckListViewCtrlImpl
: public ATL::CWindowImpl
<T
, TBase
, TWinTraits
>
662 DECLARE_WND_SUPERCLASS(NULL
, TBase::GetWndClassName())
665 static DWORD
GetExtendedLVStyle()
667 return TWinTraits::GetExtendedLVStyle();
671 BOOL
SubclassWindow(HWND hWnd
)
673 #if (_MSC_VER >= 1300)
674 BOOL bRet
= ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::SubclassWindow(hWnd
);
675 #else // !(_MSC_VER >= 1300)
676 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
677 BOOL bRet
= _baseClass::SubclassWindow(hWnd
);
678 #endif // !(_MSC_VER >= 1300)
681 T
* pT
= static_cast<T
*>(this);
688 void CheckSelectedItems(int nCurrItem
)
690 // first check if this item is selected
692 lvi
.iItem
= nCurrItem
;
694 lvi
.mask
= LVIF_STATE
;
695 lvi
.stateMask
= LVIS_SELECTED
;
697 // if item is not selected, don't do anything
698 if(!(lvi
.state
& LVIS_SELECTED
))
700 // new check state will be reverse of the current state,
701 BOOL bCheck
= !GetCheckState(nCurrItem
);
704 while((nItem
= GetNextItem(nOldItem
, LVNI_SELECTED
)) != -1)
706 if(nItem
!= nCurrItem
)
707 SetCheckState(nItem
, bCheck
);
715 T
* pT
= static_cast<T
*>(this);
716 pT
; // avoid level 4 warning
717 ATLASSERT((pT
->GetExtendedLVStyle() & LVS_EX_CHECKBOXES
) != 0);
718 SetExtendedListViewStyle(pT
->GetExtendedLVStyle());
721 // Message map and handlers
722 BEGIN_MSG_MAP(CCheckListViewCtrlImpl
)
723 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
724 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnLButtonDown
)
725 MESSAGE_HANDLER(WM_LBUTTONDBLCLK
, OnLButtonDown
)
726 MESSAGE_HANDLER(WM_KEYDOWN
, OnKeyDown
)
729 LRESULT
OnCreate(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
731 // first let list view control initialize everything
732 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
735 T
* pT
= static_cast<T
*>(this);
742 LRESULT
OnLButtonDown(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
744 POINT ptMsg
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
745 LVHITTESTINFO lvh
= { 0 };
747 if(HitTest(&lvh
) != -1 && lvh
.flags
== LVHT_ONITEMSTATEICON
&& ::GetKeyState(VK_CONTROL
) >= 0)
749 T
* pT
= static_cast<T
*>(this);
750 pT
->CheckSelectedItems(lvh
.iItem
);
756 LRESULT
OnKeyDown(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
758 if(wParam
== VK_SPACE
)
760 int nCurrItem
= GetNextItem(-1, LVNI_FOCUSED
);
761 if(nCurrItem
!= -1 && ::GetKeyState(VK_CONTROL
) >= 0)
763 T
* pT
= static_cast<T
*>(this);
764 pT
->CheckSelectedItems(nCurrItem
);
772 class CCheckListViewCtrl
: public CCheckListViewCtrlImpl
<CCheckListViewCtrl
>
775 DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName())
779 ///////////////////////////////////////////////////////////////////////////////
780 // CHyperLink - hyper link control implementation
782 #if (WINVER < 0x0500) && !defined(_WIN32_WCE)
783 __declspec(selectany
) struct
785 enum { cxWidth
= 32, cyHeight
= 32 };
788 unsigned char arrANDPlane
[cxWidth
* cyHeight
/ 8];
789 unsigned char arrXORPlane
[cxWidth
* cyHeight
/ 8];
790 } _AtlHyperLink_CursorData
=
794 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF,
795 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF, 0xFF, 0xF0, 0x01, 0xFF, 0xFF,
796 0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F, 0xFF,
797 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xE0, 0x00, 0x7F, 0xFF,
798 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF,
799 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
800 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
801 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
804 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
805 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00, 0x00, 0x06, 0xD8, 0x00, 0x00,
806 0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00, 0x00, 0x77, 0xFF, 0x00, 0x00,
807 0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00, 0x00, 0x0F, 0xFF, 0x00, 0x00,
808 0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x03, 0xFC, 0x00, 0x00,
809 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
810 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
811 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
814 #endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)
816 #define HLINK_UNDERLINED 0x00000000
817 #define HLINK_NOTUNDERLINED 0x00000001
818 #define HLINK_UNDERLINEHOVER 0x00000002
819 #define HLINK_COMMANDBUTTON 0x00000004
820 #define HLINK_NOTIFYBUTTON 0x0000000C
821 #define HLINK_USETAGS 0x00000010
822 #define HLINK_USETAGSBOLD 0x00000030
823 #define HLINK_NOTOOLTIP 0x00000040
824 #define HLINK_AUTOCREATELINKFONT 0x00000080
825 #define HLINK_SINGLELINE 0x00000100
828 // - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned
829 // - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored
831 template <class T
, class TBase
= ATL::CWindow
, class TWinTraits
= ATL::CControlWinTraits
>
832 class ATL_NO_VTABLE CHyperLinkImpl
: public ATL::CWindowImpl
< T
, TBase
, TWinTraits
>
836 LPTSTR m_lpstrHyperLink
;
845 #endif // !_WIN32_WCE
848 COLORREF m_clrVisited
;
850 DWORD m_dwExtendedStyle
; // Hyper Link specific extended styles
852 bool m_bPaintLabel
:1;
855 bool m_bInternalLinkFont
:1;
856 bool m_bInternalNormalFont
:1;
859 // Constructor/Destructor
860 CHyperLinkImpl(DWORD dwExtendedStyle
= HLINK_UNDERLINED
) :
861 m_lpstrLabel(NULL
), m_lpstrHyperLink(NULL
),
862 m_hCursor(NULL
), m_hFontLink(NULL
), m_hFontNormal(NULL
),
863 m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128)),
864 m_dwExtendedStyle(dwExtendedStyle
),
865 m_bPaintLabel(true), m_bVisited(false),
866 m_bHover(false), m_bInternalLinkFont(false), m_bInternalNormalFont(false)
868 ::SetRectEmpty(&m_rcLink
);
873 delete [] m_lpstrLabel
;
874 delete [] m_lpstrHyperLink
;
875 #if (WINVER < 0x0500) && !defined(_WIN32_WCE)
876 // It was created, not loaded, so we have to destroy it
877 if(m_hCursor
!= NULL
)
878 ::DestroyCursor(m_hCursor
);
879 #endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)
883 DWORD
GetHyperLinkExtendedStyle() const
885 return m_dwExtendedStyle
;
888 DWORD
SetHyperLinkExtendedStyle(DWORD dwExtendedStyle
, DWORD dwMask
= 0)
890 DWORD dwPrevStyle
= m_dwExtendedStyle
;
892 m_dwExtendedStyle
= dwExtendedStyle
;
894 m_dwExtendedStyle
= (m_dwExtendedStyle
& ~dwMask
) | (dwExtendedStyle
& dwMask
);
898 bool GetLabel(LPTSTR lpstrBuffer
, int nLength
) const
900 if(m_lpstrLabel
== NULL
)
902 ATLASSERT(lpstrBuffer
!= NULL
);
903 if(nLength
<= lstrlen(m_lpstrLabel
))
906 SecureHelper::strcpy_x(lpstrBuffer
, nLength
, m_lpstrLabel
);
911 bool SetLabel(LPCTSTR lpstrLabel
)
913 delete [] m_lpstrLabel
;
915 int cchLen
= lstrlen(lpstrLabel
) + 1;
916 ATLTRY(m_lpstrLabel
= new TCHAR
[cchLen
]);
917 if(m_lpstrLabel
== NULL
)
920 SecureHelper::strcpy_x(m_lpstrLabel
, cchLen
, lpstrLabel
);
921 T
* pT
= static_cast<T
*>(this);
925 SetWindowText(lpstrLabel
); // Set this for accessibility
930 bool GetHyperLink(LPTSTR lpstrBuffer
, int nLength
) const
932 if(m_lpstrHyperLink
== NULL
)
934 ATLASSERT(lpstrBuffer
!= NULL
);
935 if(nLength
<= lstrlen(m_lpstrHyperLink
))
938 SecureHelper::strcpy_x(lpstrBuffer
, nLength
, m_lpstrHyperLink
);
943 bool SetHyperLink(LPCTSTR lpstrLink
)
945 delete [] m_lpstrHyperLink
;
946 m_lpstrHyperLink
= NULL
;
947 int cchLen
= lstrlen(lpstrLink
) + 1;
948 ATLTRY(m_lpstrHyperLink
= new TCHAR
[cchLen
]);
949 if(m_lpstrHyperLink
== NULL
)
952 SecureHelper::strcpy_x(m_lpstrHyperLink
, cchLen
, lpstrLink
);
953 if(m_lpstrLabel
== NULL
)
955 T
* pT
= static_cast<T
*>(this);
961 m_tip
.Activate(TRUE
);
962 m_tip
.AddTool(m_hWnd
, m_lpstrHyperLink
, &m_rcLink
, 1);
964 #endif // !_WIN32_WCE
968 HFONT
GetLinkFont() const
973 void SetLinkFont(HFONT hFont
)
975 if(m_bInternalLinkFont
)
977 ::DeleteObject(m_hFontLink
);
978 m_bInternalLinkFont
= false;
983 T
* pT
= static_cast<T
*>(this);
987 int GetIdealHeight() const
989 ATLASSERT(::IsWindow(m_hWnd
));
990 if(m_lpstrLabel
== NULL
&& m_lpstrHyperLink
== NULL
)
995 UINT uFormat
= IsSingleLine() ? DT_SINGLELINE
: DT_WORDBREAK
;
997 CClientDC
dc(m_hWnd
);
999 GetClientRect(&rect
);
1000 HFONT hFontOld
= dc
.SelectFont(m_hFontNormal
);
1002 dc
.DrawText(_T("NS"), -1, &rcText
, DT_LEFT
| uFormat
| DT_CALCRECT
);
1003 dc
.SelectFont(m_hFontLink
);
1005 dc
.DrawText(_T("NS"), -1, &rcLink
, DT_LEFT
| uFormat
| DT_CALCRECT
);
1006 dc
.SelectFont(hFontOld
);
1007 return __max(rcText
.bottom
- rcText
.top
, rcLink
.bottom
- rcLink
.top
);
1010 bool GetIdealSize(SIZE
& size
) const
1013 bool bRet
= GetIdealSize(cx
, cy
);
1022 bool GetIdealSize(int& cx
, int& cy
) const
1024 ATLASSERT(::IsWindow(m_hWnd
));
1025 if(m_lpstrLabel
== NULL
&& m_lpstrHyperLink
== NULL
)
1030 CClientDC
dc(m_hWnd
);
1031 RECT rcClient
= { 0 };
1032 GetClientRect(&rcClient
);
1033 RECT rcAll
= rcClient
;
1037 // find tags and label parts
1038 LPTSTR lpstrLeft
= NULL
;
1040 LPTSTR lpstrLink
= NULL
;
1042 LPTSTR lpstrRight
= NULL
;
1045 const T
* pT
= static_cast<const T
*>(this);
1046 pT
->CalcLabelParts(lpstrLeft
, cchLeft
, lpstrLink
, cchLink
, lpstrRight
, cchRight
);
1048 // get label part rects
1049 UINT uFormat
= IsSingleLine() ? DT_SINGLELINE
: DT_WORDBREAK
;
1051 HFONT hFontOld
= dc
.SelectFont(m_hFontNormal
);
1052 RECT rcLeft
= rcClient
;
1053 dc
.DrawText(lpstrLeft
, cchLeft
, &rcLeft
, DT_LEFT
| uFormat
| DT_CALCRECT
);
1055 dc
.SelectFont(m_hFontLink
);
1056 RECT rcLink
= { rcLeft
.right
, rcLeft
.top
, rcClient
.right
, rcClient
.bottom
};
1057 dc
.DrawText(lpstrLink
, cchLink
, &rcLink
, DT_LEFT
| uFormat
| DT_CALCRECT
);
1059 dc
.SelectFont(m_hFontNormal
);
1060 RECT rcRight
= { rcLink
.right
, rcLink
.top
, rcClient
.right
, rcClient
.bottom
};
1061 dc
.DrawText(lpstrRight
, cchRight
, &rcRight
, DT_LEFT
| uFormat
| DT_CALCRECT
);
1063 dc
.SelectFont(hFontOld
);
1065 int cyMax
= __max(rcLeft
.bottom
, __max(rcLink
.bottom
, rcRight
.bottom
));
1066 ::SetRect(&rcAll
, rcLeft
.left
, rcLeft
.top
, rcRight
.right
, cyMax
);
1070 HFONT hOldFont
= NULL
;
1071 if(m_hFontLink
!= NULL
)
1072 hOldFont
= dc
.SelectFont(m_hFontLink
);
1073 LPTSTR lpstrText
= (m_lpstrLabel
!= NULL
) ? m_lpstrLabel
: m_lpstrHyperLink
;
1074 DWORD dwStyle
= GetStyle();
1075 UINT uFormat
= DT_LEFT
;
1076 if (dwStyle
& SS_CENTER
)
1077 uFormat
= DT_CENTER
;
1078 else if (dwStyle
& SS_RIGHT
)
1080 uFormat
|= IsSingleLine() ? DT_SINGLELINE
: DT_WORDBREAK
;
1081 dc
.DrawText(lpstrText
, -1, &rcAll
, uFormat
| DT_CALCRECT
);
1082 if(m_hFontLink
!= NULL
)
1083 dc
.SelectFont(hOldFont
);
1084 if (dwStyle
& SS_CENTER
)
1086 int dx
= (rcClient
.right
- rcAll
.right
) / 2;
1087 ::OffsetRect(&rcAll
, dx
, 0);
1089 else if (dwStyle
& SS_RIGHT
)
1091 int dx
= rcClient
.right
- rcAll
.right
;
1092 ::OffsetRect(&rcAll
, dx
, 0);
1096 cx
= rcAll
.right
- rcAll
.left
;
1097 cy
= rcAll
.bottom
- rcAll
.top
;
1102 // for command buttons only
1103 bool GetToolTipText(LPTSTR lpstrBuffer
, int nLength
) const
1105 ATLASSERT(IsCommandButton());
1106 return GetHyperLink(lpstrBuffer
, nLength
);
1109 bool SetToolTipText(LPCTSTR lpstrToolTipText
)
1111 ATLASSERT(IsCommandButton());
1112 return SetHyperLink(lpstrToolTipText
);
1116 BOOL
SubclassWindow(HWND hWnd
)
1118 ATLASSERT(m_hWnd
== NULL
);
1119 ATLASSERT(::IsWindow(hWnd
));
1120 if(m_hFontNormal
== NULL
)
1121 m_hFontNormal
= (HFONT
)::SendMessage(hWnd
, WM_GETFONT
, 0, 0L);
1123 #if (_MSC_VER >= 1300)
1124 BOOL bRet
= ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::SubclassWindow(hWnd
);
1125 #else // !(_MSC_VER >= 1300)
1126 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
1127 BOOL bRet
= _baseClass::SubclassWindow(hWnd
);
1128 #endif // !(_MSC_VER >= 1300)
1131 T
* pT
= static_cast<T
*>(this);
1140 ATLASSERT(::IsWindow(m_hWnd
));
1142 if(IsNotifyButton())
1144 NMHDR nmhdr
= { m_hWnd
, GetDlgCtrlID(), NM_CLICK
};
1145 ::SendMessage(GetParent(), WM_NOTIFY
, GetDlgCtrlID(), (LPARAM
)&nmhdr
);
1147 else if(IsCommandButton())
1149 ::SendMessage(GetParent(), WM_COMMAND
, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED
), (LPARAM
)m_hWnd
);
1153 ATLASSERT(m_lpstrHyperLink
!= NULL
);
1155 DWORD_PTR dwRet
= (DWORD_PTR
)::ShellExecute(0, _T("open"), m_lpstrHyperLink
, 0, 0, SW_SHOWNORMAL
);
1156 bRet
= (dwRet
> 32);
1157 #else // CE specific
1158 SHELLEXECUTEINFO shExeInfo
= { sizeof(SHELLEXECUTEINFO
), 0, 0, L
"open", m_lpstrHyperLink
, 0, 0, SW_SHOWNORMAL
, 0, 0, 0, 0, 0, 0, 0 };
1159 ::ShellExecuteEx(&shExeInfo
);
1160 DWORD_PTR dwRet
= (DWORD_PTR
)shExeInfo
.hInstApp
;
1161 bRet
= (dwRet
== 0) || (dwRet
> 32);
1162 #endif // _WIN32_WCE
1173 void CreateLinkFontFromNormal()
1175 if(m_bInternalLinkFont
)
1177 ::DeleteObject(m_hFontLink
);
1178 m_bInternalLinkFont
= false;
1181 CFontHandle font
= (m_hFontNormal
!= NULL
) ? m_hFontNormal
: (HFONT
)::GetStockObject(SYSTEM_FONT
);
1183 font
.GetLogFont(&lf
);
1185 if(IsUsingTagsBold())
1186 lf
.lfWeight
= FW_BOLD
;
1187 else if(!IsNotUnderlined())
1188 lf
.lfUnderline
= TRUE
;
1190 m_hFontLink
= ::CreateFontIndirect(&lf
);
1191 m_bInternalLinkFont
= true;
1192 ATLASSERT(m_hFontLink
!= NULL
);
1195 // Message map and handlers
1196 BEGIN_MSG_MAP(CHyperLinkImpl
)
1197 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
1199 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
1200 MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST
, WM_MOUSELAST
, OnMouseMessage
)
1201 #endif // !_WIN32_WCE
1202 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
1203 MESSAGE_HANDLER(WM_PAINT
, OnPaint
)
1205 MESSAGE_HANDLER(WM_PRINTCLIENT
, OnPaint
)
1206 #endif // !_WIN32_WCE
1207 MESSAGE_HANDLER(WM_SETFOCUS
, OnFocus
)
1208 MESSAGE_HANDLER(WM_KILLFOCUS
, OnFocus
)
1209 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnMouseMove
)
1211 MESSAGE_HANDLER(WM_MOUSELEAVE
, OnMouseLeave
)
1212 #endif // !_WIN32_WCE
1213 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnLButtonDown
)
1214 MESSAGE_HANDLER(WM_LBUTTONUP
, OnLButtonUp
)
1215 MESSAGE_HANDLER(WM_CHAR
, OnChar
)
1216 MESSAGE_HANDLER(WM_GETDLGCODE
, OnGetDlgCode
)
1217 MESSAGE_HANDLER(WM_SETCURSOR
, OnSetCursor
)
1218 MESSAGE_HANDLER(WM_ENABLE
, OnEnable
)
1219 MESSAGE_HANDLER(WM_GETFONT
, OnGetFont
)
1220 MESSAGE_HANDLER(WM_SETFONT
, OnSetFont
)
1221 MESSAGE_HANDLER(WM_UPDATEUISTATE
, OnUpdateUiState
)
1222 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
1225 LRESULT
OnCreate(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1227 T
* pT
= static_cast<T
*>(this);
1233 LRESULT
OnDestroy(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1235 if(m_tip
.IsWindow())
1237 m_tip
.DestroyWindow();
1238 m_tip
.m_hWnd
= NULL
;
1241 if(m_bInternalLinkFont
)
1243 ::DeleteObject(m_hFontLink
);
1245 m_bInternalLinkFont
= false;
1248 if(m_bInternalNormalFont
)
1250 ::DeleteObject(m_hFontNormal
);
1251 m_hFontNormal
= NULL
;
1252 m_bInternalNormalFont
= false;
1259 LRESULT
OnMouseMessage(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
1261 MSG msg
= { m_hWnd
, uMsg
, wParam
, lParam
};
1262 if(m_tip
.IsWindow() && IsUsingToolTip())
1263 m_tip
.RelayEvent(&msg
);
1267 #endif // !_WIN32_WCE
1269 LRESULT
OnEraseBackground(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1271 return 1; // no background painting needed (we do it all during WM_PAINT)
1274 LRESULT
OnPaint(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
1282 T
* pT
= static_cast<T
*>(this);
1285 pT
->DoEraseBackground((HDC
)wParam
);
1286 pT
->DoPaint((HDC
)wParam
);
1290 CPaintDC
dc(m_hWnd
);
1291 pT
->DoEraseBackground(dc
.m_hDC
);
1292 pT
->DoPaint(dc
.m_hDC
);
1298 LRESULT
OnFocus(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1307 LRESULT
OnMouseMove(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
1309 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
1310 if((m_lpstrHyperLink
!= NULL
|| IsCommandButton()) && ::PtInRect(&m_rcLink
, pt
))
1312 ::SetCursor(m_hCursor
);
1313 if(IsUnderlineHover())
1318 InvalidateRect(&m_rcLink
);
1321 StartTrackMouseLeave();
1322 #endif // !_WIN32_WCE
1328 if(IsUnderlineHover())
1333 InvalidateRect(&m_rcLink
);
1343 LRESULT
OnMouseLeave(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1345 if(IsUnderlineHover() && m_bHover
)
1348 InvalidateRect(&m_rcLink
);
1353 #endif // !_WIN32_WCE
1355 LRESULT
OnLButtonDown(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& /*bHandled*/)
1357 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
1358 if(::PtInRect(&m_rcLink
, pt
))
1366 LRESULT
OnLButtonUp(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& /*bHandled*/)
1368 if(GetCapture() == m_hWnd
)
1371 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
1372 if(::PtInRect(&m_rcLink
, pt
))
1374 T
* pT
= static_cast<T
*>(this);
1381 LRESULT
OnChar(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1383 if(wParam
== VK_RETURN
|| wParam
== VK_SPACE
)
1385 T
* pT
= static_cast<T
*>(this);
1391 LRESULT
OnGetDlgCode(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1393 return DLGC_WANTCHARS
;
1396 LRESULT
OnSetCursor(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
1398 POINT pt
= { 0, 0 };
1400 ScreenToClient(&pt
);
1401 if((m_lpstrHyperLink
!= NULL
|| IsCommandButton()) && ::PtInRect(&m_rcLink
, pt
))
1409 LRESULT
OnEnable(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1416 LRESULT
OnGetFont(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1418 return (LRESULT
)m_hFontNormal
;
1421 LRESULT
OnSetFont(UINT
/*uMsg*/, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
1423 if(m_bInternalNormalFont
)
1425 ::DeleteObject(m_hFontNormal
);
1426 m_bInternalNormalFont
= false;
1429 bool bCreateLinkFont
= m_bInternalLinkFont
;
1431 m_hFontNormal
= (HFONT
)wParam
;
1433 if(bCreateLinkFont
|| IsAutoCreateLinkFont())
1434 CreateLinkFontFromNormal();
1436 T
* pT
= static_cast<T
*>(this);
1437 pT
->CalcLabelRect();
1448 LRESULT
OnUpdateUiState(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1450 // If the control is subclassed or superclassed, this message can cause
1451 // repainting without WM_PAINT. We don't use this state, so just do nothing.
1455 LRESULT
OnSize(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
1457 T
* pT
= static_cast<T
*>(this);
1458 pT
->CalcLabelRect();
1466 ATLASSERT(::IsWindow(m_hWnd
));
1468 // Check if we should paint a label
1469 const int cchBuff
= 8;
1470 TCHAR szBuffer
[cchBuff
] = { 0 };
1471 if(::GetClassName(m_hWnd
, szBuffer
, cchBuff
))
1473 if(lstrcmpi(szBuffer
, _T("static")) == 0)
1475 ModifyStyle(0, SS_NOTIFY
); // we need this
1476 DWORD dwStyle
= GetStyle() & 0x000000FF;
1478 if(dwStyle
== SS_ICON
|| dwStyle
== SS_BLACKRECT
|| dwStyle
== SS_GRAYRECT
||
1479 dwStyle
== SS_WHITERECT
|| dwStyle
== SS_BLACKFRAME
|| dwStyle
== SS_GRAYFRAME
||
1480 dwStyle
== SS_WHITEFRAME
|| dwStyle
== SS_OWNERDRAW
||
1481 dwStyle
== SS_BITMAP
|| dwStyle
== SS_ENHMETAFILE
)
1482 #else // CE specific
1483 if(dwStyle
== SS_ICON
|| dwStyle
== SS_BITMAP
)
1484 #endif // _WIN32_WCE
1485 m_bPaintLabel
= false;
1489 // create or load a cursor
1490 #if (WINVER >= 0x0500) || defined(_WIN32_WCE)
1491 m_hCursor
= ::LoadCursor(NULL
, IDC_HAND
);
1493 m_hCursor
= ::CreateCursor(ModuleHelper::GetModuleInstance(), _AtlHyperLink_CursorData
.xHotSpot
, _AtlHyperLink_CursorData
.yHotSpot
, _AtlHyperLink_CursorData
.cxWidth
, _AtlHyperLink_CursorData
.cyHeight
, _AtlHyperLink_CursorData
.arrANDPlane
, _AtlHyperLink_CursorData
.arrXORPlane
);
1495 ATLASSERT(m_hCursor
!= NULL
);
1500 if(m_hFontNormal
== NULL
)
1502 m_hFontNormal
= AtlCreateControlFont();
1503 m_bInternalNormalFont
= true;
1506 if(m_hFontLink
== NULL
)
1507 CreateLinkFontFromNormal();
1511 // create a tool tip
1512 m_tip
.Create(m_hWnd
);
1513 ATLASSERT(m_tip
.IsWindow());
1514 #endif // !_WIN32_WCE
1516 // set label (defaults to window text)
1517 if(m_lpstrLabel
== NULL
)
1519 int nLen
= GetWindowTextLength();
1522 ATLTRY(m_lpstrLabel
= new TCHAR
[nLen
+ 1]);
1523 if(m_lpstrLabel
!= NULL
)
1524 ATLVERIFY(GetWindowText(m_lpstrLabel
, nLen
+ 1) > 0);
1528 T
* pT
= static_cast<T
*>(this);
1529 pT
->CalcLabelRect();
1531 // set hyperlink (defaults to label), or just activate tool tip if already set
1532 if(m_lpstrHyperLink
== NULL
&& !IsCommandButton())
1534 if(m_lpstrLabel
!= NULL
)
1535 SetHyperLink(m_lpstrLabel
);
1540 m_tip
.Activate(TRUE
);
1541 m_tip
.AddTool(m_hWnd
, m_lpstrHyperLink
, &m_rcLink
, 1);
1543 #endif // !_WIN32_WCE
1549 LONG lRet
= rk
.Open(HKEY_CURRENT_USER
, _T("Software\\Microsoft\\Internet Explorer\\Settings"));
1550 if(lRet
== ERROR_SUCCESS
)
1552 const int cchValue
= 12;
1553 TCHAR szValue
[cchValue
] = { 0 };
1554 ULONG ulCount
= cchValue
;
1555 lRet
= rk
.QueryStringValue(_T("Anchor Color"), szValue
, &ulCount
);
1556 if(lRet
== ERROR_SUCCESS
)
1558 COLORREF clr
= pT
->_ParseColorString(szValue
);
1559 ATLASSERT(clr
!= CLR_INVALID
);
1560 if(clr
!= CLR_INVALID
)
1565 lRet
= rk
.QueryStringValue(_T("Anchor Color Visited"), szValue
, &ulCount
);
1566 if(lRet
== ERROR_SUCCESS
)
1568 COLORREF clr
= pT
->_ParseColorString(szValue
);
1569 ATLASSERT(clr
!= CLR_INVALID
);
1570 if(clr
!= CLR_INVALID
)
1577 static COLORREF
_ParseColorString(LPTSTR lpstr
)
1579 int c
[3] = { -1, -1, -1 };
1581 for(int i
= 0; i
< 2; i
++)
1583 for(p
= lpstr
; *p
!= _T('\0'); p
= ::CharNext(p
))
1588 c
[i
] = MinCrtHelper::_atoi(lpstr
);
1596 if(*lpstr
== _T('\0'))
1598 c
[2] = MinCrtHelper::_atoi(lpstr
);
1600 return RGB(c
[0], c
[1], c
[2]);
1603 bool CalcLabelRect()
1605 if(!::IsWindow(m_hWnd
))
1607 if(m_lpstrLabel
== NULL
&& m_lpstrHyperLink
== NULL
)
1610 CClientDC
dc(m_hWnd
);
1611 RECT rcClient
= { 0 };
1612 GetClientRect(&rcClient
);
1613 m_rcLink
= rcClient
;
1619 // find tags and label parts
1620 LPTSTR lpstrLeft
= NULL
;
1622 LPTSTR lpstrLink
= NULL
;
1624 LPTSTR lpstrRight
= NULL
;
1627 T
* pT
= static_cast<T
*>(this);
1628 pT
->CalcLabelParts(lpstrLeft
, cchLeft
, lpstrLink
, cchLink
, lpstrRight
, cchRight
);
1629 ATLASSERT(lpstrLink
!= NULL
);
1630 ATLASSERT(cchLink
> 0);
1632 // get label part rects
1633 HFONT hFontOld
= dc
.SelectFont(m_hFontNormal
);
1635 UINT uFormat
= IsSingleLine() ? DT_SINGLELINE
: DT_WORDBREAK
;
1637 RECT rcLeft
= rcClient
;
1638 if(lpstrLeft
!= NULL
)
1639 dc
.DrawText(lpstrLeft
, cchLeft
, &rcLeft
, DT_LEFT
| uFormat
| DT_CALCRECT
);
1641 dc
.SelectFont(m_hFontLink
);
1642 RECT rcLink
= rcClient
;
1643 if(lpstrLeft
!= NULL
)
1644 rcLink
.left
= rcLeft
.right
;
1645 dc
.DrawText(lpstrLink
, cchLink
, &rcLink
, DT_LEFT
| uFormat
| DT_CALCRECT
);
1647 dc
.SelectFont(hFontOld
);
1653 HFONT hOldFont
= NULL
;
1654 if(m_hFontLink
!= NULL
)
1655 hOldFont
= dc
.SelectFont(m_hFontLink
);
1656 LPTSTR lpstrText
= (m_lpstrLabel
!= NULL
) ? m_lpstrLabel
: m_lpstrHyperLink
;
1657 DWORD dwStyle
= GetStyle();
1658 UINT uFormat
= DT_LEFT
;
1659 if (dwStyle
& SS_CENTER
)
1660 uFormat
= DT_CENTER
;
1661 else if (dwStyle
& SS_RIGHT
)
1663 uFormat
|= IsSingleLine() ? DT_SINGLELINE
: DT_WORDBREAK
;
1664 dc
.DrawText(lpstrText
, -1, &m_rcLink
, uFormat
| DT_CALCRECT
);
1665 if(m_hFontLink
!= NULL
)
1666 dc
.SelectFont(hOldFont
);
1667 if (dwStyle
& SS_CENTER
)
1669 int dx
= (rcClient
.right
- m_rcLink
.right
) / 2;
1670 ::OffsetRect(&m_rcLink
, dx
, 0);
1672 else if (dwStyle
& SS_RIGHT
)
1674 int dx
= rcClient
.right
- m_rcLink
.right
;
1675 ::OffsetRect(&m_rcLink
, dx
, 0);
1682 void CalcLabelParts(LPTSTR
& lpstrLeft
, int& cchLeft
, LPTSTR
& lpstrLink
, int& cchLink
, LPTSTR
& lpstrRight
, int& cchRight
) const
1691 LPTSTR lpstrText
= (m_lpstrLabel
!= NULL
) ? m_lpstrLabel
: m_lpstrHyperLink
;
1692 int cchText
= lstrlen(lpstrText
);
1693 bool bOutsideLink
= true;
1694 for(int i
= 0; i
< cchText
; i
++)
1696 if(lpstrText
[i
] != _T('<'))
1701 if(::CompareString(LOCALE_USER_DEFAULT
, NORM_IGNORECASE
, &lpstrText
[i
], 3, _T("<A>"), 3) == CSTR_EQUAL
)
1705 lpstrLeft
= lpstrText
;
1708 lpstrLink
= &lpstrText
[i
+ 3];
1709 bOutsideLink
= false;
1714 if(::CompareString(LOCALE_USER_DEFAULT
, NORM_IGNORECASE
, &lpstrText
[i
], 4, _T("</A>"), 4) == CSTR_EQUAL
)
1716 cchLink
= i
- 3 - cchLeft
;
1717 if(lpstrText
[i
+ 4] != 0)
1719 lpstrRight
= &lpstrText
[i
+ 4];
1720 cchRight
= cchText
- (i
+ 4);
1729 void DoEraseBackground(CDCHandle dc
)
1731 HBRUSH hBrush
= (HBRUSH
)::SendMessage(GetParent(), WM_CTLCOLORSTATIC
, (WPARAM
)dc
.m_hDC
, (LPARAM
)m_hWnd
);
1735 GetClientRect(&rect
);
1736 dc
.FillRect(&rect
, hBrush
);
1740 void DoPaint(CDCHandle dc
)
1744 // find tags and label parts
1745 LPTSTR lpstrLeft
= NULL
;
1747 LPTSTR lpstrLink
= NULL
;
1749 LPTSTR lpstrRight
= NULL
;
1752 T
* pT
= static_cast<T
*>(this);
1753 pT
->CalcLabelParts(lpstrLeft
, cchLeft
, lpstrLink
, cchLink
, lpstrRight
, cchRight
);
1755 // get label part rects
1756 RECT rcClient
= { 0 };
1757 GetClientRect(&rcClient
);
1759 dc
.SetBkMode(TRANSPARENT
);
1760 HFONT hFontOld
= dc
.SelectFont(m_hFontNormal
);
1762 UINT uFormat
= IsSingleLine() ? DT_SINGLELINE
: DT_WORDBREAK
;
1764 if(lpstrLeft
!= NULL
)
1765 dc
.DrawText(lpstrLeft
, cchLeft
, &rcClient
, DT_LEFT
| uFormat
);
1767 COLORREF clrOld
= dc
.SetTextColor(IsWindowEnabled() ? (m_bVisited
? m_clrVisited
: m_clrLink
) : (::GetSysColor(COLOR_GRAYTEXT
)));
1768 if(m_hFontLink
!= NULL
&& (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover
)))
1769 dc
.SelectFont(m_hFontLink
);
1771 dc
.SelectFont(m_hFontNormal
);
1773 dc
.DrawText(lpstrLink
, cchLink
, &m_rcLink
, DT_LEFT
| uFormat
);
1775 dc
.SetTextColor(clrOld
);
1776 dc
.SelectFont(m_hFontNormal
);
1777 if(lpstrRight
!= NULL
)
1779 RECT rcRight
= { m_rcLink
.right
, m_rcLink
.top
, rcClient
.right
, rcClient
.bottom
};
1780 dc
.DrawText(lpstrRight
, cchRight
, &rcRight
, DT_LEFT
| uFormat
);
1783 if(GetFocus() == m_hWnd
)
1784 dc
.DrawFocusRect(&m_rcLink
);
1786 dc
.SelectFont(hFontOld
);
1790 dc
.SetBkMode(TRANSPARENT
);
1791 COLORREF clrOld
= dc
.SetTextColor(IsWindowEnabled() ? (m_bVisited
? m_clrVisited
: m_clrLink
) : (::GetSysColor(COLOR_GRAYTEXT
)));
1793 HFONT hFontOld
= NULL
;
1794 if(m_hFontLink
!= NULL
&& (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover
)))
1795 hFontOld
= dc
.SelectFont(m_hFontLink
);
1797 hFontOld
= dc
.SelectFont(m_hFontNormal
);
1799 LPTSTR lpstrText
= (m_lpstrLabel
!= NULL
) ? m_lpstrLabel
: m_lpstrHyperLink
;
1801 DWORD dwStyle
= GetStyle();
1802 UINT uFormat
= DT_LEFT
;
1803 if (dwStyle
& SS_CENTER
)
1804 uFormat
= DT_CENTER
;
1805 else if (dwStyle
& SS_RIGHT
)
1807 uFormat
|= IsSingleLine() ? DT_SINGLELINE
: DT_WORDBREAK
;
1809 dc
.DrawText(lpstrText
, -1, &m_rcLink
, uFormat
);
1811 if(GetFocus() == m_hWnd
)
1812 dc
.DrawFocusRect(&m_rcLink
);
1814 dc
.SetTextColor(clrOld
);
1815 dc
.SelectFont(hFontOld
);
1820 BOOL
StartTrackMouseLeave()
1822 TRACKMOUSEEVENT tme
= { 0 };
1823 tme
.cbSize
= sizeof(tme
);
1824 tme
.dwFlags
= TME_LEAVE
;
1825 tme
.hwndTrack
= m_hWnd
;
1826 return _TrackMouseEvent(&tme
);
1828 #endif // !_WIN32_WCE
1830 // Implementation helpers
1831 bool IsUnderlined() const
1833 return ((m_dwExtendedStyle
& (HLINK_NOTUNDERLINED
| HLINK_UNDERLINEHOVER
)) == 0);
1836 bool IsNotUnderlined() const
1838 return ((m_dwExtendedStyle
& HLINK_NOTUNDERLINED
) != 0);
1841 bool IsUnderlineHover() const
1843 return ((m_dwExtendedStyle
& HLINK_UNDERLINEHOVER
) != 0);
1846 bool IsCommandButton() const
1848 return ((m_dwExtendedStyle
& HLINK_COMMANDBUTTON
) != 0);
1851 bool IsNotifyButton() const
1853 return ((m_dwExtendedStyle
& HLINK_NOTIFYBUTTON
) == HLINK_NOTIFYBUTTON
);
1856 bool IsUsingTags() const
1858 return ((m_dwExtendedStyle
& HLINK_USETAGS
) != 0);
1861 bool IsUsingTagsBold() const
1863 return ((m_dwExtendedStyle
& HLINK_USETAGSBOLD
) == HLINK_USETAGSBOLD
);
1866 bool IsUsingToolTip() const
1868 return ((m_dwExtendedStyle
& HLINK_NOTOOLTIP
) == 0);
1871 bool IsAutoCreateLinkFont() const
1873 return ((m_dwExtendedStyle
& HLINK_AUTOCREATELINKFONT
) == HLINK_AUTOCREATELINKFONT
);
1876 bool IsSingleLine() const
1878 return ((m_dwExtendedStyle
& HLINK_SINGLELINE
) == HLINK_SINGLELINE
);
1882 class CHyperLink
: public CHyperLinkImpl
<CHyperLink
>
1885 DECLARE_WND_CLASS(_T("WTL_HyperLink"))
1889 ///////////////////////////////////////////////////////////////////////////////
1890 // CWaitCursor - displays a wait cursor
1896 HCURSOR m_hWaitCursor
;
1897 HCURSOR m_hOldCursor
;
1900 // Constructor/destructor
1901 CWaitCursor(bool bSet
= true, LPCTSTR lpstrCursor
= IDC_WAIT
, bool bSys
= true) : m_hOldCursor(NULL
), m_bInUse(false)
1903 HINSTANCE hInstance
= bSys
? NULL
: ModuleHelper::GetResourceInstance();
1904 m_hWaitCursor
= ::LoadCursor(hInstance
, lpstrCursor
);
1905 ATLASSERT(m_hWaitCursor
!= NULL
);
1921 m_hOldCursor
= ::SetCursor(m_hWaitCursor
);
1930 ::SetCursor(m_hOldCursor
);
1937 ///////////////////////////////////////////////////////////////////////////////
1938 // CCustomWaitCursor - for custom and animated cursors
1940 class CCustomWaitCursor
: public CWaitCursor
1943 // Constructor/destructor
1944 CCustomWaitCursor(ATL::_U_STRINGorID cursor
, bool bSet
= true, HINSTANCE hInstance
= NULL
) :
1945 CWaitCursor(false, IDC_WAIT
, true)
1947 if(hInstance
== NULL
)
1948 hInstance
= ModuleHelper::GetResourceInstance();
1949 m_hWaitCursor
= (HCURSOR
)::LoadImage(hInstance
, cursor
.m_lpstr
, IMAGE_CURSOR
, 0, 0, LR_DEFAULTSIZE
);
1955 ~CCustomWaitCursor()
1958 #if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))
1959 ::DestroyCursor(m_hWaitCursor
);
1960 #endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))
1965 ///////////////////////////////////////////////////////////////////////////////
1966 // CMultiPaneStatusBarCtrl - Status Bar with multiple panes
1968 template <class T
, class TBase
= CStatusBarCtrl
>
1969 class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl
: public ATL::CWindowImpl
< T
, TBase
>
1972 DECLARE_WND_SUPERCLASS(NULL
, TBase::GetWndClassName())
1975 enum { m_cxPaneMargin
= 3 };
1980 // Constructor/destructor
1981 CMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL
)
1984 ~CMultiPaneStatusBarCtrlImpl()
1990 HWND
Create(HWND hWndParent
, LPCTSTR lpstrText
, DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| SBARS_SIZEGRIP
, UINT nID
= ATL_IDW_STATUS_BAR
)
1992 #if (_MSC_VER >= 1300)
1993 return ATL::CWindowImpl
< T
, TBase
>::Create(hWndParent
, rcDefault
, lpstrText
, dwStyle
, 0, nID
);
1994 #else // !(_MSC_VER >= 1300)
1995 typedef ATL::CWindowImpl
< T
, TBase
> _baseClass
;
1996 return _baseClass::Create(hWndParent
, rcDefault
, lpstrText
, dwStyle
, 0, nID
);
1997 #endif // !(_MSC_VER >= 1300)
2000 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
)
2002 const int cchMax
= 128; // max text length is 127 for status bars (+1 for null)
2003 TCHAR szText
[cchMax
] = { 0 };
2004 ::LoadString(ModuleHelper::GetResourceInstance(), nTextID
, szText
, cchMax
);
2005 return Create(hWndParent
, szText
, dwStyle
, nID
);
2008 BOOL
SetPanes(int* pPanes
, int nPanes
, bool bSetText
= true)
2010 ATLASSERT(::IsWindow(m_hWnd
));
2011 ATLASSERT(nPanes
> 0);
2017 ATLTRY(m_pPane
= new int[nPanes
]);
2018 ATLASSERT(m_pPane
!= NULL
);
2022 CTempBuffer
<int, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
2023 int* pPanesPos
= buff
.Allocate(nPanes
);
2024 ATLASSERT(pPanesPos
!= NULL
);
2025 if(pPanesPos
== NULL
)
2028 SecureHelper::memcpy_x(m_pPane
, nPanes
* sizeof(int), pPanes
, nPanes
* sizeof(int));
2030 // get status bar DC and set font
2031 CClientDC
dc(m_hWnd
);
2032 HFONT hOldFont
= dc
.SelectFont(GetFont());
2034 // get status bar borders
2035 int arrBorders
[3] = { 0 };
2036 GetBorders(arrBorders
);
2038 const int cchBuff
= 128;
2039 TCHAR szBuff
[cchBuff
] = { 0 };
2040 SIZE size
= { 0, 0 };
2041 int cxLeft
= arrBorders
[0];
2043 // calculate right edge of each part
2044 for(int i
= 0; i
< nPanes
; i
++)
2046 if(pPanes
[i
] == ID_DEFAULT_PANE
)
2048 // make very large, will be resized later
2049 pPanesPos
[i
] = INT_MAX
/ 2;
2053 ::LoadString(ModuleHelper::GetResourceInstance(), pPanes
[i
], szBuff
, cchBuff
);
2054 dc
.GetTextExtent(szBuff
, lstrlen(szBuff
), &size
);
2055 T
* pT
= static_cast<T
*>(this);
2057 pPanesPos
[i
] = cxLeft
+ size
.cx
+ arrBorders
[2] + 2 * pT
->m_cxPaneMargin
;
2059 cxLeft
= pPanesPos
[i
];
2062 BOOL bRet
= SetParts(nPanes
, pPanesPos
);
2064 if(bRet
&& bSetText
)
2066 for(int i
= 0; i
< nPanes
; i
++)
2068 if(pPanes
[i
] != ID_DEFAULT_PANE
)
2070 ::LoadString(ModuleHelper::GetResourceInstance(), pPanes
[i
], szBuff
, cchBuff
);
2071 SetPaneText(m_pPane
[i
], szBuff
);
2076 dc
.SelectFont(hOldFont
);
2080 bool GetPaneTextLength(int nPaneID
, int* pcchLength
= NULL
, int* pnType
= NULL
) const
2082 ATLASSERT(::IsWindow(m_hWnd
));
2083 int nIndex
= GetPaneIndexFromID(nPaneID
);
2087 int nLength
= GetTextLength(nIndex
, pnType
);
2088 if(pcchLength
!= NULL
)
2089 *pcchLength
= nLength
;
2094 BOOL
GetPaneText(int nPaneID
, LPTSTR lpstrText
, int* pcchLength
= NULL
, int* pnType
= NULL
) const
2096 ATLASSERT(::IsWindow(m_hWnd
));
2097 int nIndex
= GetPaneIndexFromID(nPaneID
);
2101 int nLength
= GetText(nIndex
, lpstrText
, pnType
);
2102 if(pcchLength
!= NULL
)
2103 *pcchLength
= nLength
;
2108 BOOL
SetPaneText(int nPaneID
, LPCTSTR lpstrText
, int nType
= 0)
2110 ATLASSERT(::IsWindow(m_hWnd
));
2111 int nIndex
= GetPaneIndexFromID(nPaneID
);
2115 return SetText(nIndex
, lpstrText
, nType
);
2118 BOOL
GetPaneRect(int nPaneID
, LPRECT lpRect
) const
2120 ATLASSERT(::IsWindow(m_hWnd
));
2121 int nIndex
= GetPaneIndexFromID(nPaneID
);
2125 return GetRect(nIndex
, lpRect
);
2128 BOOL
SetPaneWidth(int nPaneID
, int cxWidth
)
2130 ATLASSERT(::IsWindow(m_hWnd
));
2131 ATLASSERT(nPaneID
!= ID_DEFAULT_PANE
); // Can't resize this one
2132 int nIndex
= GetPaneIndexFromID(nPaneID
);
2136 // get pane positions
2137 CTempBuffer
<int, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
2138 int* pPanesPos
= buff
.Allocate(m_nPanes
);
2139 if(pPanesPos
== NULL
)
2141 GetParts(m_nPanes
, pPanesPos
);
2143 int cxPaneWidth
= pPanesPos
[nIndex
] - ((nIndex
== 0) ? 0 : pPanesPos
[nIndex
- 1]);
2144 int cxOff
= cxWidth
- cxPaneWidth
;
2145 // find variable width pane
2146 int nDef
= m_nPanes
;
2147 for(int i
= 0; i
< m_nPanes
; i
++)
2149 if(m_pPane
[i
] == ID_DEFAULT_PANE
)
2156 if(nIndex
< nDef
) // before default pane
2158 for(int i
= nIndex
; i
< nDef
; i
++)
2159 pPanesPos
[i
] += cxOff
;
2162 else // after default one
2164 for(int i
= nDef
; i
< nIndex
; i
++)
2165 pPanesPos
[i
] -= cxOff
;
2167 // set pane postions
2168 return SetParts(m_nPanes
, pPanesPos
);
2171 #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
2172 BOOL
GetPaneTipText(int nPaneID
, LPTSTR lpstrText
, int nSize
) const
2174 ATLASSERT(::IsWindow(m_hWnd
));
2175 int nIndex
= GetPaneIndexFromID(nPaneID
);
2179 GetTipText(nIndex
, lpstrText
, nSize
);
2183 BOOL
SetPaneTipText(int nPaneID
, LPCTSTR lpstrText
)
2185 ATLASSERT(::IsWindow(m_hWnd
));
2186 int nIndex
= GetPaneIndexFromID(nPaneID
);
2190 SetTipText(nIndex
, lpstrText
);
2193 #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
2195 #if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))
2196 BOOL
GetPaneIcon(int nPaneID
, HICON
& hIcon
) const
2198 ATLASSERT(::IsWindow(m_hWnd
));
2199 int nIndex
= GetPaneIndexFromID(nPaneID
);
2203 hIcon
= GetIcon(nIndex
);
2207 BOOL
SetPaneIcon(int nPaneID
, HICON hIcon
)
2209 ATLASSERT(::IsWindow(m_hWnd
));
2210 int nIndex
= GetPaneIndexFromID(nPaneID
);
2214 return SetIcon(nIndex
, hIcon
);
2216 #endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && (_WIN32_WCE >= 0x0500))
2218 // Message map and handlers
2219 BEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl
< T
>)
2220 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2223 LRESULT
OnSize(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
2225 LRESULT lRet
= DefWindowProc(uMsg
, wParam
, lParam
);
2226 if(wParam
!= SIZE_MINIMIZED
&& m_nPanes
> 0)
2228 T
* pT
= static_cast<T
*>(this);
2229 pT
->UpdatePanesLayout();
2235 BOOL
UpdatePanesLayout()
2237 // get pane positions
2238 CTempBuffer
<int, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
2239 int* pPanesPos
= buff
.Allocate(m_nPanes
);
2240 ATLASSERT(pPanesPos
!= NULL
);
2241 if(pPanesPos
== NULL
)
2243 int nRet
= GetParts(m_nPanes
, pPanesPos
);
2244 ATLASSERT(nRet
== m_nPanes
);
2245 if(nRet
!= m_nPanes
)
2248 RECT rcClient
= { 0 };
2249 GetClientRect(&rcClient
);
2250 int cxOff
= rcClient
.right
- pPanesPos
[m_nPanes
- 1];
2252 // Move panes left if size grip box is present
2253 if((GetStyle() & SBARS_SIZEGRIP
) != 0)
2254 cxOff
-= ::GetSystemMetrics(SM_CXVSCROLL
) + ::GetSystemMetrics(SM_CXEDGE
);
2255 #endif // !_WIN32_WCE
2256 // find variable width pane
2258 for(i
= 0; i
< m_nPanes
; i
++)
2260 if(m_pPane
[i
] == ID_DEFAULT_PANE
)
2263 // resize all panes from the variable one to the right
2264 if((i
< m_nPanes
) && (pPanesPos
[i
] + cxOff
) > ((i
== 0) ? 0 : pPanesPos
[i
- 1]))
2266 for(; i
< m_nPanes
; i
++)
2267 pPanesPos
[i
] += cxOff
;
2269 // set pane postions
2270 return SetParts(m_nPanes
, pPanesPos
);
2273 int GetPaneIndexFromID(int nPaneID
) const
2275 for(int i
= 0; i
< m_nPanes
; i
++)
2277 if(m_pPane
[i
] == nPaneID
)
2281 return -1; // not found
2285 class CMultiPaneStatusBarCtrl
: public CMultiPaneStatusBarCtrlImpl
<CMultiPaneStatusBarCtrl
>
2288 DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName())
2292 ///////////////////////////////////////////////////////////////////////////////
2293 // CPaneContainer - provides header with title and close button for panes
2295 // pane container extended styles
2296 #define PANECNT_NOCLOSEBUTTON 0x00000001
2297 #define PANECNT_VERTICAL 0x00000002
2298 #define PANECNT_FLATBORDER 0x00000004
2299 #define PANECNT_NOBORDER 0x00000008
2301 template <class T
, class TBase
= ATL::CWindow
, class TWinTraits
= ATL::CControlWinTraits
>
2302 class ATL_NO_VTABLE CPaneContainerImpl
: public ATL::CWindowImpl
< T
, TBase
, TWinTraits
>, public CCustomDraw
< T
>
2305 DECLARE_WND_CLASS_EX(NULL
, 0, -1)
2311 m_cxyTextOffset
= 4,
2320 m_cxToolBar
= m_cxImageTB
+ m_cxyBtnAddTB
+ m_cxyBorder
+ m_cxyBtnOffset
,
2322 m_xBtnImageLeft
= 6,
2324 m_xBtnImageRight
= 12,
2325 m_yBtnImageBottom
= 11,
2327 m_nCloseBtnID
= ID_PANE_CLOSE
2332 ATL::CWindow m_wndClient
;
2334 TCHAR m_szTitle
[m_cchTitle
];
2335 DWORD m_dwExtendedStyle
; // Pane container specific extended styles
2337 bool m_bInternalFont
;
2341 CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0), m_hFont(NULL
), m_bInternalFont(false)
2347 DWORD
GetPaneContainerExtendedStyle() const
2349 return m_dwExtendedStyle
;
2352 DWORD
SetPaneContainerExtendedStyle(DWORD dwExtendedStyle
, DWORD dwMask
= 0)
2354 DWORD dwPrevStyle
= m_dwExtendedStyle
;
2356 m_dwExtendedStyle
= dwExtendedStyle
;
2358 m_dwExtendedStyle
= (m_dwExtendedStyle
& ~dwMask
) | (dwExtendedStyle
& dwMask
);
2361 T
* pT
= static_cast<T
*>(this);
2362 bool bUpdate
= false;
2364 if(((dwPrevStyle
& PANECNT_NOCLOSEBUTTON
) != 0) && ((m_dwExtendedStyle
& PANECNT_NOCLOSEBUTTON
) == 0)) // add close button
2366 pT
->CreateCloseButton();
2369 else if(((dwPrevStyle
& PANECNT_NOCLOSEBUTTON
) == 0) && ((m_dwExtendedStyle
& PANECNT_NOCLOSEBUTTON
) != 0)) // remove close button
2371 pT
->DestroyCloseButton();
2375 if((dwPrevStyle
& PANECNT_VERTICAL
) != (m_dwExtendedStyle
& PANECNT_VERTICAL
)) // change orientation
2381 if((dwPrevStyle
& (PANECNT_FLATBORDER
| PANECNT_NOBORDER
)) !=
2382 (m_dwExtendedStyle
& (PANECNT_FLATBORDER
| PANECNT_NOBORDER
))) // change border
2393 HWND
GetClient() const
2398 HWND
SetClient(HWND hWndClient
)
2400 HWND hWndOldClient
= m_wndClient
;
2401 m_wndClient
= hWndClient
;
2404 T
* pT
= static_cast<T
*>(this);
2407 return hWndOldClient
;
2410 BOOL
GetTitle(LPTSTR lpstrTitle
, int cchLength
) const
2412 ATLASSERT(lpstrTitle
!= NULL
);
2414 errno_t nRet
= SecureHelper::strncpy_x(lpstrTitle
, cchLength
, m_szTitle
, _TRUNCATE
);
2416 return (nRet
== 0 || nRet
== STRUNCATE
);
2419 BOOL
SetTitle(LPCTSTR lpstrTitle
)
2421 ATLASSERT(lpstrTitle
!= NULL
);
2423 errno_t nRet
= SecureHelper::strncpy_x(m_szTitle
, m_cchTitle
, lpstrTitle
, _TRUNCATE
);
2424 bool bRet
= (nRet
== 0 || nRet
== STRUNCATE
);
2425 if(bRet
&& m_hWnd
!= NULL
)
2427 T
* pT
= static_cast<T
*>(this);
2434 int GetTitleLength() const
2436 return lstrlen(m_szTitle
);
2440 HWND
Create(HWND hWndParent
, LPCTSTR lpstrTitle
= NULL
, DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
,
2441 DWORD dwExStyle
= 0, UINT nID
= 0, LPVOID lpCreateParam
= NULL
)
2443 if(lpstrTitle
!= NULL
)
2444 SecureHelper::strncpy_x(m_szTitle
, m_cchTitle
, lpstrTitle
, _TRUNCATE
);
2445 #if (_MSC_VER >= 1300)
2446 return ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::Create(hWndParent
, rcDefault
, NULL
, dwStyle
, dwExStyle
, nID
, lpCreateParam
);
2447 #else // !(_MSC_VER >= 1300)
2448 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
2449 return _baseClass::Create(hWndParent
, rcDefault
, NULL
, dwStyle
, dwExStyle
, nID
, lpCreateParam
);
2450 #endif // !(_MSC_VER >= 1300)
2453 HWND
Create(HWND hWndParent
, UINT uTitleID
, DWORD dwStyle
= WS_CHILD
| WS_VISIBLE
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
,
2454 DWORD dwExStyle
= 0, UINT nID
= 0, LPVOID lpCreateParam
= NULL
)
2457 ::LoadString(ModuleHelper::GetResourceInstance(), uTitleID
, m_szTitle
, m_cchTitle
);
2458 #if (_MSC_VER >= 1300)
2459 return ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::Create(hWndParent
, rcDefault
, NULL
, dwStyle
, dwExStyle
, nID
, lpCreateParam
);
2460 #else // !(_MSC_VER >= 1300)
2461 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
2462 return _baseClass::Create(hWndParent
, rcDefault
, NULL
, dwStyle
, dwExStyle
, nID
, lpCreateParam
);
2463 #endif // !(_MSC_VER >= 1300)
2466 BOOL
SubclassWindow(HWND hWnd
)
2468 #if (_MSC_VER >= 1300)
2469 BOOL bRet
= ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::SubclassWindow(hWnd
);
2470 #else // !(_MSC_VER >= 1300)
2471 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
2472 BOOL bRet
= _baseClass::SubclassWindow(hWnd
);
2473 #endif // !(_MSC_VER >= 1300)
2476 T
* pT
= static_cast<T
*>(this);
2480 GetClientRect(&rect
);
2481 pT
->UpdateLayout(rect
.right
, rect
.bottom
);
2487 BOOL
EnableCloseButton(BOOL bEnable
)
2489 ATLASSERT(::IsWindow(m_hWnd
));
2490 T
* pT
= static_cast<T
*>(this);
2491 pT
; // avoid level 4 warning
2492 return (m_tb
.m_hWnd
!= NULL
) ? m_tb
.EnableButton(pT
->m_nCloseBtnID
, bEnable
) : FALSE
;
2497 RECT rcClient
= { 0 };
2498 GetClientRect(&rcClient
);
2499 T
* pT
= static_cast<T
*>(this);
2500 pT
->UpdateLayout(rcClient
.right
, rcClient
.bottom
);
2503 // Message map and handlers
2504 BEGIN_MSG_MAP(CPaneContainerImpl
)
2505 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
2506 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
2507 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
2508 MESSAGE_HANDLER(WM_SETFOCUS
, OnSetFocus
)
2509 MESSAGE_HANDLER(WM_GETFONT
, OnGetFont
)
2510 MESSAGE_HANDLER(WM_SETFONT
, OnSetFont
)
2511 MESSAGE_HANDLER(WM_ERASEBKGND
, OnEraseBackground
)
2512 MESSAGE_HANDLER(WM_PAINT
, OnPaint
)
2514 MESSAGE_HANDLER(WM_PRINTCLIENT
, OnPaint
)
2515 #endif // !_WIN32_WCE
2516 MESSAGE_HANDLER(WM_NOTIFY
, OnNotify
)
2517 MESSAGE_HANDLER(WM_COMMAND
, OnCommand
)
2518 FORWARD_NOTIFICATIONS()
2521 LRESULT
OnCreate(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
2523 T
* pT
= static_cast<T
*>(this);
2529 LRESULT
OnDestroy(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
2533 ::DeleteObject(m_hFont
);
2535 m_bInternalFont
= false;
2541 LRESULT
OnSize(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& /*bHandled*/)
2543 T
* pT
= static_cast<T
*>(this);
2544 pT
->UpdateLayout(GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
));
2548 LRESULT
OnSetFocus(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
2550 if(m_wndClient
.m_hWnd
!= NULL
)
2551 m_wndClient
.SetFocus();
2555 LRESULT
OnGetFont(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
2557 return (LRESULT
)m_hFont
;
2560 LRESULT
OnSetFont(UINT
/*uMsg*/, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
2564 ::DeleteObject(m_hFont
);
2565 m_bInternalFont
= false;
2568 m_hFont
= (HFONT
)wParam
;
2570 T
* pT
= static_cast<T
*>(this);
2573 if((BOOL
)lParam
!= FALSE
)
2579 LRESULT
OnEraseBackground(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
2581 return 1; // no background needed
2584 LRESULT
OnPaint(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
2586 T
* pT
= static_cast<T
*>(this);
2589 pT
->DrawPaneTitle((HDC
)wParam
);
2591 if(m_wndClient
.m_hWnd
== NULL
) // no client window
2592 pT
->DrawPane((HDC
)wParam
);
2596 CPaintDC
dc(m_hWnd
);
2597 pT
->DrawPaneTitle(dc
.m_hDC
);
2599 if(m_wndClient
.m_hWnd
== NULL
) // no client window
2600 pT
->DrawPane(dc
.m_hDC
);
2606 LRESULT
OnNotify(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
2608 if(m_tb
.m_hWnd
== NULL
)
2614 T
* pT
= static_cast<T
*>(this);
2616 LPNMHDR lpnmh
= (LPNMHDR
)lParam
;
2619 // pass toolbar custom draw notifications to the base class
2620 if(lpnmh
->code
== NM_CUSTOMDRAW
&& lpnmh
->hwndFrom
== m_tb
.m_hWnd
)
2621 lRet
= CCustomDraw
< T
>::OnCustomDraw(0, lpnmh
, bHandled
);
2623 // tooltip notifications come with the tooltip window handle and button ID,
2624 // pass them to the parent if we don't handle them
2625 else if(lpnmh
->code
== TTN_GETDISPINFO
&& lpnmh
->idFrom
== pT
->m_nCloseBtnID
)
2626 bHandled
= pT
->GetToolTipText(lpnmh
);
2627 #endif // !_WIN32_WCE
2628 // only let notifications not from the toolbar go to the parent
2629 else if(lpnmh
->hwndFrom
!= m_tb
.m_hWnd
&& lpnmh
->idFrom
!= pT
->m_nCloseBtnID
)
2635 LRESULT
OnCommand(UINT
/*uMsg*/, WPARAM wParam
, LPARAM lParam
, BOOL
& bHandled
)
2637 // if command comes from the close button, substitute HWND of the pane container instead
2638 if(m_tb
.m_hWnd
!= NULL
&& (HWND
)lParam
== m_tb
.m_hWnd
)
2639 return ::SendMessage(GetParent(), WM_COMMAND
, wParam
, (LPARAM
)m_hWnd
);
2645 // Custom draw overrides
2646 DWORD
OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW
/*lpNMCustomDraw*/)
2648 return CDRF_NOTIFYITEMDRAW
; // we need per-item notifications
2651 DWORD
OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw
)
2653 CDCHandle dc
= lpNMCustomDraw
->hdc
;
2654 #if (_WIN32_IE >= 0x0400)
2655 RECT
& rc
= lpNMCustomDraw
->rc
;
2656 #else // !(_WIN32_IE >= 0x0400)
2658 m_tb
.GetItemRect(0, &rc
);
2659 #endif // !(_WIN32_IE >= 0x0400)
2661 dc
.FillRect(&rc
, COLOR_3DFACE
);
2663 return CDRF_NOTIFYPOSTPAINT
;
2666 DWORD
OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw
)
2668 CDCHandle dc
= lpNMCustomDraw
->hdc
;
2669 #if (_WIN32_IE >= 0x0400)
2670 RECT
& rc
= lpNMCustomDraw
->rc
;
2671 #else // !(_WIN32_IE >= 0x0400)
2673 m_tb
.GetItemRect(0, &rc
);
2674 #endif // !(_WIN32_IE >= 0x0400)
2676 RECT rcImage
= { m_xBtnImageLeft
, m_yBtnImageTop
, m_xBtnImageRight
+ 1, m_yBtnImageBottom
+ 1 };
2677 ::OffsetRect(&rcImage
, rc
.left
, rc
.top
);
2678 T
* pT
= static_cast<T
*>(this);
2680 if((lpNMCustomDraw
->uItemState
& CDIS_DISABLED
) != 0)
2682 RECT rcShadow
= rcImage
;
2683 ::OffsetRect(&rcShadow
, 1, 1);
2685 pen1
.CreatePen(PS_SOLID
, 0, ::GetSysColor(COLOR_3DHILIGHT
));
2686 pT
->DrawButtonImage(dc
, rcShadow
, pen1
);
2688 pen2
.CreatePen(PS_SOLID
, 0, ::GetSysColor(COLOR_3DSHADOW
));
2689 pT
->DrawButtonImage(dc
, rcImage
, pen2
);
2693 if((lpNMCustomDraw
->uItemState
& CDIS_SELECTED
) != 0)
2694 ::OffsetRect(&rcImage
, 1, 1);
2696 pen
.CreatePen(PS_SOLID
, 0, ::GetSysColor(COLOR_BTNTEXT
));
2697 pT
->DrawButtonImage(dc
, rcImage
, pen
);
2700 return CDRF_DODEFAULT
; // continue with the default item painting
2703 // Implementation - overrideable methods
2708 // The same as AtlCreateControlFont() for horizontal pane
2711 ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT
, sizeof(LOGFONT
), &lf
, 0) != FALSE
);
2713 lf
.lfEscapement
= 900; // 90 degrees
2714 m_hFont
= ::CreateFontIndirect(&lf
);
2715 #else // CE specific
2716 m_hFont
= (HFONT
)::GetStockObject(SYSTEM_FONT
);
2719 CLogFont
lf(m_hFont
);
2720 lf
.lfEscapement
= 900; // 90 degrees
2721 m_hFont
= ::CreateFontIndirect(&lf
);
2723 #endif // _WIN32_WCE
2724 m_bInternalFont
= true;
2727 T
* pT
= static_cast<T
*>(this);
2730 if((m_dwExtendedStyle
& PANECNT_NOCLOSEBUTTON
) == 0)
2731 pT
->CreateCloseButton();
2734 void UpdateLayout(int cxWidth
, int cyHeight
)
2736 ATLASSERT(::IsWindow(m_hWnd
));
2741 ::SetRect(&rect
, 0, 0, m_cxyHeader
, cyHeight
);
2742 if(m_tb
.m_hWnd
!= NULL
)
2743 m_tb
.SetWindowPos(NULL
, m_cxyBorder
, m_cxyBorder
+ m_cxyBtnOffset
, 0, 0, SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
2745 if(m_wndClient
.m_hWnd
!= NULL
)
2746 m_wndClient
.SetWindowPos(NULL
, m_cxyHeader
, 0, cxWidth
- m_cxyHeader
, cyHeight
, SWP_NOZORDER
);
2748 rect
.right
= cxWidth
;
2752 ::SetRect(&rect
, 0, 0, cxWidth
, m_cxyHeader
);
2753 if(m_tb
.m_hWnd
!= NULL
)
2754 m_tb
.SetWindowPos(NULL
, rect
.right
- m_cxToolBar
, m_cxyBorder
+ m_cxyBtnOffset
, 0, 0, SWP_NOZORDER
| SWP_NOSIZE
| SWP_NOACTIVATE
);
2756 if(m_wndClient
.m_hWnd
!= NULL
)
2757 m_wndClient
.SetWindowPos(NULL
, 0, m_cxyHeader
, cxWidth
, cyHeight
- m_cxyHeader
, SWP_NOZORDER
);
2759 rect
.bottom
= cyHeight
;
2762 InvalidateRect(&rect
);
2765 void CreateCloseButton()
2767 ATLASSERT(m_tb
.m_hWnd
== NULL
);
2768 // create toolbar for the "x" button
2769 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);
2770 ATLASSERT(m_tb
.IsWindow());
2772 if(m_tb
.m_hWnd
!= NULL
)
2774 T
* pT
= static_cast<T
*>(this);
2775 pT
; // avoid level 4 warning
2777 m_tb
.SetButtonStructSize();
2779 TBBUTTON tbbtn
= { 0 };
2780 tbbtn
.idCommand
= pT
->m_nCloseBtnID
;
2781 tbbtn
.fsState
= TBSTATE_ENABLED
;
2782 tbbtn
.fsStyle
= BTNS_BUTTON
;
2783 m_tb
.AddButtons(1, &tbbtn
);
2785 m_tb
.SetBitmapSize(m_cxImageTB
, m_cyImageTB
);
2786 m_tb
.SetButtonSize(m_cxImageTB
+ m_cxyBtnAddTB
, m_cyImageTB
+ m_cxyBtnAddTB
);
2789 m_tb
.SetWindowPos(NULL
, m_cxyBorder
+ m_cxyBtnOffset
, m_cxyBorder
+ m_cxyBtnOffset
, m_cxImageTB
+ m_cxyBtnAddTB
, m_cyImageTB
+ m_cxyBtnAddTB
, SWP_NOZORDER
| SWP_NOACTIVATE
);
2791 m_tb
.SetWindowPos(NULL
, 0, 0, m_cxImageTB
+ m_cxyBtnAddTB
, m_cyImageTB
+ m_cxyBtnAddTB
, SWP_NOZORDER
| SWP_NOMOVE
| SWP_NOACTIVATE
);
2795 void DestroyCloseButton()
2797 if(m_tb
.m_hWnd
!= NULL
)
2798 m_tb
.DestroyWindow();
2803 T
* pT
= static_cast<T
*>(this);
2804 CFontHandle font
= pT
->GetTitleFont();
2806 font
= (HFONT
)::GetStockObject(SYSTEM_FONT
);
2808 font
.GetLogFont(lf
);
2811 m_cxyHeader
= m_cxImageTB
+ m_cxyBtnAddTB
+ m_cxyBorder
;
2815 int cyFont
= abs(lf
.lfHeight
) + m_cxyBorder
+ 2 * m_cxyTextOffset
;
2816 int cyBtn
= m_cyImageTB
+ m_cxyBtnAddTB
+ m_cxyBorder
+ 2 * m_cxyBtnOffset
;
2817 m_cxyHeader
= __max(cyFont
, cyBtn
);
2821 HFONT
GetTitleFont() const
2827 BOOL
GetToolTipText(LPNMHDR
/*lpnmh*/)
2831 #endif // !_WIN32_WCE
2833 void DrawPaneTitle(CDCHandle dc
)
2836 GetClientRect(&rect
);
2838 UINT uBorder
= BF_LEFT
| BF_TOP
| BF_ADJUST
;
2841 rect
.right
= rect
.left
+ m_cxyHeader
;
2842 uBorder
|= BF_BOTTOM
;
2846 rect
.bottom
= rect
.top
+ m_cxyHeader
;
2847 uBorder
|= BF_RIGHT
;
2850 if((m_dwExtendedStyle
& PANECNT_NOBORDER
) == 0)
2852 if((m_dwExtendedStyle
& PANECNT_FLATBORDER
) != 0)
2854 dc
.DrawEdge(&rect
, EDGE_ETCHED
, uBorder
);
2856 dc
.FillRect(&rect
, COLOR_3DFACE
);
2859 dc
.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT
));
2860 dc
.SetBkMode(TRANSPARENT
);
2861 T
* pT
= static_cast<T
*>(this);
2862 HFONT hFontOld
= dc
.SelectFont(pT
->GetTitleFont());
2863 #if defined(_WIN32_WCE) && !defined(DT_END_ELLIPSIS)
2864 const UINT DT_END_ELLIPSIS
= 0;
2865 #endif // defined(_WIN32_WCE) && !defined(DT_END_ELLIPSIS)
2869 rect
.top
+= m_cxyTextOffset
;
2870 rect
.bottom
-= m_cxyTextOffset
;
2871 if(m_tb
.m_hWnd
!= NULL
)
2872 rect
.top
+= m_cxToolBar
;;
2874 RECT rcCalc
= { rect
.left
, rect
.bottom
, rect
.right
, rect
.top
};
2875 int cxFont
= dc
.DrawText(m_szTitle
, -1, &rcCalc
, DT_TOP
| DT_SINGLELINE
| DT_END_ELLIPSIS
| DT_CALCRECT
);
2876 RECT rcText
= { 0 };
2877 rcText
.left
= (rect
.right
- rect
.left
- cxFont
) / 2;
2878 rcText
.right
= rcText
.left
+ (rect
.bottom
- rect
.top
);
2879 rcText
.top
= rect
.bottom
;
2880 rcText
.bottom
= rect
.top
;
2881 dc
.DrawText(m_szTitle
, -1, &rcText
, DT_TOP
| DT_SINGLELINE
| DT_END_ELLIPSIS
);
2885 rect
.left
+= m_cxyTextOffset
;
2886 rect
.right
-= m_cxyTextOffset
;
2887 if(m_tb
.m_hWnd
!= NULL
)
2888 rect
.right
-= m_cxToolBar
;;
2890 dc
.DrawText(m_szTitle
, -1, &rect
, DT_LEFT
| DT_SINGLELINE
| DT_VCENTER
| DT_END_ELLIPSIS
);
2893 dc
.SelectFont(hFontOld
);
2896 // called only if pane is empty
2897 void DrawPane(CDCHandle dc
)
2900 GetClientRect(&rect
);
2902 rect
.left
+= m_cxyHeader
;
2904 rect
.top
+= m_cxyHeader
;
2905 if((GetExStyle() & WS_EX_CLIENTEDGE
) == 0)
2906 dc
.DrawEdge(&rect
, EDGE_SUNKEN
, BF_RECT
| BF_ADJUST
);
2907 dc
.FillRect(&rect
, COLOR_APPWORKSPACE
);
2910 // drawing helper - draws "x" button image
2911 void DrawButtonImage(CDCHandle dc
, RECT
& rcImage
, HPEN hPen
)
2913 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
2914 HPEN hPenOld
= dc
.SelectPen(hPen
);
2916 dc
.MoveTo(rcImage
.left
, rcImage
.top
);
2917 dc
.LineTo(rcImage
.right
, rcImage
.bottom
);
2918 dc
.MoveTo(rcImage
.left
+ 1, rcImage
.top
);
2919 dc
.LineTo(rcImage
.right
+ 1, rcImage
.bottom
);
2921 dc
.MoveTo(rcImage
.left
, rcImage
.bottom
- 1);
2922 dc
.LineTo(rcImage
.right
, rcImage
.top
- 1);
2923 dc
.MoveTo(rcImage
.left
+ 1, rcImage
.bottom
- 1);
2924 dc
.LineTo(rcImage
.right
+ 1, rcImage
.top
- 1);
2926 dc
.SelectPen(hPenOld
);
2927 #else // (_WIN32_WCE < 400)
2930 // no support for the "x" button image
2931 #endif // (_WIN32_WCE < 400)
2934 bool IsVertical() const
2936 return ((m_dwExtendedStyle
& PANECNT_VERTICAL
) != 0);
2940 class CPaneContainer
: public CPaneContainerImpl
<CPaneContainer
>
2943 DECLARE_WND_CLASS_EX(_T("WTL_PaneContainer"), 0, -1)
2947 ///////////////////////////////////////////////////////////////////////////////
2948 // CSortListViewCtrl - implements sorting for a listview control
2950 // sort listview extended styles
2951 #define SORTLV_USESHELLBITMAPS 0x00000001
2953 // Notification sent to parent when sort column is changed by user clicking header.
2954 #define SLVN_SORTCHANGED LVN_LAST
2956 // A LPNMSORTLISTVIEW is sent with the SLVN_SORTCHANGED notification
2957 typedef struct tagNMSORTLISTVIEW
2962 } NMSORTLISTVIEW
, *LPNMSORTLISTVIEW
;
2964 // Column sort types. Can be set on a per-column basis with the SetColumnSortType method.
2968 LVCOLSORT_TEXT
, // default
2969 LVCOLSORT_TEXTNOCASE
,
2977 LVCOLSORT_LAST
= LVCOLSORT_CUSTOM
2982 class CSortListViewImpl
2987 m_cchCmpTextMax
= 32, // overrideable
2992 m_iSortUp
= 0, // index of sort bitmaps
2994 m_nShellSortUpID
= 133
2997 // passed to LVCompare functions as lParam1 and lParam2
2998 struct LVCompareParam
3001 DWORD_PTR dwItemData
;
3011 // passed to LVCompare functions as the lParamSort parameter
3019 bool m_bSortDescending
;
3022 CBitmap m_bmSort
[2];
3023 int m_fmtOldSortCol
;
3024 HBITMAP m_hbmOldSortCol
;
3025 DWORD m_dwSortLVExtendedStyle
;
3026 ATL::CSimpleArray
<WORD
> m_arrColSortType
;
3027 bool m_bUseWaitCursor
;
3029 CSortListViewImpl() :
3030 m_bSortDescending(false),
3031 m_bCommCtrl6(false),
3034 m_hbmOldSortCol(NULL
),
3035 m_dwSortLVExtendedStyle(SORTLV_USESHELLBITMAPS
),
3036 m_bUseWaitCursor(true)
3041 HRESULT hRet
= ATL::AtlGetCommCtrlVersion(&dwMajor
, &dwMinor
);
3042 m_bCommCtrl6
= SUCCEEDED(hRet
) && dwMajor
>= 6;
3043 #endif // !_WIN32_WCE
3047 void SetSortColumn(int iCol
)
3049 T
* pT
= static_cast<T
*>(this);
3050 ATLASSERT(::IsWindow(pT
->m_hWnd
));
3051 CHeaderCtrl header
= pT
->GetHeader();
3052 ATLASSERT(header
.m_hWnd
!= NULL
);
3053 ATLASSERT(iCol
>= -1 && iCol
< m_arrColSortType
.GetSize());
3055 int iOldSortCol
= m_iSortColumn
;
3056 m_iSortColumn
= iCol
;
3060 const int HDF_SORTUP
= 0x0400;
3061 #endif // HDF_SORTUP
3062 #ifndef HDF_SORTDOWN
3063 const int HDF_SORTDOWN
= 0x0200;
3064 #endif // HDF_SORTDOWN
3065 const int nMask
= HDF_SORTUP
| HDF_SORTDOWN
;
3066 HDITEM hditem
= { HDI_FORMAT
};
3067 if(iOldSortCol
!= iCol
&& iOldSortCol
>= 0 && header
.GetItem(iOldSortCol
, &hditem
))
3069 hditem
.fmt
&= ~nMask
;
3070 header
.SetItem(iOldSortCol
, &hditem
);
3072 if(iCol
>= 0 && header
.GetItem(iCol
, &hditem
))
3074 hditem
.fmt
&= ~nMask
;
3075 hditem
.fmt
|= m_bSortDescending
? HDF_SORTDOWN
: HDF_SORTUP
;
3076 header
.SetItem(iCol
, &hditem
);
3081 if(m_bmSort
[m_iSortUp
].IsNull())
3082 pT
->CreateSortBitmaps();
3084 // restore previous sort column's bitmap, if any, and format
3085 HDITEM hditem
= { HDI_BITMAP
| HDI_FORMAT
};
3086 if(iOldSortCol
!= iCol
&& iOldSortCol
>= 0)
3088 hditem
.hbm
= m_hbmOldSortCol
;
3089 hditem
.fmt
= m_fmtOldSortCol
;
3090 header
.SetItem(iOldSortCol
, &hditem
);
3093 // save new sort column's bitmap and format, and add our sort bitmap
3094 if(iCol
>= 0 && header
.GetItem(iCol
, &hditem
))
3096 if(iOldSortCol
!= iCol
)
3098 m_fmtOldSortCol
= hditem
.fmt
;
3099 m_hbmOldSortCol
= hditem
.hbm
;
3101 hditem
.fmt
&= ~HDF_IMAGE
;
3102 hditem
.fmt
|= HDF_BITMAP
| HDF_BITMAP_ON_RIGHT
;
3103 int i
= m_bSortDescending
? m_iSortDown
: m_iSortUp
;
3104 hditem
.hbm
= m_bmSort
[i
];
3105 header
.SetItem(iCol
, &hditem
);
3109 int GetSortColumn() const
3111 return m_iSortColumn
;
3114 void SetColumnSortType(int iCol
, WORD wType
)
3116 ATLASSERT(iCol
>= 0 && iCol
< m_arrColSortType
.GetSize());
3117 ATLASSERT(wType
>= LVCOLSORT_NONE
&& wType
<= LVCOLSORT_LAST
);
3118 m_arrColSortType
[iCol
] = wType
;
3121 WORD
GetColumnSortType(int iCol
) const
3123 ATLASSERT((iCol
>= 0) && iCol
< m_arrColSortType
.GetSize());
3124 return m_arrColSortType
[iCol
];
3127 int GetColumnCount() const
3129 const T
* pT
= static_cast<const T
*>(this);
3130 ATLASSERT(::IsWindow(pT
->m_hWnd
));
3131 CHeaderCtrl header
= pT
->GetHeader();
3132 return header
.m_hWnd
!= NULL
? header
.GetItemCount() : 0;
3135 bool IsSortDescending() const
3137 return m_bSortDescending
;
3140 DWORD
GetSortListViewExtendedStyle() const
3142 return m_dwSortLVExtendedStyle
;
3145 DWORD
SetSortListViewExtendedStyle(DWORD dwExtendedStyle
, DWORD dwMask
= 0)
3147 DWORD dwPrevStyle
= m_dwSortLVExtendedStyle
;
3149 m_dwSortLVExtendedStyle
= dwExtendedStyle
;
3151 m_dwSortLVExtendedStyle
= (m_dwSortLVExtendedStyle
& ~dwMask
) | (dwExtendedStyle
& dwMask
);
3156 bool DoSortItems(int iCol
, bool bDescending
= false)
3158 T
* pT
= static_cast<T
*>(this);
3159 ATLASSERT(::IsWindow(pT
->m_hWnd
));
3160 ATLASSERT(iCol
>= 0 && iCol
< m_arrColSortType
.GetSize());
3162 WORD wType
= m_arrColSortType
[iCol
];
3163 if(wType
== LVCOLSORT_NONE
)
3166 int nCount
= pT
->GetItemCount();
3169 m_bSortDescending
= bDescending
;
3170 SetSortColumn(iCol
);
3174 CWaitCursor
waitCursor(false);
3175 if(m_bUseWaitCursor
)
3178 LVCompareParam
* pParam
= NULL
;
3179 ATLTRY(pParam
= new LVCompareParam
[nCount
]);
3180 PFNLVCOMPARE pFunc
= NULL
;
3181 TCHAR pszTemp
[pT
->m_cchCmpTextMax
] = { 0 };
3182 bool bStrValue
= false;
3186 case LVCOLSORT_TEXT
:
3187 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareText
;
3188 case LVCOLSORT_TEXTNOCASE
:
3190 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareTextNoCase
;
3191 case LVCOLSORT_CUSTOM
:
3194 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareCustom
;
3196 for(int i
= 0; i
< nCount
; i
++)
3198 pParam
[i
].iItem
= i
;
3199 pParam
[i
].dwItemData
= pT
->GetItemData(i
);
3200 pParam
[i
].pszValue
= new TCHAR
[pT
->m_cchCmpTextMax
];
3201 pT
->GetItemText(i
, iCol
, (LPTSTR
)pParam
[i
].pszValue
, pT
->m_cchCmpTextMax
);
3202 pT
->SetItemData(i
, (DWORD_PTR
)&pParam
[i
]);
3207 case LVCOLSORT_LONG
:
3209 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareLong
;
3210 for(int i
= 0; i
< nCount
; i
++)
3212 pParam
[i
].iItem
= i
;
3213 pParam
[i
].dwItemData
= pT
->GetItemData(i
);
3214 pT
->GetItemText(i
, iCol
, pszTemp
, pT
->m_cchCmpTextMax
);
3215 pParam
[i
].lValue
= pT
->StrToLong(pszTemp
);
3216 pT
->SetItemData(i
, (DWORD_PTR
)&pParam
[i
]);
3220 case LVCOLSORT_DOUBLE
:
3222 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareDouble
;
3223 for(int i
= 0; i
< nCount
; i
++)
3225 pParam
[i
].iItem
= i
;
3226 pParam
[i
].dwItemData
= pT
->GetItemData(i
);
3227 pT
->GetItemText(i
, iCol
, pszTemp
, pT
->m_cchCmpTextMax
);
3228 pParam
[i
].dblValue
= pT
->StrToDouble(pszTemp
);
3229 pT
->SetItemData(i
, (DWORD_PTR
)&pParam
[i
]);
3233 case LVCOLSORT_DECIMAL
:
3235 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareDecimal
;
3236 for(int i
= 0; i
< nCount
; i
++)
3238 pParam
[i
].iItem
= i
;
3239 pParam
[i
].dwItemData
= pT
->GetItemData(i
);
3240 pT
->GetItemText(i
, iCol
, pszTemp
, pT
->m_cchCmpTextMax
);
3241 pT
->StrToDecimal(pszTemp
, &pParam
[i
].decValue
);
3242 pT
->SetItemData(i
, (DWORD_PTR
)&pParam
[i
]);
3246 case LVCOLSORT_DATETIME
:
3247 case LVCOLSORT_DATE
:
3248 case LVCOLSORT_TIME
:
3250 pFunc
= (PFNLVCOMPARE
)pT
->LVCompareDouble
;
3251 DWORD dwFlags
= LOCALE_NOUSEROVERRIDE
;
3252 if(wType
== LVCOLSORT_DATE
)
3253 dwFlags
|= VAR_DATEVALUEONLY
;
3254 else if(wType
== LVCOLSORT_TIME
)
3255 dwFlags
|= VAR_TIMEVALUEONLY
;
3256 for(int i
= 0; i
< nCount
; i
++)
3258 pParam
[i
].iItem
= i
;
3259 pParam
[i
].dwItemData
= pT
->GetItemData(i
);
3260 pT
->GetItemText(i
, iCol
, pszTemp
, pT
->m_cchCmpTextMax
);
3261 pParam
[i
].dblValue
= pT
->DateStrToDouble(pszTemp
, dwFlags
);
3262 pT
->SetItemData(i
, (DWORD_PTR
)&pParam
[i
]);
3267 ATLTRACE2(atlTraceUI
, 0, _T("Unknown value for sort type in CSortListViewImpl::DoSortItems()\n"));
3271 ATLASSERT(pFunc
!= NULL
);
3272 LVSortInfo lvsi
= { pT
, iCol
, bDescending
};
3273 bool bRet
= ((BOOL
)pT
->DefWindowProc(LVM_SORTITEMS
, (WPARAM
)&lvsi
, (LPARAM
)pFunc
) != FALSE
);
3274 for(int i
= 0; i
< nCount
; i
++)
3276 DWORD_PTR dwItemData
= pT
->GetItemData(i
);
3277 LVCompareParam
* p
= (LVCompareParam
*)dwItemData
;
3278 ATLASSERT(p
!= NULL
);
3280 delete [] (TCHAR
*)p
->pszValue
;
3281 pT
->SetItemData(i
, p
->dwItemData
);
3287 m_bSortDescending
= bDescending
;
3288 SetSortColumn(iCol
);
3291 if(m_bUseWaitCursor
)
3292 waitCursor
.Restore();
3297 void CreateSortBitmaps()
3299 if((m_dwSortLVExtendedStyle
& SORTLV_USESHELLBITMAPS
) != 0)
3302 LPCTSTR pszModule
= _T("shell32.dll");
3303 HINSTANCE hShell
= ::GetModuleHandle(pszModule
);
3307 hShell
= ::LoadLibrary(pszModule
);
3313 bool bSuccess
= true;
3314 for(int i
= m_iSortUp
; i
<= m_iSortDown
; i
++)
3316 if(!m_bmSort
[i
].IsNull())
3317 m_bmSort
[i
].DeleteObject();
3318 m_bmSort
[i
] = (HBITMAP
)::LoadImage(hShell
, MAKEINTRESOURCE(m_nShellSortUpID
+ i
),
3320 IMAGE_BITMAP
, 0, 0, LR_LOADMAP3DCOLORS
);
3321 #else // CE specific
3322 IMAGE_BITMAP
, 0, 0, 0);
3323 #endif // _WIN32_WCE
3324 if(m_bmSort
[i
].IsNull())
3331 ::FreeLibrary(hShell
);
3337 T
* pT
= static_cast<T
*>(this);
3338 for(int i
= m_iSortUp
; i
<= m_iSortDown
; i
++)
3340 if(!m_bmSort
[i
].IsNull())
3341 m_bmSort
[i
].DeleteObject();
3344 CClientDC
dc(::GetDesktopWindow());
3345 dcMem
.CreateCompatibleDC(dc
.m_hDC
);
3346 m_bmSort
[i
].CreateCompatibleBitmap(dc
.m_hDC
, m_cxSortImage
, m_cySortImage
);
3347 HBITMAP hbmOld
= dcMem
.SelectBitmap(m_bmSort
[i
]);
3348 RECT rc
= { 0, 0, m_cxSortImage
, m_cySortImage
};
3349 pT
->DrawSortBitmap(dcMem
.m_hDC
, i
, &rc
);
3350 dcMem
.SelectBitmap(hbmOld
);
3355 void NotifyParentSortChanged(int iNewSortCol
, int iOldSortCol
)
3357 T
* pT
= static_cast<T
*>(this);
3358 int nID
= pT
->GetDlgCtrlID();
3359 NMSORTLISTVIEW nm
= { { pT
->m_hWnd
, nID
, SLVN_SORTCHANGED
}, iNewSortCol
, iOldSortCol
};
3360 ::SendMessage(pT
->GetParent(), WM_NOTIFY
, (WPARAM
)nID
, (LPARAM
)&nm
);
3364 int CompareItemsCustom(LVCompareParam
* /*pItem1*/, LVCompareParam
* /*pItem2*/, int /*iSortCol*/)
3366 // pItem1 and pItem2 contain valid iItem, dwItemData, and pszValue members.
3367 // If item1 > item2 return 1, if item1 < item2 return -1, else return 0.
3371 void DrawSortBitmap(CDCHandle dc
, int iBitmap
, LPRECT prc
)
3373 dc
.FillRect(prc
, ::GetSysColorBrush(COLOR_BTNFACE
));
3374 HBRUSH hbrOld
= dc
.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW
));
3376 pen
.CreatePen(PS_SOLID
, 0, ::GetSysColor(COLOR_BTNSHADOW
));
3377 HPEN hpenOld
= dc
.SelectPen(pen
);
3378 POINT ptOrg
= { (m_cxSortImage
- m_cxSortArrow
) / 2, (m_cySortImage
- m_cySortArrow
) / 2 };
3379 if(iBitmap
== m_iSortUp
)
3383 { ptOrg
.x
+ m_cxSortArrow
/ 2, ptOrg
.y
},
3384 { ptOrg
.x
, ptOrg
.y
+ m_cySortArrow
- 1 },
3385 { ptOrg
.x
+ m_cxSortArrow
- 1, ptOrg
.y
+ m_cySortArrow
- 1 }
3393 { ptOrg
.x
, ptOrg
.y
},
3394 { ptOrg
.x
+ m_cxSortArrow
/ 2, ptOrg
.y
+ m_cySortArrow
- 1 },
3395 { ptOrg
.x
+ m_cxSortArrow
- 1, ptOrg
.y
}
3399 dc
.SelectBrush(hbrOld
);
3400 dc
.SelectPen(hpenOld
);
3403 double DateStrToDouble(LPCTSTR lpstr
, DWORD dwFlags
)
3405 ATLASSERT(lpstr
!= NULL
);
3406 if(lpstr
== NULL
|| lpstr
[0] == _T('\0'))
3410 HRESULT hRet
= E_FAIL
;
3412 if (FAILED(hRet
= ::VarDateFromStr((LPOLESTR
)T2COLE(lpstr
), LANG_USER_DEFAULT
, dwFlags
, &dRet
)))
3414 ATLTRACE2(atlTraceUI
, 0, _T("VarDateFromStr failed with result of 0x%8.8X\n"), hRet
);
3420 long StrToLong(LPCTSTR lpstr
)
3422 ATLASSERT(lpstr
!= NULL
);
3423 if(lpstr
== NULL
|| lpstr
[0] == _T('\0'))
3427 HRESULT hRet
= E_FAIL
;
3429 if (FAILED(hRet
= ::VarI4FromStr((LPOLESTR
)T2COLE(lpstr
), LANG_USER_DEFAULT
, LOCALE_NOUSEROVERRIDE
, &lRet
)))
3431 ATLTRACE2(atlTraceUI
, 0, _T("VarI4FromStr failed with result of 0x%8.8X\n"), hRet
);
3437 double StrToDouble(LPCTSTR lpstr
)
3439 ATLASSERT(lpstr
!= NULL
);
3440 if(lpstr
== NULL
|| lpstr
[0] == _T('\0'))
3444 HRESULT hRet
= E_FAIL
;
3446 if (FAILED(hRet
= ::VarR8FromStr((LPOLESTR
)T2COLE(lpstr
), LANG_USER_DEFAULT
, LOCALE_NOUSEROVERRIDE
, &dblRet
)))
3448 ATLTRACE2(atlTraceUI
, 0, _T("VarR8FromStr failed with result of 0x%8.8X\n"), hRet
);
3454 bool StrToDecimal(LPCTSTR lpstr
, DECIMAL
* pDecimal
)
3456 ATLASSERT(lpstr
!= NULL
);
3457 ATLASSERT(pDecimal
!= NULL
);
3458 if(lpstr
== NULL
|| pDecimal
== NULL
)
3462 HRESULT hRet
= E_FAIL
;
3463 if (FAILED(hRet
= ::VarDecFromStr((LPOLESTR
)T2COLE(lpstr
), LANG_USER_DEFAULT
, LOCALE_NOUSEROVERRIDE
, pDecimal
)))
3465 ATLTRACE2(atlTraceUI
, 0, _T("VarDecFromStr failed with result of 0x%8.8X\n"), hRet
);
3468 pDecimal
->signscale
= 0;
3474 // Overrideable PFNLVCOMPARE functions
3475 static int CALLBACK
LVCompareText(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3477 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3479 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3480 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3481 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3483 int nRet
= lstrcmp(pParam1
->pszValue
, pParam2
->pszValue
);
3484 return pInfo
->bDescending
? -nRet
: nRet
;
3487 static int CALLBACK
LVCompareTextNoCase(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3489 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3491 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3492 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3493 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3495 int nRet
= lstrcmpi(pParam1
->pszValue
, pParam2
->pszValue
);
3496 return pInfo
->bDescending
? -nRet
: nRet
;
3499 static int CALLBACK
LVCompareLong(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3501 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3503 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3504 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3505 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3508 if(pParam1
->lValue
> pParam2
->lValue
)
3510 else if(pParam1
->lValue
< pParam2
->lValue
)
3512 return pInfo
->bDescending
? -nRet
: nRet
;
3515 static int CALLBACK
LVCompareDouble(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3517 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3519 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3520 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3521 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3524 if(pParam1
->dblValue
> pParam2
->dblValue
)
3526 else if(pParam1
->dblValue
< pParam2
->dblValue
)
3528 return pInfo
->bDescending
? -nRet
: nRet
;
3531 static int CALLBACK
LVCompareCustom(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3533 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3535 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3536 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3537 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3539 int nRet
= pInfo
->pT
->CompareItemsCustom(pParam1
, pParam2
, pInfo
->iSortCol
);
3540 return pInfo
->bDescending
? -nRet
: nRet
;
3544 static int CALLBACK
LVCompareDecimal(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3546 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3548 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3549 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3550 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3552 int nRet
= (int)::VarDecCmp(&pParam1
->decValue
, &pParam2
->decValue
);
3554 return pInfo
->bDescending
? -nRet
: nRet
;
3557 // Compare mantissas, ignore sign and scale
3558 static int CompareMantissas(const DECIMAL
& decLeft
, const DECIMAL
& decRight
)
3560 if (decLeft
.Hi32
< decRight
.Hi32
)
3564 if (decLeft
.Hi32
> decRight
.Hi32
)
3568 // Here, decLeft.Hi32 == decRight.Hi32
3569 if (decLeft
.Lo64
< decRight
.Lo64
)
3573 if (decLeft
.Lo64
> decRight
.Lo64
)
3580 // return values: VARCMP_LT, VARCMP_EQ, VARCMP_GT, VARCMP_NULL
3581 static HRESULT
VarDecCmp(const DECIMAL
* pdecLeft
, const DECIMAL
* pdecRight
)
3583 static const ULONG powersOfTen
[] =
3595 static const int largestPower
= sizeof(powersOfTen
) / sizeof(powersOfTen
[0]);
3596 if (!pdecLeft
|| !pdecRight
)
3601 // Degenerate case - at least one comparand is of the form
3602 // [+-]0*10^N (denormalized zero)
3603 bool bLeftZero
= (!pdecLeft
->Lo64
&& !pdecLeft
->Hi32
);
3604 bool bRightZero
= (!pdecRight
->Lo64
&& !pdecRight
->Hi32
);
3605 if (bLeftZero
&& bRightZero
)
3609 bool bLeftNeg
= ((pdecLeft
->sign
& DECIMAL_NEG
) != 0);
3610 bool bRightNeg
= ((pdecRight
->sign
& DECIMAL_NEG
) != 0);
3613 return (bRightNeg
? VARCMP_GT
: VARCMP_LT
);
3615 // This also covers the case where the comparands have different signs
3616 if (bRightZero
|| bLeftNeg
!= bRightNeg
)
3618 return (bLeftNeg
? VARCMP_LT
: VARCMP_GT
);
3621 // Here both comparands have the same sign and need to be compared
3622 // on mantissa and scale. The result is obvious when
3623 // 1. Scales are equal (then compare mantissas)
3624 // 2. A number with smaller scale is also the one with larger mantissa
3625 // (then this number is obviously larger)
3626 // In the remaining case, we would multiply the number with smaller
3627 // scale by 10 and simultaneously increment its scale (which amounts to
3628 // adding trailing zeros after decimal point), until the numbers fall under
3629 // one of the two cases above
3631 bool bInvert
= bLeftNeg
; // the final result needs to be inverted
3632 if (pdecLeft
->scale
< pdecRight
->scale
)
3639 pdecRight
= pdecLeft
;
3643 // Now temp is the number with smaller (or equal) scale, and
3644 // we can modify it freely without touching original parameters
3646 while ((comp
= CompareMantissas(temp
, *pdecRight
)) < 0 &&
3647 temp
.scale
< pdecRight
->scale
)
3649 // Multiply by an appropriate power of 10
3650 int scaleDiff
= pdecRight
->scale
- temp
.scale
;
3651 if (scaleDiff
> largestPower
)
3653 // Keep the multiplier representable in 32bit
3654 scaleDiff
= largestPower
;
3656 DWORDLONG power
= powersOfTen
[scaleDiff
- 1];
3657 // Multiply temp's mantissa by power
3658 DWORDLONG product
= temp
.Lo32
* power
;
3659 ULONG carry
= static_cast<ULONG
>(product
>> 32);
3660 temp
.Lo32
= static_cast<ULONG
>(product
);
3661 product
= temp
.Mid32
* power
+ carry
;
3662 carry
= static_cast<ULONG
>(product
>> 32);
3663 temp
.Mid32
= static_cast<ULONG
>(product
);
3664 product
= temp
.Hi32
* power
+ carry
;
3665 if (static_cast<ULONG
>(product
>> 32))
3667 // Multiplication overflowed - pdecLeft is clearly larger
3670 temp
.Hi32
= static_cast<ULONG
>(product
);
3671 temp
.scale
= (BYTE
)(temp
.scale
+ scaleDiff
);
3673 if (temp
.scale
< pdecRight
->scale
)
3681 return (comp
> 0 ? VARCMP_GT
: comp
< 0 ? VARCMP_LT
: VARCMP_EQ
);
3684 static int CALLBACK
LVCompareDecimal(LPARAM lParam1
, LPARAM lParam2
, LPARAM lParamSort
)
3686 ATLASSERT(lParam1
!= NULL
&& lParam2
!= NULL
&& lParamSort
!= NULL
);
3688 LVCompareParam
* pParam1
= (LVCompareParam
*)lParam1
;
3689 LVCompareParam
* pParam2
= (LVCompareParam
*)lParam2
;
3690 LVSortInfo
* pInfo
= (LVSortInfo
*)lParamSort
;
3692 int nRet
= (int)VarDecCmp(&pParam1
->decValue
, &pParam2
->decValue
);
3694 return pInfo
->bDescending
? -nRet
: nRet
;
3696 #endif // !_WIN32_WCE
3698 BEGIN_MSG_MAP(CSortListViewImpl
)
3699 MESSAGE_HANDLER(LVM_INSERTCOLUMN
, OnInsertColumn
)
3700 MESSAGE_HANDLER(LVM_DELETECOLUMN
, OnDeleteColumn
)
3701 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA
, OnHeaderItemClick
)
3702 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW
, OnHeaderItemClick
)
3703 MESSAGE_HANDLER(WM_SETTINGCHANGE
, OnSettingChange
)
3706 LRESULT
OnInsertColumn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
3708 T
* pT
= static_cast<T
*>(this);
3709 LRESULT lRet
= pT
->DefWindowProc(uMsg
, wParam
, lParam
);
3714 m_arrColSortType
.Add(wType
);
3715 int nCount
= m_arrColSortType
.GetSize();
3716 ATLASSERT(nCount
== GetColumnCount());
3718 for(int i
= nCount
- 1; i
> lRet
; i
--)
3719 m_arrColSortType
[i
] = m_arrColSortType
[i
- 1];
3720 m_arrColSortType
[(int)lRet
] = LVCOLSORT_TEXT
;
3722 if(lRet
<= m_iSortColumn
)
3728 LRESULT
OnDeleteColumn(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
3730 T
* pT
= static_cast<T
*>(this);
3731 LRESULT lRet
= pT
->DefWindowProc(uMsg
, wParam
, lParam
);
3735 int iCol
= (int)wParam
;
3736 if(m_iSortColumn
== iCol
)
3738 else if(m_iSortColumn
> iCol
)
3740 m_arrColSortType
.RemoveAt(iCol
);
3745 LRESULT
OnHeaderItemClick(int /*idCtrl*/, LPNMHDR pnmh
, BOOL
& bHandled
)
3747 LPNMHEADER p
= (LPNMHEADER
)pnmh
;
3750 int iOld
= m_iSortColumn
;
3751 bool bDescending
= (m_iSortColumn
== p
->iItem
) ? !m_bSortDescending
: false;
3752 if(DoSortItems(p
->iItem
, bDescending
))
3753 NotifyParentSortChanged(p
->iItem
, iOld
);
3759 LRESULT
OnSettingChange(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
3762 if(wParam
== SPI_SETNONCLIENTMETRICS
)
3763 GetSystemSettings();
3764 #else // CE specific
3765 wParam
; // avoid level 4 warning
3766 GetSystemSettings();
3767 #endif // _WIN32_WCE
3772 void GetSystemSettings()
3774 if(!m_bCommCtrl6
&& !m_bmSort
[m_iSortUp
].IsNull())
3776 T
* pT
= static_cast<T
*>(this);
3777 pT
->CreateSortBitmaps();
3778 if(m_iSortColumn
!= -1)
3779 SetSortColumn(m_iSortColumn
);
3786 typedef ATL::CWinTraits
<WS_CHILD
| WS_VISIBLE
| WS_CLIPCHILDREN
| WS_CLIPSIBLINGS
| LVS_REPORT
| LVS_SHOWSELALWAYS
, WS_EX_CLIENTEDGE
> CSortListViewCtrlTraits
;
3788 template <class T
, class TBase
= CListViewCtrl
, class TWinTraits
= CSortListViewCtrlTraits
>
3789 class ATL_NO_VTABLE CSortListViewCtrlImpl
: public ATL::CWindowImpl
<T
, TBase
, TWinTraits
>, public CSortListViewImpl
<T
>
3792 DECLARE_WND_SUPERCLASS(NULL
, TBase::GetWndClassName())
3794 bool SortItems(int iCol
, bool bDescending
= false)
3796 return DoSortItems(iCol
, bDescending
);
3799 BEGIN_MSG_MAP(CSortListViewCtrlImpl
)
3800 MESSAGE_HANDLER(LVM_INSERTCOLUMN
, CSortListViewImpl
<T
>::OnInsertColumn
)
3801 MESSAGE_HANDLER(LVM_DELETECOLUMN
, CSortListViewImpl
<T
>::OnDeleteColumn
)
3802 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA
, CSortListViewImpl
<T
>::OnHeaderItemClick
)
3803 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW
, CSortListViewImpl
<T
>::OnHeaderItemClick
)
3804 MESSAGE_HANDLER(WM_SETTINGCHANGE
, CSortListViewImpl
<T
>::OnSettingChange
)
3808 class CSortListViewCtrl
: public CSortListViewCtrlImpl
<CSortListViewCtrl
>
3811 DECLARE_WND_SUPERCLASS(_T("WTL_SortListViewCtrl"), GetWndClassName())
3815 ///////////////////////////////////////////////////////////////////////////////
3816 // CTabView - implements tab view window
3818 // TabView Notifications
3819 #define TBVN_PAGEACTIVATED (0U-741)
3820 #define TBVN_CONTEXTMENU (0U-742)
3822 // Notification data for TBVN_CONTEXTMENU
3823 struct TBVCONTEXTMENUINFO
3829 typedef TBVCONTEXTMENUINFO
* LPTBVCONTEXTMENUINFO
;
3832 template <class T
, class TBase
= ATL::CWindow
, class TWinTraits
= ATL::CControlWinTraits
>
3833 class ATL_NO_VTABLE CTabViewImpl
: public ATL::CWindowImpl
< T
, TBase
, TWinTraits
>
3836 DECLARE_WND_CLASS_EX(NULL
, 0, COLOR_APPWORKSPACE
)
3838 // Declarations and enums
3848 TCITEMHEADER tciheader
;
3851 operator LPTCITEM() { return (LPTCITEM
)this; }
3859 m_nMenuItemsMax
= (ID_WINDOW_TABLAST
- ID_WINDOW_TABFIRST
+ 1)
3863 ATL::CContainedWindowT
<CTabCtrl
> m_tab
;
3869 POINT m_ptStartDrag
;
3873 int m_cchTabTextLength
;
3875 int m_nMenuItemsCount
;
3877 ATL::CWindow m_wndTitleBar
;
3878 LPTSTR m_lpstrTitleBarBase
;
3879 int m_cchTitleBarLength
;
3881 CImageList m_ilDrag
;
3883 bool m_bDestroyPageOnRemove
:1;
3884 bool m_bDestroyImageList
:1;
3885 bool m_bActivePageMenuItem
:1;
3886 bool m_bActiveAsDefaultMenuItem
:1;
3887 bool m_bEmptyMenuItem
:1;
3888 bool m_bWindowsMenuItem
:1;
3889 bool m_bNoTabDrag
:1;
3891 bool m_bTabCapture
:1;
3893 bool m_bInternalFont
:1;
3895 // Constructor/destructor
3901 m_cchTabTextLength(30),
3902 m_nMenuItemsCount(10),
3903 m_lpstrTitleBarBase(NULL
),
3904 m_cchTitleBarLength(100),
3905 m_bDestroyPageOnRemove(true),
3906 m_bDestroyImageList(true),
3907 m_bActivePageMenuItem(true),
3908 m_bActiveAsDefaultMenuItem(false),
3909 m_bEmptyMenuItem(false),
3910 m_bWindowsMenuItem(false),
3911 m_bNoTabDrag(false),
3912 m_bTabCapture(false),
3914 m_bInternalFont(false)
3916 m_ptStartDrag
.x
= 0;
3917 m_ptStartDrag
.y
= 0;
3922 delete [] m_lpstrTitleBarBase
;
3925 // Message filter function - to be called from PreTranslateMessage of the main window
3926 BOOL
PreTranslateMessage(MSG
* pMsg
)
3928 if(IsWindow() == FALSE
)
3933 // Check for TabView built-in accelerators (Ctrl+Tab/Ctrl+Shift+Tab - next/previous page)
3934 int nCount
= GetPageCount();
3937 bool bControl
= (::GetKeyState(VK_CONTROL
) < 0);
3938 if((pMsg
->message
== WM_KEYDOWN
) && (pMsg
->wParam
== VK_TAB
) && bControl
)
3942 int nPage
= m_nActivePage
;
3943 bool bShift
= (::GetKeyState(VK_SHIFT
) < 0);
3945 nPage
= (nPage
> 0) ? (nPage
- 1) : (nCount
- 1);
3947 nPage
= ((nPage
>= 0) && (nPage
< (nCount
- 1))) ? (nPage
+ 1) : 0;
3949 SetActivePage(nPage
);
3950 T
* pT
= static_cast<T
*>(this);
3951 pT
->OnPageActivated(m_nActivePage
);
3958 // If we are doing drag-drop, check for Escape key that cancels it
3961 if(m_bTabCapture
&& pMsg
->message
== WM_KEYDOWN
&& pMsg
->wParam
== VK_ESCAPE
)
3968 // Pass the message to the active page
3971 if(m_nActivePage
!= -1)
3972 bRet
= (BOOL
)::SendMessage(GetPageHWND(m_nActivePage
), WM_FORWARDMSG
, 0, (LPARAM
)pMsg
);
3979 int GetPageCount() const
3981 ATLASSERT(::IsWindow(m_hWnd
));
3982 return m_tab
.GetItemCount();
3985 int GetActivePage() const
3987 return m_nActivePage
;
3990 void SetActivePage(int nPage
)
3992 ATLASSERT(::IsWindow(m_hWnd
));
3993 ATLASSERT(IsValidPageIndex(nPage
));
3995 T
* pT
= static_cast<T
*>(this);
3999 if(m_nActivePage
!= -1)
4000 ::ShowWindow(GetPageHWND(m_nActivePage
), FALSE
);
4001 m_nActivePage
= nPage
;
4002 m_tab
.SetCurSel(m_nActivePage
);
4003 ::ShowWindow(GetPageHWND(m_nActivePage
), TRUE
);
4008 RedrawWindow(NULL
, NULL
, RDW_FRAME
| RDW_INVALIDATE
| RDW_UPDATENOW
| RDW_ALLCHILDREN
);
4010 if(::GetFocus() != m_tab
.m_hWnd
)
4011 ::SetFocus(GetPageHWND(m_nActivePage
));
4013 pT
->UpdateTitleBar();
4017 HIMAGELIST
GetImageList() const
4019 ATLASSERT(::IsWindow(m_hWnd
));
4020 return m_tab
.GetImageList();
4023 HIMAGELIST
SetImageList(HIMAGELIST hImageList
)
4025 ATLASSERT(::IsWindow(m_hWnd
));
4026 return m_tab
.SetImageList(hImageList
);
4029 void SetWindowMenu(HMENU hMenu
)
4031 ATLASSERT(::IsWindow(m_hWnd
));
4035 T
* pT
= static_cast<T
*>(this);
4039 void SetTitleBarWindow(HWND hWnd
)
4041 ATLASSERT(::IsWindow(m_hWnd
));
4043 delete [] m_lpstrTitleBarBase
;
4044 m_lpstrTitleBarBase
= NULL
;
4046 m_wndTitleBar
= hWnd
;
4050 int cchLen
= m_wndTitleBar
.GetWindowTextLength() + 1;
4051 ATLTRY(m_lpstrTitleBarBase
= new TCHAR
[cchLen
]);
4052 if(m_lpstrTitleBarBase
!= NULL
)
4054 m_wndTitleBar
.GetWindowText(m_lpstrTitleBarBase
, cchLen
);
4055 T
* pT
= static_cast<T
*>(this);
4056 pT
->UpdateTitleBar();
4061 HWND
GetPageHWND(int nPage
) const
4063 ATLASSERT(::IsWindow(m_hWnd
));
4064 ATLASSERT(IsValidPageIndex(nPage
));
4066 TCITEMEXTRA tcix
= { 0 };
4067 tcix
.tciheader
.mask
= TCIF_PARAM
;
4068 m_tab
.GetItem(nPage
, tcix
);
4070 return tcix
.tvpage
.hWnd
;
4073 LPCTSTR
GetPageTitle(int nPage
) const
4075 ATLASSERT(::IsWindow(m_hWnd
));
4076 ATLASSERT(IsValidPageIndex(nPage
));
4078 TCITEMEXTRA tcix
= { 0 };
4079 tcix
.tciheader
.mask
= TCIF_PARAM
;
4080 if(m_tab
.GetItem(nPage
, tcix
) == FALSE
)
4083 return tcix
.tvpage
.lpstrTitle
;
4086 bool SetPageTitle(int nPage
, LPCTSTR lpstrTitle
)
4088 ATLASSERT(::IsWindow(m_hWnd
));
4089 ATLASSERT(IsValidPageIndex(nPage
));
4091 T
* pT
= static_cast<T
*>(this);
4093 int cchBuff
= lstrlen(lpstrTitle
) + 1;
4094 LPTSTR lpstrBuff
= NULL
;
4095 ATLTRY(lpstrBuff
= new TCHAR
[cchBuff
]);
4096 if(lpstrBuff
== NULL
)
4099 SecureHelper::strcpy_x(lpstrBuff
, cchBuff
, lpstrTitle
);
4100 TCITEMEXTRA tcix
= { 0 };
4101 tcix
.tciheader
.mask
= TCIF_PARAM
;
4102 if(m_tab
.GetItem(nPage
, tcix
) == FALSE
)
4105 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
4106 LPTSTR lpstrTabText
= buff
.Allocate(m_cchTabTextLength
+ 1);
4107 if(lpstrTabText
== NULL
)
4110 delete [] tcix
.tvpage
.lpstrTitle
;
4112 pT
->ShortenTitle(lpstrTitle
, lpstrTabText
, m_cchTabTextLength
+ 1);
4114 tcix
.tciheader
.mask
= TCIF_TEXT
| TCIF_PARAM
;
4115 tcix
.tciheader
.pszText
= lpstrTabText
;
4116 tcix
.tvpage
.lpstrTitle
= lpstrBuff
;
4117 if(m_tab
.SetItem(nPage
, tcix
) == FALSE
)
4120 pT
->UpdateTitleBar();
4126 LPVOID
GetPageData(int nPage
) const
4128 ATLASSERT(::IsWindow(m_hWnd
));
4129 ATLASSERT(IsValidPageIndex(nPage
));
4131 TCITEMEXTRA tcix
= { 0 };
4132 tcix
.tciheader
.mask
= TCIF_PARAM
;
4133 m_tab
.GetItem(nPage
, tcix
);
4135 return tcix
.tvpage
.pData
;
4138 LPVOID
SetPageData(int nPage
, LPVOID pData
)
4140 ATLASSERT(::IsWindow(m_hWnd
));
4141 ATLASSERT(IsValidPageIndex(nPage
));
4143 TCITEMEXTRA tcix
= { 0 };
4144 tcix
.tciheader
.mask
= TCIF_PARAM
;
4145 m_tab
.GetItem(nPage
, tcix
);
4146 LPVOID pDataOld
= tcix
.tvpage
.pData
;
4148 tcix
.tvpage
.pData
= pData
;
4149 m_tab
.SetItem(nPage
, tcix
);
4154 int GetPageImage(int nPage
) const
4156 ATLASSERT(::IsWindow(m_hWnd
));
4157 ATLASSERT(IsValidPageIndex(nPage
));
4159 TCITEMEXTRA tcix
= { 0 };
4160 tcix
.tciheader
.mask
= TCIF_IMAGE
;
4161 m_tab
.GetItem(nPage
, tcix
);
4163 return tcix
.tciheader
.iImage
;
4166 int SetPageImage(int nPage
, int nImage
)
4168 ATLASSERT(::IsWindow(m_hWnd
));
4169 ATLASSERT(IsValidPageIndex(nPage
));
4171 TCITEMEXTRA tcix
= { 0 };
4172 tcix
.tciheader
.mask
= TCIF_IMAGE
;
4173 m_tab
.GetItem(nPage
, tcix
);
4174 int nImageOld
= tcix
.tciheader
.iImage
;
4176 tcix
.tciheader
.iImage
= nImage
;
4177 m_tab
.SetItem(nPage
, tcix
);
4183 bool AddPage(HWND hWndView
, LPCTSTR lpstrTitle
, int nImage
= -1, LPVOID pData
= NULL
)
4185 return InsertPage(GetPageCount(), hWndView
, lpstrTitle
, nImage
, pData
);
4188 bool InsertPage(int nPage
, HWND hWndView
, LPCTSTR lpstrTitle
, int nImage
= -1, LPVOID pData
= NULL
)
4190 ATLASSERT(::IsWindow(m_hWnd
));
4191 ATLASSERT(nPage
== GetPageCount() || IsValidPageIndex(nPage
));
4193 T
* pT
= static_cast<T
*>(this);
4195 int cchBuff
= lstrlen(lpstrTitle
) + 1;
4196 LPTSTR lpstrBuff
= NULL
;
4197 ATLTRY(lpstrBuff
= new TCHAR
[cchBuff
]);
4198 if(lpstrBuff
== NULL
)
4201 SecureHelper::strcpy_x(lpstrBuff
, cchBuff
, lpstrTitle
);
4203 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
4204 LPTSTR lpstrTabText
= buff
.Allocate(m_cchTabTextLength
+ 1);
4205 if(lpstrTabText
== NULL
)
4208 pT
->ShortenTitle(lpstrTitle
, lpstrTabText
, m_cchTabTextLength
+ 1);
4212 TCITEMEXTRA tcix
= { 0 };
4213 tcix
.tciheader
.mask
= TCIF_TEXT
| TCIF_IMAGE
| TCIF_PARAM
;
4214 tcix
.tciheader
.pszText
= lpstrTabText
;
4215 tcix
.tciheader
.iImage
= nImage
;
4216 tcix
.tvpage
.hWnd
= hWndView
;
4217 tcix
.tvpage
.lpstrTitle
= lpstrBuff
;
4218 tcix
.tvpage
.pData
= pData
;
4219 int nItem
= m_tab
.InsertItem(nPage
, tcix
);
4222 delete [] lpstrBuff
;
4227 // adjust active page index, if inserted before it
4228 if(nPage
<= m_nActivePage
)
4231 SetActivePage(nItem
);
4232 pT
->OnPageActivated(m_nActivePage
);
4234 if(GetPageCount() == 1)
4235 pT
->ShowTabControl(true);
4240 RedrawWindow(NULL
, NULL
, RDW_FRAME
| RDW_INVALIDATE
| RDW_UPDATENOW
| RDW_ALLCHILDREN
);
4245 void RemovePage(int nPage
)
4247 ATLASSERT(::IsWindow(m_hWnd
));
4248 ATLASSERT(IsValidPageIndex(nPage
));
4250 T
* pT
= static_cast<T
*>(this);
4254 if(GetPageCount() == 1)
4255 pT
->ShowTabControl(false);
4257 if(m_bDestroyPageOnRemove
)
4258 ::DestroyWindow(GetPageHWND(nPage
));
4260 ::ShowWindow(GetPageHWND(nPage
), FALSE
);
4261 LPTSTR lpstrTitle
= (LPTSTR
)GetPageTitle(nPage
);
4262 delete [] lpstrTitle
;
4264 ATLVERIFY(m_tab
.DeleteItem(nPage
) != FALSE
);
4266 if(m_nActivePage
== nPage
)
4272 SetActivePage(nPage
- 1);
4274 else if(GetPageCount() > 0)
4276 SetActivePage(nPage
);
4283 pT
->UpdateTitleBar();
4289 nPage
= (nPage
< m_nActivePage
) ? (m_nActivePage
- 1) : m_nActivePage
;
4291 SetActivePage(nPage
);
4294 pT
->OnPageActivated(m_nActivePage
);
4297 void RemoveAllPages()
4299 ATLASSERT(::IsWindow(m_hWnd
));
4301 if(GetPageCount() == 0)
4304 T
* pT
= static_cast<T
*>(this);
4308 pT
->ShowTabControl(false);
4310 for(int i
= 0; i
< GetPageCount(); i
++)
4312 if(m_bDestroyPageOnRemove
)
4313 ::DestroyWindow(GetPageHWND(i
));
4315 ::ShowWindow(GetPageHWND(i
), FALSE
);
4316 LPTSTR lpstrTitle
= (LPTSTR
)GetPageTitle(i
);
4317 delete [] lpstrTitle
;
4319 m_tab
.DeleteAllItems();
4322 pT
->OnPageActivated(m_nActivePage
);
4328 pT
->UpdateTitleBar();
4332 int PageIndexFromHwnd(HWND hWnd
) const
4336 for(int i
= 0; i
< GetPageCount(); i
++)
4338 if(GetPageHWND(i
) == hWnd
)
4348 void BuildWindowMenu(HMENU hMenu
, int nMenuItemsCount
= 10, bool bEmptyMenuItem
= true, bool bWindowsMenuItem
= true, bool bActivePageMenuItem
= true, bool bActiveAsDefaultMenuItem
= false)
4350 ATLASSERT(::IsWindow(m_hWnd
));
4352 CMenuHandle menu
= hMenu
;
4353 T
* pT
= static_cast<T
*>(this);
4354 pT
; // avoid level 4 warning
4357 // Find first menu item in our range
4359 for(nFirstPos
= 0; nFirstPos
< menu
.GetMenuItemCount(); nFirstPos
++)
4361 UINT nID
= menu
.GetMenuItemID(nFirstPos
);
4362 if((nID
>= ID_WINDOW_TABFIRST
&& nID
<= ID_WINDOW_TABLAST
) || nID
== ID_WINDOW_SHOWTABLIST
)
4365 #else // CE specific
4366 for(nFirstPos
= 0; ; nFirstPos
++)
4369 mii
.fMask
= MIIM_ID
;
4370 BOOL bRet
= menu
.GetMenuItemInfo(nFirstPos
, TRUE
, &mii
);
4373 if((mii
.wID
>= ID_WINDOW_TABFIRST
&& mii
.wID
<= ID_WINDOW_TABLAST
) || mii
.wID
== ID_WINDOW_SHOWTABLIST
)
4376 #endif // _WIN32_WCE
4378 // Remove all menu items for tab pages
4380 while(bRet
!= FALSE
)
4381 bRet
= menu
.DeleteMenu(nFirstPos
, MF_BYPOSITION
);
4383 // Add separator if it's not already there
4384 int nPageCount
= GetPageCount();
4385 if((bWindowsMenuItem
|| (nPageCount
> 0)) && (nFirstPos
> 0))
4388 mii
.fMask
= MIIM_TYPE
;
4389 menu
.GetMenuItemInfo(nFirstPos
- 1, TRUE
, &mii
);
4390 if((nFirstPos
<= 0) || ((mii
.fType
& MFT_SEPARATOR
) == 0))
4392 menu
.AppendMenu(MF_SEPARATOR
);
4397 // Add menu items for all pages
4400 // Append menu items for all pages
4401 const int cchPrefix
= 3; // 2 digits + space
4402 nMenuItemsCount
= __min(__min(nPageCount
, nMenuItemsCount
), (int)m_nMenuItemsMax
);
4403 ATLASSERT(nMenuItemsCount
< 100); // 2 digits only
4404 if(nMenuItemsCount
>= 100)
4405 nMenuItemsCount
= 99;
4407 for(int i
= 0; i
< nMenuItemsCount
; i
++)
4409 LPCTSTR lpstrTitle
= GetPageTitle(i
);
4410 int nLen
= lstrlen(lpstrTitle
);
4411 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
4412 LPTSTR lpstrText
= buff
.Allocate(cchPrefix
+ nLen
+ 1);
4413 ATLASSERT(lpstrText
!= NULL
);
4414 if(lpstrText
!= NULL
)
4416 LPCTSTR lpstrFormat
= (i
< 9) ? _T("&%i %s") : _T("%i %s");
4417 SecureHelper::wsprintf_x(lpstrText
, cchPrefix
+ nLen
+ 1, lpstrFormat
, i
+ 1, lpstrTitle
);
4418 menu
.AppendMenu(MF_STRING
, ID_WINDOW_TABFIRST
+ i
, lpstrText
);
4423 if(bActivePageMenuItem
&& (m_nActivePage
!= -1))
4426 if(bActiveAsDefaultMenuItem
)
4428 menu
.SetMenuDefaultItem((UINT
)-1, TRUE
);
4429 menu
.SetMenuDefaultItem(nFirstPos
+ m_nActivePage
, TRUE
);
4432 #else // CE specific
4433 bActiveAsDefaultMenuItem
; // avoid level 4 warning
4434 #endif // _WIN32_WCE
4436 menu
.CheckMenuRadioItem(nFirstPos
, nFirstPos
+ nMenuItemsCount
, nFirstPos
+ m_nActivePage
, MF_BYPOSITION
);
4444 menu
.AppendMenu(MF_BYPOSITION
| MF_STRING
, ID_WINDOW_TABFIRST
, pT
->GetEmptyListText());
4445 menu
.EnableMenuItem(ID_WINDOW_TABFIRST
, MF_GRAYED
);
4448 // Remove separator if nothing else is there
4449 if(!bEmptyMenuItem
&& !bWindowsMenuItem
&& (nFirstPos
> 0))
4452 mii
.fMask
= MIIM_TYPE
;
4453 menu
.GetMenuItemInfo(nFirstPos
- 1, TRUE
, &mii
);
4454 if((mii
.fType
& MFT_SEPARATOR
) != 0)
4455 menu
.DeleteMenu(nFirstPos
- 1, MF_BYPOSITION
);
4459 // Add "Windows..." menu item
4460 if(bWindowsMenuItem
)
4461 menu
.AppendMenu(MF_BYPOSITION
| MF_STRING
, ID_WINDOW_SHOWTABLIST
, pT
->GetWindowsMenuItemText());
4464 BOOL
SubclassWindow(HWND hWnd
)
4466 #if (_MSC_VER >= 1300)
4467 BOOL bRet
= ATL::CWindowImpl
< T
, TBase
, TWinTraits
>::SubclassWindow(hWnd
);
4468 #else // !(_MSC_VER >= 1300)
4469 typedef ATL::CWindowImpl
< T
, TBase
, TWinTraits
> _baseClass
;
4470 BOOL bRet
= _baseClass::SubclassWindow(hWnd
);
4471 #endif // !(_MSC_VER >= 1300)
4474 T
* pT
= static_cast<T
*>(this);
4475 pT
->CreateTabControl();
4482 // Message map and handlers
4483 BEGIN_MSG_MAP(CTabViewImpl
)
4484 MESSAGE_HANDLER(WM_CREATE
, OnCreate
)
4485 MESSAGE_HANDLER(WM_DESTROY
, OnDestroy
)
4486 MESSAGE_HANDLER(WM_SIZE
, OnSize
)
4487 MESSAGE_HANDLER(WM_SETFOCUS
, OnSetFocus
)
4488 MESSAGE_HANDLER(WM_GETFONT
, OnGetFont
)
4489 MESSAGE_HANDLER(WM_SETFONT
, OnSetFont
)
4490 NOTIFY_HANDLER(m_nTabID
, TCN_SELCHANGE
, OnTabChanged
)
4491 NOTIFY_ID_HANDLER(m_nTabID
, OnTabNotification
)
4493 NOTIFY_CODE_HANDLER(TTN_GETDISPINFO
, OnTabGetDispInfo
)
4494 #endif // !_WIN32_WCE
4495 FORWARD_NOTIFICATIONS()
4496 ALT_MSG_MAP(1) // tab control
4497 MESSAGE_HANDLER(WM_LBUTTONDOWN
, OnTabLButtonDown
)
4498 MESSAGE_HANDLER(WM_LBUTTONUP
, OnTabLButtonUp
)
4499 MESSAGE_HANDLER(WM_CAPTURECHANGED
, OnTabCaptureChanged
)
4500 MESSAGE_HANDLER(WM_MOUSEMOVE
, OnTabMouseMove
)
4501 MESSAGE_HANDLER(WM_RBUTTONUP
, OnTabRButtonUp
)
4502 MESSAGE_HANDLER(WM_SYSKEYDOWN
, OnTabSysKeyDown
)
4505 LRESULT
OnCreate(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
4507 T
* pT
= static_cast<T
*>(this);
4508 pT
->CreateTabControl();
4513 LRESULT
OnDestroy(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
4517 if(m_bDestroyImageList
)
4519 CImageList il
= m_tab
.SetImageList(NULL
);
4520 if(il
.m_hImageList
!= NULL
)
4526 HFONT hFont
= m_tab
.GetFont();
4527 m_tab
.SetFont(NULL
, FALSE
);
4528 ::DeleteObject(hFont
);
4529 m_bInternalFont
= false;
4535 LRESULT
OnSize(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
4537 T
* pT
= static_cast<T
*>(this);
4542 LRESULT
OnSetFocus(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
4544 if(m_nActivePage
!= -1)
4545 ::SetFocus(GetPageHWND(m_nActivePage
));
4549 LRESULT
OnGetFont(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& /*bHandled*/)
4551 return m_tab
.SendMessage(WM_GETFONT
);
4554 LRESULT
OnSetFont(UINT
/*uMsg*/, WPARAM wParam
, LPARAM lParam
, BOOL
& /*bHandled*/)
4558 HFONT hFont
= m_tab
.GetFont();
4559 m_tab
.SetFont(NULL
, FALSE
);
4560 ::DeleteObject(hFont
);
4561 m_bInternalFont
= false;
4564 m_tab
.SendMessage(WM_SETFONT
, wParam
, lParam
);
4566 T
* pT
= static_cast<T
*>(this);
4567 m_cyTabHeight
= pT
->CalcTabHeight();
4569 if((BOOL
)lParam
!= FALSE
)
4575 LRESULT
OnTabChanged(int /*idCtrl*/, LPNMHDR
/*pnmh*/, BOOL
& /*bHandled*/)
4577 SetActivePage(m_tab
.GetCurSel());
4578 T
* pT
= static_cast<T
*>(this);
4579 pT
->OnPageActivated(m_nActivePage
);
4584 LRESULT
OnTabNotification(int /*idCtrl*/, LPNMHDR
/*pnmh*/, BOOL
& /*bHandled*/)
4586 // nothing to do - this just blocks all tab control
4587 // notifications from being propagated further
4592 LRESULT
OnTabGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh
, BOOL
& bHandled
)
4594 LPNMTTDISPINFO pTTDI
= (LPNMTTDISPINFO
)pnmh
;
4595 if(pTTDI
->hdr
.hwndFrom
== m_tab
.GetTooltips())
4597 T
* pT
= static_cast<T
*>(this);
4598 pT
->UpdateTooltipText(pTTDI
);
4607 #endif // !_WIN32_WCE
4609 // Tab control message handlers
4610 LRESULT
OnTabLButtonDown(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
4612 if(!m_bNoTabDrag
&& (m_tab
.GetItemCount() > 1))
4614 m_bTabCapture
= true;
4617 m_ptStartDrag
.x
= GET_X_LPARAM(lParam
);
4618 m_ptStartDrag
.y
= GET_Y_LPARAM(lParam
);
4625 LRESULT
OnTabLButtonUp(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
4631 TCHITTESTINFO hti
= { 0 };
4632 hti
.pt
.x
= GET_X_LPARAM(lParam
);
4633 hti
.pt
.y
= GET_Y_LPARAM(lParam
);
4634 int nItem
= m_tab
.HitTest(&hti
);
4636 MovePage(m_nActivePage
, nItem
);
4646 LRESULT
OnTabCaptureChanged(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM
/*lParam*/, BOOL
& bHandled
)
4650 m_bTabCapture
= false;
4655 T
* pT
= static_cast<T
*>(this);
4656 pT
->DrawMoveMark(-1);
4659 m_ilDrag
.DragLeave(GetDesktopWindow());
4660 #endif // !_WIN32_WCE
4664 m_ilDrag
.m_hImageList
= NULL
;
4672 LRESULT
OnTabMouseMove(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& bHandled
)
4678 POINT pt
= { GET_X_LPARAM(lParam
), GET_Y_LPARAM(lParam
) };
4683 if(abs(m_ptStartDrag
.x
- GET_X_LPARAM(lParam
)) >= ::GetSystemMetrics(SM_CXDRAG
) ||
4684 abs(m_ptStartDrag
.y
- GET_Y_LPARAM(lParam
)) >= ::GetSystemMetrics(SM_CYDRAG
))
4685 #else // CE specific
4686 if(abs(m_ptStartDrag
.x
- GET_X_LPARAM(lParam
)) >= 4 ||
4687 abs(m_ptStartDrag
.y
- GET_Y_LPARAM(lParam
)) >= 4)
4688 #endif // _WIN32_WCE
4690 T
* pT
= static_cast<T
*>(this);
4691 pT
->GenerateDragImage(m_nActivePage
);
4693 int cxCursor
= ::GetSystemMetrics(SM_CXCURSOR
);
4694 int cyCursor
= ::GetSystemMetrics(SM_CYCURSOR
);
4695 m_ilDrag
.BeginDrag(0, -(cxCursor
/ 2), -(cyCursor
/ 2));
4697 POINT ptEnter
= m_ptStartDrag
;
4698 m_tab
.ClientToScreen(&ptEnter
);
4699 m_ilDrag
.DragEnter(GetDesktopWindow(), ptEnter
);
4700 #endif // !_WIN32_WCE
4708 TCHITTESTINFO hti
= { 0 };
4710 int nItem
= m_tab
.HitTest(&hti
);
4712 T
* pT
= static_cast<T
*>(this);
4713 pT
->SetMoveCursor(nItem
!= -1);
4715 if(m_nInsertItem
!= nItem
)
4716 pT
->DrawMoveMark(nItem
);
4718 m_ilDrag
.DragShowNolock((nItem
!= -1) ? TRUE
: FALSE
);
4719 m_tab
.ClientToScreen(&pt
);
4720 m_ilDrag
.DragMove(pt
);
4729 LRESULT
OnTabRButtonUp(UINT
/*uMsg*/, WPARAM
/*wParam*/, LPARAM lParam
, BOOL
& /*bHandled*/)
4731 TCHITTESTINFO hti
= { 0 };
4732 hti
.pt
.x
= GET_X_LPARAM(lParam
);
4733 hti
.pt
.y
= GET_Y_LPARAM(lParam
);
4734 int nItem
= m_tab
.HitTest(&hti
);
4737 T
* pT
= static_cast<T
*>(this);
4738 pT
->OnContextMenu(nItem
, hti
.pt
);
4744 LRESULT
OnTabSysKeyDown(UINT
/*uMsg*/, WPARAM wParam
, LPARAM
/*lParam*/, BOOL
& bHandled
)
4746 bool bShift
= (::GetKeyState(VK_SHIFT
) < 0);
4747 if(wParam
== VK_F10
&& bShift
)
4749 if(m_nActivePage
!= -1)
4752 m_tab
.GetItemRect(m_nActivePage
, &rect
);
4753 POINT pt
= { rect
.left
, rect
.bottom
};
4754 T
* pT
= static_cast<T
*>(this);
4755 pT
->OnContextMenu(m_nActivePage
, pt
);
4766 // Implementation helpers
4767 bool IsValidPageIndex(int nPage
) const
4769 return (nPage
>= 0 && nPage
< GetPageCount());
4772 bool MovePage(int nMovePage
, int nInsertBeforePage
)
4774 ATLASSERT(IsValidPageIndex(nMovePage
));
4775 ATLASSERT(IsValidPageIndex(nInsertBeforePage
));
4777 if(!IsValidPageIndex(nMovePage
) || !IsValidPageIndex(nInsertBeforePage
))
4780 if(nMovePage
== nInsertBeforePage
)
4781 return true; // nothing to do
4783 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
4784 LPTSTR lpstrTabText
= buff
.Allocate(m_cchTabTextLength
+ 1);
4785 if(lpstrTabText
== NULL
)
4787 TCITEMEXTRA tcix
= { 0 };
4788 tcix
.tciheader
.mask
= TCIF_TEXT
| TCIF_IMAGE
| TCIF_PARAM
;
4789 tcix
.tciheader
.pszText
= lpstrTabText
;
4790 tcix
.tciheader
.cchTextMax
= m_cchTabTextLength
+ 1;
4791 BOOL bRet
= m_tab
.GetItem(nMovePage
, tcix
);
4792 ATLASSERT(bRet
!= FALSE
);
4796 int nInsertItem
= (nInsertBeforePage
> nMovePage
) ? nInsertBeforePage
+ 1 : nInsertBeforePage
;
4797 int nNewItem
= m_tab
.InsertItem(nInsertItem
, tcix
);
4798 ATLASSERT(nNewItem
== nInsertItem
);
4799 if(nNewItem
!= nInsertItem
)
4801 ATLVERIFY(m_tab
.DeleteItem(nNewItem
));
4805 if(nMovePage
> nInsertBeforePage
)
4806 ATLVERIFY(m_tab
.DeleteItem(nMovePage
+ 1) != FALSE
);
4807 else if(nMovePage
< nInsertBeforePage
)
4808 ATLVERIFY(m_tab
.DeleteItem(nMovePage
) != FALSE
);
4810 SetActivePage(nInsertBeforePage
);
4811 T
* pT
= static_cast<T
*>(this);
4812 pT
->OnPageActivated(m_nActivePage
);
4817 // Implementation overrideables
4818 bool CreateTabControl()
4821 m_tab
.Create(m_hWnd
, rcDefault
, NULL
, WS_CHILD
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
| TCS_TOOLTIPS
, 0, m_nTabID
);
4822 #else // CE specific
4823 m_tab
.Create(m_hWnd
, rcDefault
, NULL
, WS_CHILD
| WS_CLIPSIBLINGS
| WS_CLIPCHILDREN
, 0, m_nTabID
);
4824 #endif // _WIN32_WCE
4825 ATLASSERT(m_tab
.m_hWnd
!= NULL
);
4826 if(m_tab
.m_hWnd
== NULL
)
4829 m_tab
.SetFont(AtlCreateControlFont());
4830 m_bInternalFont
= true;
4832 m_tab
.SetItemExtra(sizeof(TABVIEWPAGE
));
4834 T
* pT
= static_cast<T
*>(this);
4835 m_cyTabHeight
= pT
->CalcTabHeight();
4842 int nCount
= m_tab
.GetItemCount();
4843 TCITEMEXTRA tcix
= { 0 };
4844 tcix
.tciheader
.mask
= TCIF_TEXT
;
4845 tcix
.tciheader
.pszText
= _T("NS");
4846 int nIndex
= m_tab
.InsertItem(nCount
, tcix
);
4848 RECT rect
= { 0, 0, 1000, 1000 };
4849 m_tab
.AdjustRect(FALSE
, &rect
);
4851 RECT rcWnd
= { 0, 0, 1000, rect
.top
};
4852 ::AdjustWindowRectEx(&rcWnd
, m_tab
.GetStyle(), FALSE
, m_tab
.GetExStyle());
4854 int nHeight
= rcWnd
.bottom
- rcWnd
.top
;
4856 m_tab
.DeleteItem(nIndex
);
4861 void ShowTabControl(bool bShow
)
4863 m_tab
.ShowWindow(bShow
? SW_SHOWNOACTIVATE
: SW_HIDE
);
4864 T
* pT
= static_cast<T
*>(this);
4871 GetClientRect(&rect
);
4874 if(m_tab
.IsWindow() && ((m_tab
.GetStyle() & WS_VISIBLE
) != 0))
4876 m_tab
.SetWindowPos(NULL
, 0, 0, rect
.right
- rect
.left
, m_cyTabHeight
, SWP_NOZORDER
);
4877 cyOffset
= m_cyTabHeight
;
4880 if(m_nActivePage
!= -1)
4881 ::SetWindowPos(GetPageHWND(m_nActivePage
), NULL
, 0, cyOffset
, rect
.right
- rect
.left
, rect
.bottom
- rect
.top
- cyOffset
, SWP_NOZORDER
);
4886 if(m_menu
.m_hMenu
!= NULL
)
4887 BuildWindowMenu(m_menu
, m_nMenuItemsCount
, m_bEmptyMenuItem
, m_bWindowsMenuItem
, m_bActivePageMenuItem
, m_bActiveAsDefaultMenuItem
);
4890 void UpdateTitleBar()
4892 if(!m_wndTitleBar
.IsWindow() || m_lpstrTitleBarBase
== NULL
)
4893 return; // nothing to do
4895 if(m_nActivePage
!= -1)
4897 T
* pT
= static_cast<T
*>(this);
4898 LPCTSTR lpstrTitle
= pT
->GetPageTitle(m_nActivePage
);
4899 LPCTSTR lpstrDivider
= pT
->GetTitleDividerText();
4900 int cchBuffer
= m_cchTitleBarLength
+ lstrlen(lpstrDivider
) + lstrlen(m_lpstrTitleBarBase
) + 1;
4901 CTempBuffer
<TCHAR
, _WTL_STACK_ALLOC_THRESHOLD
> buff
;
4902 LPTSTR lpstrPageTitle
= buff
.Allocate(cchBuffer
);
4903 ATLASSERT(lpstrPageTitle
!= NULL
);
4904 if(lpstrPageTitle
!= NULL
)
4906 pT
->ShortenTitle(lpstrTitle
, lpstrPageTitle
, m_cchTitleBarLength
+ 1);
4907 SecureHelper::strcat_x(lpstrPageTitle
, cchBuffer
, lpstrDivider
);
4908 SecureHelper::strcat_x(lpstrPageTitle
, cchBuffer
, m_lpstrTitleBarBase
);
4912 lpstrPageTitle
= m_lpstrTitleBarBase
;
4915 m_wndTitleBar
.SetWindowText(lpstrPageTitle
);
4919 m_wndTitleBar
.SetWindowText(m_lpstrTitleBarBase
);
4923 void DrawMoveMark(int nItem
)
4925 T
* pT
= static_cast<T
*>(this);
4927 if(m_nInsertItem
!= -1)
4930 pT
->GetMoveMarkRect(rect
);
4931 m_tab
.InvalidateRect(&rect
);
4934 m_nInsertItem
= nItem
;
4936 if(m_nInsertItem
!= -1)
4938 CClientDC
dc(m_tab
.m_hWnd
);
4941 pT
->GetMoveMarkRect(rect
);
4944 pen
.CreatePen(PS_SOLID
, 1, ::GetSysColor(COLOR_WINDOWTEXT
));
4946 brush
.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT
));
4948 HPEN hPenOld
= dc
.SelectPen(pen
);
4949 HBRUSH hBrushOld
= dc
.SelectBrush(brush
);
4953 POINT ptsTop
[3] = { { x
, y
}, { x
+ m_cxMoveMark
, y
}, { x
+ (m_cxMoveMark
/ 2), y
+ m_cyMoveMark
} };
4954 dc
.Polygon(ptsTop
, 3);
4956 y
= rect
.bottom
- 1;
4957 POINT ptsBottom
[3] = { { x
, y
}, { x
+ m_cxMoveMark
, y
}, { x
+ (m_cxMoveMark
/ 2), y
- m_cyMoveMark
} };
4958 dc
.Polygon(ptsBottom
, 3);
4960 dc
.SelectPen(hPenOld
);
4961 dc
.SelectBrush(hBrushOld
);
4965 void GetMoveMarkRect(RECT
& rect
) const
4967 m_tab
.GetClientRect(&rect
);
4969 RECT rcItem
= { 0 };
4970 m_tab
.GetItemRect(m_nInsertItem
, &rcItem
);
4972 if(m_nInsertItem
<= m_nActivePage
)
4974 rect
.left
= rcItem
.left
- m_cxMoveMark
/ 2 - 1;
4975 rect
.right
= rcItem
.left
+ m_cxMoveMark
/ 2;
4979 rect
.left
= rcItem
.right
- m_cxMoveMark
/ 2 - 1;
4980 rect
.right
= rcItem
.right
+ m_cxMoveMark
/ 2;
4984 void SetMoveCursor(bool bCanMove
)
4986 ::SetCursor(::LoadCursor(NULL
, bCanMove
? IDC_ARROW
: IDC_NO
));
4989 void GenerateDragImage(int nItem
)
4991 ATLASSERT(IsValidPageIndex(nItem
));
4994 RECT rcItem
= { 0 };
4995 m_tab
.GetItemRect(nItem
, &rcItem
);
4996 ::InflateRect(&rcItem
, 2, 2); // make bigger to cover selected item
4997 #else // CE specific
4998 nItem
; // avoid level 4 warning
4999 RECT rcItem
= { 0, 0, 40, 20 };
5000 #endif // _WIN32_WCE
5002 ATLASSERT(m_ilDrag
.m_hImageList
== NULL
);
5003 m_ilDrag
.Create(rcItem
.right
- rcItem
.left
, rcItem
.bottom
- rcItem
.top
, ILC_COLORDDB
| ILC_MASK
, 1, 1);
5005 CClientDC
dc(m_hWnd
);
5007 dcMem
.CreateCompatibleDC(dc
);
5008 ATLASSERT(dcMem
.m_hDC
!= NULL
);
5009 dcMem
.SetViewportOrg(-rcItem
.left
, -rcItem
.top
);
5012 bmp
.CreateCompatibleBitmap(dc
, rcItem
.right
- rcItem
.left
, rcItem
.bottom
- rcItem
.top
);
5013 ATLASSERT(bmp
.m_hBitmap
!= NULL
);
5015 HBITMAP hBmpOld
= dcMem
.SelectBitmap(bmp
);
5017 m_tab
.SendMessage(WM_PRINTCLIENT
, (WPARAM
)dcMem
.m_hDC
);
5018 #else // CE specific
5019 dcMem
.Rectangle(&rcItem
);
5020 #endif // _WIN32_WCE
5021 dcMem
.SelectBitmap(hBmpOld
);
5023 ATLVERIFY(m_ilDrag
.Add(bmp
.m_hBitmap
, RGB(255, 0, 255)) != -1);
5026 void ShortenTitle(LPCTSTR lpstrTitle
, LPTSTR lpstrShortTitle
, int cchShortTitle
)
5028 if(lstrlen(lpstrTitle
) >= cchShortTitle
)
5030 LPCTSTR lpstrEllipsis
= _T("...");
5031 int cchEllipsis
= lstrlen(lpstrEllipsis
);
5032 SecureHelper::strncpy_x(lpstrShortTitle
, cchShortTitle
, lpstrTitle
, cchShortTitle
- cchEllipsis
- 1);
5033 SecureHelper::strcat_x(lpstrShortTitle
, cchShortTitle
, lpstrEllipsis
);
5037 SecureHelper::strcpy_x(lpstrShortTitle
, cchShortTitle
, lpstrTitle
);
5042 void UpdateTooltipText(LPNMTTDISPINFO pTTDI
)
5044 ATLASSERT(pTTDI
!= NULL
);
5045 pTTDI
->lpszText
= (LPTSTR
)GetPageTitle((int)pTTDI
->hdr
.idFrom
);
5047 #endif // !_WIN32_WCE
5049 // Text for menu items and title bar - override to provide different strings
5050 static LPCTSTR
GetEmptyListText()
5052 return _T("(Empty)");
5055 static LPCTSTR
GetWindowsMenuItemText()
5057 return _T("&Windows...");
5060 static LPCTSTR
GetTitleDividerText()
5065 // Notifications - override to provide different behavior
5066 void OnPageActivated(int nPage
)
5068 NMHDR nmhdr
= { 0 };
5069 nmhdr
.hwndFrom
= m_hWnd
;
5070 nmhdr
.idFrom
= nPage
;
5071 nmhdr
.code
= TBVN_PAGEACTIVATED
;
5072 ::SendMessage(GetParent(), WM_NOTIFY
, GetDlgCtrlID(), (LPARAM
)&nmhdr
);
5075 void OnContextMenu(int nPage
, POINT pt
)
5077 m_tab
.ClientToScreen(&pt
);
5079 TBVCONTEXTMENUINFO cmi
= { 0 };
5080 cmi
.hdr
.hwndFrom
= m_hWnd
;
5081 cmi
.hdr
.idFrom
= nPage
;
5082 cmi
.hdr
.code
= TBVN_CONTEXTMENU
;
5084 ::SendMessage(GetParent(), WM_NOTIFY
, GetDlgCtrlID(), (LPARAM
)&cmi
);
5088 class CTabView
: public CTabViewImpl
<CTabView
>
5091 DECLARE_WND_CLASS_EX(_T("WTL_TabView"), 0, COLOR_APPWORKSPACE
)
5096 #endif // __ATLCTRLX_H__