Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(7)

Side by Side Diff: third_party/wtl/include/atlctrlx.h

Issue 703753005: More Windows build fixes. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: remove generated files Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/wtl/include/atlctrlw.h ('k') | third_party/wtl/include/atlddx.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Windows Template Library - WTL version 8.0
2 // Copyright (C) Microsoft Corporation. All rights reserved.
3 //
4 // This file is a part of the Windows Template Library.
5 // The use and distribution terms for this software are covered by the
6 // Microsoft Permissive License (Ms-PL) which can be found in the file
7 // Ms-PL.txt at the root of this distribution.
8
9 #ifndef __ATLCTRLX_H__
10 #define __ATLCTRLX_H__
11
12 #pragma once
13
14 #ifndef __cplusplus
15 #error ATL requires C++ compilation (use a .cpp suffix)
16 #endif
17
18 #ifndef __ATLAPP_H__
19 #error atlctrlx.h requires atlapp.h to be included first
20 #endif
21
22 #ifndef __ATLCTRLS_H__
23 #error atlctrlx.h requires atlctrls.h to be included first
24 #endif
25
26 #ifndef WM_UPDATEUISTATE
27 #define WM_UPDATEUISTATE 0x0128
28 #endif // !WM_UPDATEUISTATE
29
30
31 ///////////////////////////////////////////////////////////////////////////////
32 // Classes in this file:
33 //
34 // CBitmapButtonImpl<T, TBase, TWinTraits>
35 // CBitmapButton
36 // CCheckListViewCtrlImpl<T, TBase, TWinTraits>
37 // CCheckListViewCtrl
38 // CHyperLinkImpl<T, TBase, TWinTraits>
39 // CHyperLink
40 // CWaitCursor
41 // CCustomWaitCursor
42 // CMultiPaneStatusBarCtrlImpl<T, TBase>
43 // CMultiPaneStatusBarCtrl
44 // CPaneContainerImpl<T, TBase, TWinTraits>
45 // CPaneContainer
46 // CSortListViewImpl<T>
47 // CSortListViewCtrlImpl<T, TBase, TWinTraits>
48 // CSortListViewCtrl
49 // CTabViewImpl<T, TBase, TWinTraits>
50 // CTabView
51
52 namespace WTL
53 {
54
55 ///////////////////////////////////////////////////////////////////////////////
56 // CBitmapButton - bitmap button implementation
57
58 #ifndef _WIN32_WCE
59
60 // bitmap button extended styles
61 #define BMPBTN_HOVER 0x00000001
62 #define BMPBTN_AUTO3D_SINGLE 0x00000002
63 #define BMPBTN_AUTO3D_DOUBLE 0x00000004
64 #define BMPBTN_AUTOSIZE 0x00000008
65 #define BMPBTN_SHAREIMAGELISTS 0x00000010
66 #define BMPBTN_AUTOFIRE 0x00000020
67
68 template <class T, class TBase = CButton, class TWinTraits = ATL::CControlWinTra its>
69 class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinT raits>
70 {
71 public:
72 DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
73
74 enum
75 {
76 _nImageNormal = 0,
77 _nImagePushed,
78 _nImageFocusOrHover,
79 _nImageDisabled,
80
81 _nImageCount = 4,
82 };
83
84 enum
85 {
86 ID_TIMER_FIRST = 1000,
87 ID_TIMER_REPEAT = 1001
88 };
89
90 // Bitmap button specific extended styles
91 DWORD m_dwExtendedStyle;
92
93 CImageList m_ImageList;
94 int m_nImage[_nImageCount];
95
96 CToolTipCtrl m_tip;
97 LPTSTR m_lpstrToolTipText;
98
99 // Internal states
100 unsigned m_fMouseOver:1;
101 unsigned m_fFocus:1;
102 unsigned m_fPressed:1;
103
104
105 // Constructor/Destructor
106 CBitmapButtonImpl(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hI mageList = NULL) :
107 m_ImageList(hImageList), m_dwExtendedStyle(dwExtendedSty le),
108 m_lpstrToolTipText(NULL),
109 m_fMouseOver(0), m_fFocus(0), m_fPressed(0)
110 {
111 m_nImage[_nImageNormal] = -1;
112 m_nImage[_nImagePushed] = -1;
113 m_nImage[_nImageFocusOrHover] = -1;
114 m_nImage[_nImageDisabled] = -1;
115 }
116
117 ~CBitmapButtonImpl()
118 {
119 if((m_dwExtendedStyle & BMPBTN_SHAREIMAGELISTS) == 0)
120 m_ImageList.Destroy();
121 delete [] m_lpstrToolTipText;
122 }
123
124 // overridden to provide proper initialization
125 BOOL SubclassWindow(HWND hWnd)
126 {
127 #if (_MSC_VER >= 1300)
128 BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits>::SubclassWin dow(hWnd);
129 #else // !(_MSC_VER >= 1300)
130 typedef ATL::CWindowImpl< T, TBase, TWinTraits> _baseClass;
131 BOOL bRet = _baseClass::SubclassWindow(hWnd);
132 #endif // !(_MSC_VER >= 1300)
133 if(bRet)
134 Init();
135 return bRet;
136 }
137
138 // Attributes
139 DWORD GetBitmapButtonExtendedStyle() const
140 {
141 return m_dwExtendedStyle;
142 }
143
144 DWORD SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
145 {
146 DWORD dwPrevStyle = m_dwExtendedStyle;
147 if(dwMask == 0)
148 m_dwExtendedStyle = dwExtendedStyle;
149 else
150 m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwE xtendedStyle & dwMask);
151 return dwPrevStyle;
152 }
153
154 HIMAGELIST GetImageList() const
155 {
156 return m_ImageList;
157 }
158
159 HIMAGELIST SetImageList(HIMAGELIST hImageList)
160 {
161 HIMAGELIST hImageListPrev = m_ImageList;
162 m_ImageList = hImageList;
163 if((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0 && ::IsWindow(m_hW nd))
164 SizeToImage();
165 return hImageListPrev;
166 }
167
168 int GetToolTipTextLength() const
169 {
170 return (m_lpstrToolTipText == NULL) ? -1 : lstrlen(m_lpstrToolTi pText);
171 }
172
173 bool GetToolTipText(LPTSTR lpstrText, int nLength) const
174 {
175 ATLASSERT(lpstrText != NULL);
176 if(m_lpstrToolTipText == NULL)
177 return false;
178
179 errno_t nRet = SecureHelper::strncpy_x(lpstrText, nLength, m_lps trToolTipText, _TRUNCATE);
180
181 return (nRet == 0 || nRet == STRUNCATE);
182 }
183
184 bool SetToolTipText(LPCTSTR lpstrText)
185 {
186 if(m_lpstrToolTipText != NULL)
187 {
188 delete [] m_lpstrToolTipText;
189 m_lpstrToolTipText = NULL;
190 }
191
192 if(lpstrText == NULL)
193 {
194 if(m_tip.IsWindow())
195 m_tip.Activate(FALSE);
196 return true;
197 }
198
199 int cchLen = lstrlen(lpstrText) + 1;
200 ATLTRY(m_lpstrToolTipText = new TCHAR[cchLen]);
201 if(m_lpstrToolTipText == NULL)
202 return false;
203
204 SecureHelper::strcpy_x(m_lpstrToolTipText, cchLen, lpstrText);
205 if(m_tip.IsWindow())
206 {
207 m_tip.Activate(TRUE);
208 m_tip.AddTool(m_hWnd, m_lpstrToolTipText);
209 }
210
211 return true;
212 }
213
214 // Operations
215 void SetImages(int nNormal, int nPushed = -1, int nFocusOrHover = -1, in t nDisabled = -1)
216 {
217 if(nNormal != -1)
218 m_nImage[_nImageNormal] = nNormal;
219 if(nPushed != -1)
220 m_nImage[_nImagePushed] = nPushed;
221 if(nFocusOrHover != -1)
222 m_nImage[_nImageFocusOrHover] = nFocusOrHover;
223 if(nDisabled != -1)
224 m_nImage[_nImageDisabled] = nDisabled;
225 }
226
227 BOOL SizeToImage()
228 {
229 ATLASSERT(::IsWindow(m_hWnd) && m_ImageList.m_hImageList != NULL );
230 int cx = 0;
231 int cy = 0;
232 if(!m_ImageList.GetIconSize(cx, cy))
233 return FALSE;
234 return ResizeClient(cx, cy);
235 }
236
237 // Overrideables
238 void DoPaint(CDCHandle dc)
239 {
240 ATLASSERT(m_ImageList.m_hImageList != NULL); // image list mus t be set
241 ATLASSERT(m_nImage[0] != -1); // main bitmap mu st be set
242
243 // set bitmap according to the current button state
244 int nImage = -1;
245 bool bHover = IsHoverMode();
246 if(!IsWindowEnabled())
247 nImage = m_nImage[_nImageDisabled];
248 else if(m_fPressed == 1)
249 nImage = m_nImage[_nImagePushed];
250 else if((!bHover && m_fFocus == 1) || (bHover && m_fMouseOver == 1))
251 nImage = m_nImage[_nImageFocusOrHover];
252 if(nImage == -1) // not there, use default one
253 nImage = m_nImage[_nImageNormal];
254
255 // draw the button image
256 int xyPos = 0;
257 if((m_fPressed == 1) && ((m_dwExtendedStyle & (BMPBTN_AUTO3D_SIN GLE | BMPBTN_AUTO3D_DOUBLE)) != 0) && (m_nImage[_nImagePushed] == -1))
258 xyPos = 1;
259 m_ImageList.Draw(dc, nImage, xyPos, xyPos, ILD_NORMAL);
260
261 // draw 3D border if required
262 if((m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DO UBLE)) != 0)
263 {
264 RECT rect;
265 GetClientRect(&rect);
266
267 if(m_fPressed == 1)
268 dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_ AUTO3D_SINGLE) != 0) ? BDR_SUNKENOUTER : EDGE_SUNKEN, BF_RECT);
269 else if(!bHover || m_fMouseOver == 1)
270 dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_ AUTO3D_SINGLE) != 0) ? BDR_RAISEDINNER : EDGE_RAISED, BF_RECT);
271
272 if(!bHover && m_fFocus == 1)
273 {
274 ::InflateRect(&rect, -2 * ::GetSystemMetrics(SM_ CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE));
275 dc.DrawFocusRect(&rect);
276 }
277 }
278 }
279
280 // Message map and handlers
281 BEGIN_MSG_MAP(CBitmapButtonImpl)
282 MESSAGE_HANDLER(WM_CREATE, OnCreate)
283 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
284 MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessag e)
285 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
286 MESSAGE_HANDLER(WM_PAINT, OnPaint)
287 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
288 MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
289 MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
290 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
291 MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk)
292 MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
293 MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
294 MESSAGE_HANDLER(WM_ENABLE, OnEnable)
295 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
296 MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
297 MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
298 MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)
299 MESSAGE_HANDLER(WM_TIMER, OnTimer)
300 MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState)
301 END_MSG_MAP()
302
303 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BO OL& bHandled)
304 {
305 Init();
306 bHandled = FALSE;
307 return 1;
308 }
309
310 LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, B OOL& bHandled)
311 {
312 if(m_tip.IsWindow())
313 {
314 m_tip.DestroyWindow();
315 m_tip.m_hWnd = NULL;
316 }
317 bHandled = FALSE;
318 return 1;
319 }
320
321 LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bH andled)
322 {
323 MSG msg = { m_hWnd, uMsg, wParam, lParam };
324 if(m_tip.IsWindow())
325 m_tip.RelayEvent(&msg);
326 bHandled = FALSE;
327 return 1;
328 }
329
330 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPa ram*/, BOOL& /*bHandled*/)
331 {
332 return 1; // no background needed
333 }
334
335 LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& / *bHandled*/)
336 {
337 T* pT = static_cast<T*>(this);
338 if(wParam != NULL)
339 {
340 pT->DoPaint((HDC)wParam);
341 }
342 else
343 {
344 CPaintDC dc(m_hWnd);
345 pT->DoPaint(dc.m_hDC);
346 }
347 return 0;
348 }
349
350 LRESULT OnFocus(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& b Handled)
351 {
352 m_fFocus = (uMsg == WM_SETFOCUS) ? 1 : 0;
353 Invalidate();
354 UpdateWindow();
355 bHandled = FALSE;
356 return 1;
357 }
358
359 LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*b Handled*/)
360 {
361 LRESULT lRet = 0;
362 if(IsHoverMode())
363 SetCapture();
364 else
365 lRet = DefWindowProc(uMsg, wParam, lParam);
366 if(::GetCapture() == m_hWnd)
367 {
368 m_fPressed = 1;
369 Invalidate();
370 UpdateWindow();
371 }
372 if((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0)
373 {
374 int nElapse = 250;
375 int nDelay = 0;
376 if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDel ay, 0))
377 nElapse += nDelay * 250; // all milli-seconds
378 SetTimer(ID_TIMER_FIRST, nElapse);
379 }
380 return lRet;
381 }
382
383 LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& / *bHandled*/)
384 {
385 LRESULT lRet = 0;
386 if(!IsHoverMode())
387 lRet = DefWindowProc(uMsg, wParam, lParam);
388 if(::GetCapture() != m_hWnd)
389 SetCapture();
390 if(m_fPressed == 0)
391 {
392 m_fPressed = 1;
393 Invalidate();
394 UpdateWindow();
395 }
396 return lRet;
397 }
398
399 LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHa ndled*/)
400 {
401 LRESULT lRet = 0;
402 bool bHover = IsHoverMode();
403 if(!bHover)
404 lRet = DefWindowProc(uMsg, wParam, lParam);
405 if(::GetCapture() == m_hWnd)
406 {
407 if(bHover && m_fPressed == 1)
408 ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARA M(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
409 ::ReleaseCapture();
410 }
411 return lRet;
412 }
413
414 LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPar am*/, BOOL& bHandled)
415 {
416 if(m_fPressed == 1)
417 {
418 m_fPressed = 0;
419 Invalidate();
420 UpdateWindow();
421 }
422 bHandled = FALSE;
423 return 1;
424 }
425
426 LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BO OL& bHandled)
427 {
428 Invalidate();
429 UpdateWindow();
430 bHandled = FALSE;
431 return 1;
432 }
433
434 LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOO L& bHandled)
435 {
436 if(::GetCapture() == m_hWnd)
437 {
438 POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lP aram) };
439 ClientToScreen(&ptCursor);
440 RECT rect = { 0 };
441 GetWindowRect(&rect);
442 unsigned int uPressed = ::PtInRect(&rect, ptCursor) ? 1 : 0;
443 if(m_fPressed != uPressed)
444 {
445 m_fPressed = uPressed;
446 Invalidate();
447 UpdateWindow();
448 }
449 }
450 else if(IsHoverMode() && m_fMouseOver == 0)
451 {
452 m_fMouseOver = 1;
453 Invalidate();
454 UpdateWindow();
455 StartTrackMouseLeave();
456 }
457 bHandled = FALSE;
458 return 1;
459 }
460
461 LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ , BOOL& /*bHandled*/)
462 {
463 if(m_fMouseOver == 1)
464 {
465 m_fMouseOver = 0;
466 Invalidate();
467 UpdateWindow();
468 }
469 return 0;
470 }
471
472 LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
473 {
474 if(wParam == VK_SPACE && IsHoverMode())
475 return 0; // ignore if in hover mode
476 if(wParam == VK_SPACE && m_fPressed == 0)
477 {
478 m_fPressed = 1;
479 Invalidate();
480 UpdateWindow();
481 }
482 bHandled = FALSE;
483 return 1;
484 }
485
486 LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& b Handled)
487 {
488 if(wParam == VK_SPACE && IsHoverMode())
489 return 0; // ignore if in hover mode
490 if(wParam == VK_SPACE && m_fPressed == 1)
491 {
492 m_fPressed = 0;
493 Invalidate();
494 UpdateWindow();
495 }
496 bHandled = FALSE;
497 return 1;
498 }
499
500 LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& / *bHandled*/)
501 {
502 ATLASSERT((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0);
503 switch(wParam) // timer ID
504 {
505 case ID_TIMER_FIRST:
506 KillTimer(ID_TIMER_FIRST);
507 if(m_fPressed == 1)
508 {
509 ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARA M(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
510 int nElapse = 250;
511 int nRepeat = 40;
512 if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0))
513 nElapse = 10000 / (10 * nRepeat + 25); // milli-seconds, approximated
514 SetTimer(ID_TIMER_REPEAT, nElapse);
515 }
516 break;
517 case ID_TIMER_REPEAT:
518 if(m_fPressed == 1)
519 ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARA M(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
520 else if(::GetCapture() != m_hWnd)
521 KillTimer(ID_TIMER_REPEAT);
522 break;
523 default: // not our timer
524 break;
525 }
526 return 0;
527 }
528
529 LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPara m*/, BOOL& /*bHandled*/)
530 {
531 // If the control is subclassed or superclassed, this message ca n cause
532 // repainting without WM_PAINT. We don't use this state, so just do nothing.
533 return 0;
534 }
535
536 // Implementation
537 void Init()
538 {
539 // We need this style to prevent Windows from painting the butto n
540 ModifyStyle(0, BS_OWNERDRAW);
541
542 // create a tool tip
543 m_tip.Create(m_hWnd);
544 ATLASSERT(m_tip.IsWindow());
545 if(m_tip.IsWindow() && m_lpstrToolTipText != NULL)
546 {
547 m_tip.Activate(TRUE);
548 m_tip.AddTool(m_hWnd, m_lpstrToolTipText);
549 }
550
551 if(m_ImageList.m_hImageList != NULL && (m_dwExtendedStyle & BMPB TN_AUTOSIZE) != 0)
552 SizeToImage();
553 }
554
555 BOOL StartTrackMouseLeave()
556 {
557 TRACKMOUSEEVENT tme = { 0 };
558 tme.cbSize = sizeof(tme);
559 tme.dwFlags = TME_LEAVE;
560 tme.hwndTrack = m_hWnd;
561 return _TrackMouseEvent(&tme);
562 }
563
564 bool IsHoverMode() const
565 {
566 return ((m_dwExtendedStyle & BMPBTN_HOVER) != 0);
567 }
568 };
569
570
571 class CBitmapButton : public CBitmapButtonImpl<CBitmapButton>
572 {
573 public:
574 DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName())
575
576 CBitmapButton(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImage List = NULL) :
577 CBitmapButtonImpl<CBitmapButton>(dwExtendedStyle, hImageList)
578 { }
579 };
580
581 #endif // !_WIN32_WCE
582
583
584 ///////////////////////////////////////////////////////////////////////////////
585 // CCheckListCtrlView - list view control with check boxes
586
587 template <DWORD t_dwStyle, DWORD t_dwExStyle, DWORD t_dwExListViewStyle>
588 class CCheckListViewCtrlImplTraits
589 {
590 public:
591 static DWORD GetWndStyle(DWORD dwStyle)
592 {
593 return (dwStyle == 0) ? t_dwStyle : dwStyle;
594 }
595
596 static DWORD GetWndExStyle(DWORD dwExStyle)
597 {
598 return (dwExStyle == 0) ? t_dwExStyle : dwExStyle;
599 }
600
601 static DWORD GetExtendedLVStyle()
602 {
603 return t_dwExListViewStyle;
604 }
605 };
606
607 typedef CCheckListViewCtrlImplTraits<WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SH OWSELALWAYS, WS_EX_CLIENTEDGE, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT> CChec kListViewCtrlTraits;
608
609 template <class T, class TBase = CListViewCtrl, class TWinTraits = CCheckListVie wCtrlTraits>
610 class ATL_NO_VTABLE CCheckListViewCtrlImpl : public ATL::CWindowImpl<T, TBase, T WinTraits>
611 {
612 public:
613 DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
614
615 // Attributes
616 static DWORD GetExtendedLVStyle()
617 {
618 return TWinTraits::GetExtendedLVStyle();
619 }
620
621 // Operations
622 BOOL SubclassWindow(HWND hWnd)
623 {
624 #if (_MSC_VER >= 1300)
625 BOOL bRet = ATL::CWindowImplBaseT< TBase, TWinTraits>::SubclassW indow(hWnd);
626 #else // !(_MSC_VER >= 1300)
627 typedef ATL::CWindowImplBaseT< TBase, TWinTraits> _baseClass;
628 BOOL bRet = _baseClass::SubclassWindow(hWnd);
629 #endif // !(_MSC_VER >= 1300)
630 if(bRet)
631 {
632 T* pT = static_cast<T*>(this);
633 pT;
634 ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0);
635 SetExtendedListViewStyle(pT->GetExtendedLVStyle());
636 }
637 return bRet;
638 }
639
640 void CheckSelectedItems(int nCurrItem)
641 {
642 // first check if this item is selected
643 LVITEM lvi = { 0 };
644 lvi.iItem = nCurrItem;
645 lvi.iSubItem = 0;
646 lvi.mask = LVIF_STATE;
647 lvi.stateMask = LVIS_SELECTED;
648 GetItem(&lvi);
649 // if item is not selected, don't do anything
650 if(!(lvi.state & LVIS_SELECTED))
651 return;
652 // new check state will be reverse of the current state,
653 BOOL bCheck = !GetCheckState(nCurrItem);
654 int nItem = -1;
655 int nOldItem = -1;
656 while((nItem = GetNextItem(nOldItem, LVNI_SELECTED)) != -1)
657 {
658 if(nItem != nCurrItem)
659 SetCheckState(nItem, bCheck);
660 nOldItem = nItem;
661 }
662 }
663
664 // Implementation
665 BEGIN_MSG_MAP(CCheckListViewCtrlImpl)
666 MESSAGE_HANDLER(WM_CREATE, OnCreate)
667 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
668 MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown)
669 MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
670 END_MSG_MAP()
671
672 LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandl ed*/)
673 {
674 // first let list view control initialize everything
675 LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
676 T* pT = static_cast<T*>(this);
677 pT;
678 ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0);
679 SetExtendedListViewStyle(pT->GetExtendedLVStyle());
680 return lRet;
681 }
682
683 LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B OOL& bHandled)
684 {
685 POINT ptMsg = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
686 LVHITTESTINFO lvh = { 0 };
687 lvh.pt = ptMsg;
688 if(HitTest(&lvh) != -1 && lvh.flags == LVHT_ONITEMSTATEICON && : :GetKeyState(VK_CONTROL) >= 0)
689 {
690 T* pT = static_cast<T*>(this);
691 pT->CheckSelectedItems(lvh.iItem);
692 }
693 bHandled = FALSE;
694 return 1;
695 }
696
697 LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
698 {
699 if(wParam == VK_SPACE)
700 {
701 int nCurrItem = GetNextItem(-1, LVNI_FOCUSED);
702 if(nCurrItem != -1 && ::GetKeyState(VK_CONTROL) >= 0)
703 {
704 T* pT = static_cast<T*>(this);
705 pT->CheckSelectedItems(nCurrItem);
706 }
707 }
708 bHandled = FALSE;
709 return 1;
710 }
711 };
712
713 class CCheckListViewCtrl : public CCheckListViewCtrlImpl<CCheckListViewCtrl>
714 {
715 public:
716 DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName())
717 };
718
719
720 ///////////////////////////////////////////////////////////////////////////////
721 // CHyperLink - hyper link control implementation
722
723 #if (WINVER < 0x0500) && !defined(_WIN32_WCE)
724 __declspec(selectany) struct
725 {
726 enum { cxWidth = 32, cyHeight = 32 };
727 int xHotSpot;
728 int yHotSpot;
729 unsigned char arrANDPlane[cxWidth * cyHeight / 8];
730 unsigned char arrXORPlane[cxWidth * cyHeight / 8];
731 } _AtlHyperLink_CursorData =
732 {
733 5, 0,
734 {
735 0xF9, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0xFF, 0xFF , 0xFF, 0xF0, 0xFF, 0xFF, 0xFF,
736 0xF0, 0xFF, 0xFF, 0xFF, 0xF0, 0x3F, 0xFF, 0xFF, 0xF0, 0x07, 0xFF , 0xFF, 0xF0, 0x01, 0xFF, 0xFF,
737 0xF0, 0x00, 0xFF, 0xFF, 0x10, 0x00, 0x7F, 0xFF, 0x00, 0x00, 0x7F , 0xFF, 0x00, 0x00, 0x7F, 0xFF,
738 0x80, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F, 0xFF, 0xC0, 0x00, 0x7F , 0xFF, 0xE0, 0x00, 0x7F, 0xFF,
739 0xE0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x00, 0xFF , 0xFF, 0xF8, 0x01, 0xFF, 0xFF,
740 0xF8, 0x01, 0xFF, 0xFF, 0xF8, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF , 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
741 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF , 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
742 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF , 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
743 },
744 {
745 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00 , 0x00, 0x06, 0x00, 0x00, 0x00,
746 0x06, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x06, 0xC0, 0x00 , 0x00, 0x06, 0xD8, 0x00, 0x00,
747 0x06, 0xDA, 0x00, 0x00, 0x06, 0xDB, 0x00, 0x00, 0x67, 0xFB, 0x00 , 0x00, 0x77, 0xFF, 0x00, 0x00,
748 0x37, 0xFF, 0x00, 0x00, 0x17, 0xFF, 0x00, 0x00, 0x1F, 0xFF, 0x00 , 0x00, 0x0F, 0xFF, 0x00, 0x00,
749 0x0F, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00, 0x00, 0x07, 0xFE, 0x00 , 0x00, 0x03, 0xFC, 0x00, 0x00,
750 0x03, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00,
751 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00,
752 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 , 0x00, 0x00, 0x00, 0x00, 0x00
753 }
754 };
755 #endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)
756
757 #define HLINK_UNDERLINED 0x00000000
758 #define HLINK_NOTUNDERLINED 0x00000001
759 #define HLINK_UNDERLINEHOVER 0x00000002
760 #define HLINK_COMMANDBUTTON 0x00000004
761 #define HLINK_NOTIFYBUTTON 0x0000000C
762 #define HLINK_USETAGS 0x00000010
763 #define HLINK_USETAGSBOLD 0x00000030
764 #define HLINK_NOTOOLTIP 0x00000040
765
766 // Notes:
767 // - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned
768 // - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored
769
770 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlW inTraits>
771 class ATL_NO_VTABLE CHyperLinkImpl : public ATL::CWindowImpl< T, TBase, TWinTrai ts >
772 {
773 public:
774 LPTSTR m_lpstrLabel;
775 LPTSTR m_lpstrHyperLink;
776
777 HCURSOR m_hCursor;
778 HFONT m_hFont;
779 HFONT m_hFontNormal;
780
781 RECT m_rcLink;
782 #ifndef _WIN32_WCE
783 CToolTipCtrl m_tip;
784 #endif // !_WIN32_WCE
785
786 COLORREF m_clrLink;
787 COLORREF m_clrVisited;
788
789 DWORD m_dwExtendedStyle; // Hyper Link specific extended styles
790
791 bool m_bPaintLabel:1;
792 bool m_bVisited:1;
793 bool m_bHover:1;
794 bool m_bInternalLinkFont:1;
795
796
797 // Constructor/Destructor
798 CHyperLinkImpl(DWORD dwExtendedStyle = HLINK_UNDERLINED) :
799 m_lpstrLabel(NULL), m_lpstrHyperLink(NULL),
800 m_hCursor(NULL), m_hFont(NULL), m_hFontNormal(NULL),
801 m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128) ),
802 m_dwExtendedStyle(dwExtendedStyle),
803 m_bPaintLabel(true), m_bVisited(false),
804 m_bHover(false), m_bInternalLinkFont(false)
805 {
806 ::SetRectEmpty(&m_rcLink);
807 }
808
809 ~CHyperLinkImpl()
810 {
811 delete [] m_lpstrLabel;
812 delete [] m_lpstrHyperLink;
813 if(m_bInternalLinkFont && m_hFont != NULL)
814 ::DeleteObject(m_hFont);
815 #if (WINVER < 0x0500) && !defined(_WIN32_WCE)
816 // It was created, not loaded, so we have to destroy it
817 if(m_hCursor != NULL)
818 ::DestroyCursor(m_hCursor);
819 #endif // (WINVER < 0x0500) && !defined(_WIN32_WCE)
820 }
821
822 // Attributes
823 DWORD GetHyperLinkExtendedStyle() const
824 {
825 return m_dwExtendedStyle;
826 }
827
828 DWORD SetHyperLinkExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
829 {
830 DWORD dwPrevStyle = m_dwExtendedStyle;
831 if(dwMask == 0)
832 m_dwExtendedStyle = dwExtendedStyle;
833 else
834 m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwE xtendedStyle & dwMask);
835 return dwPrevStyle;
836 }
837
838 bool GetLabel(LPTSTR lpstrBuffer, int nLength) const
839 {
840 if(m_lpstrLabel == NULL)
841 return false;
842 ATLASSERT(lpstrBuffer != NULL);
843 if(nLength <= lstrlen(m_lpstrLabel))
844 return false;
845
846 SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrLabel);
847
848 return true;
849 }
850
851 bool SetLabel(LPCTSTR lpstrLabel)
852 {
853 delete [] m_lpstrLabel;
854 m_lpstrLabel = NULL;
855 int cchLen = lstrlen(lpstrLabel) + 1;
856 ATLTRY(m_lpstrLabel = new TCHAR[cchLen]);
857 if(m_lpstrLabel == NULL)
858 return false;
859
860 SecureHelper::strcpy_x(m_lpstrLabel, cchLen, lpstrLabel);
861 T* pT = static_cast<T*>(this);
862 pT->CalcLabelRect();
863
864 if(m_hWnd != NULL)
865 SetWindowText(lpstrLabel); // Set this for accessibili ty
866
867 return true;
868 }
869
870 bool GetHyperLink(LPTSTR lpstrBuffer, int nLength) const
871 {
872 if(m_lpstrHyperLink == NULL)
873 return false;
874 ATLASSERT(lpstrBuffer != NULL);
875 if(nLength <= lstrlen(m_lpstrHyperLink))
876 return false;
877
878 SecureHelper::strcpy_x(lpstrBuffer, nLength, m_lpstrHyperLink);
879
880 return true;
881 }
882
883 bool SetHyperLink(LPCTSTR lpstrLink)
884 {
885 delete [] m_lpstrHyperLink;
886 m_lpstrHyperLink = NULL;
887 int cchLen = lstrlen(lpstrLink) + 1;
888 ATLTRY(m_lpstrHyperLink = new TCHAR[cchLen]);
889 if(m_lpstrHyperLink == NULL)
890 return false;
891
892 SecureHelper::strcpy_x(m_lpstrHyperLink, cchLen, lpstrLink);
893 if(m_lpstrLabel == NULL)
894 {
895 T* pT = static_cast<T*>(this);
896 pT->CalcLabelRect();
897 }
898 #ifndef _WIN32_WCE
899 if(m_tip.IsWindow())
900 {
901 m_tip.Activate(TRUE);
902 m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1);
903 }
904 #endif // !_WIN32_WCE
905 return true;
906 }
907
908 HFONT GetLinkFont() const
909 {
910 return m_hFont;
911 }
912
913 void SetLinkFont(HFONT hFont)
914 {
915 if(m_bInternalLinkFont && m_hFont != NULL)
916 {
917 ::DeleteObject(m_hFont);
918 m_bInternalLinkFont = false;
919 }
920 m_hFont = hFont;
921 }
922
923 int GetIdealHeight() const
924 {
925 ATLASSERT(::IsWindow(m_hWnd));
926 if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
927 return -1;
928 if(!m_bPaintLabel)
929 return -1;
930
931 CClientDC dc(m_hWnd);
932 RECT rect = { 0 };
933 GetClientRect(&rect);
934 HFONT hFontOld = dc.SelectFont(m_hFontNormal);
935 RECT rcText = rect;
936 dc.DrawText(_T("NS"), -1, &rcText, DT_LEFT | DT_WORDBREAK | DT_C ALCRECT);
937 dc.SelectFont(m_hFont);
938 RECT rcLink = rect;
939 dc.DrawText(_T("NS"), -1, &rcLink, DT_LEFT | DT_WORDBREAK | DT_C ALCRECT);
940 dc.SelectFont(hFontOld);
941 return __max(rcText.bottom - rcText.top, rcLink.bottom - rcLink. top);
942 }
943
944 bool GetIdealSize(SIZE& size) const
945 {
946 int cx = 0, cy = 0;
947 bool bRet = GetIdealSize(cx, cy);
948 if(bRet)
949 {
950 size.cx = cx;
951 size.cy = cy;
952 }
953 return bRet;
954 }
955
956 bool GetIdealSize(int& cx, int& cy) const
957 {
958 ATLASSERT(::IsWindow(m_hWnd));
959 if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
960 return false;
961 if(!m_bPaintLabel)
962 return false;
963
964 CClientDC dc(m_hWnd);
965 RECT rcClient = { 0 };
966 GetClientRect(&rcClient);
967 RECT rcAll = rcClient;
968
969 if(IsUsingTags())
970 {
971 // find tags and label parts
972 LPTSTR lpstrLeft = NULL;
973 int cchLeft = 0;
974 LPTSTR lpstrLink = NULL;
975 int cchLink = 0;
976 LPTSTR lpstrRight = NULL;
977 int cchRight = 0;
978
979 const T* pT = static_cast<const T*>(this);
980 pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLin k, lpstrRight, cchRight);
981
982 // get label part rects
983 HFONT hFontOld = dc.SelectFont(m_hFontNormal);
984 RECT rcLeft = rcClient;
985 dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | DT_WO RDBREAK | DT_CALCRECT);
986
987 dc.SelectFont(m_hFont);
988 RECT rcLink = { rcLeft.right, rcLeft.top, rcClient.right , rcClient.bottom };
989 dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | DT_WO RDBREAK | DT_CALCRECT);
990
991 dc.SelectFont(m_hFontNormal);
992 RECT rcRight = { rcLink.right, rcLink.top, rcClient.righ t, rcClient.bottom };
993 dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | DT _WORDBREAK | DT_CALCRECT);
994
995 dc.SelectFont(hFontOld);
996
997 int cyMax = __max(rcLeft.bottom, max(rcLink.bottom, rcRi ght.bottom));
998 ::SetRect(&rcAll, rcLeft.left, rcLeft.top, rcRight.right , cyMax);
999 }
1000 else
1001 {
1002 HFONT hOldFont = NULL;
1003 if(m_hFont != NULL)
1004 hOldFont = dc.SelectFont(m_hFont);
1005 LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
1006 DWORD dwStyle = GetStyle();
1007 int nDrawStyle = DT_LEFT;
1008 if (dwStyle & SS_CENTER)
1009 nDrawStyle = DT_CENTER;
1010 else if (dwStyle & SS_RIGHT)
1011 nDrawStyle = DT_RIGHT;
1012 dc.DrawText(lpstrText, -1, &rcAll, nDrawStyle | DT_WORDB REAK | DT_CALCRECT);
1013 if(m_hFont != NULL)
1014 dc.SelectFont(hOldFont);
1015 if (dwStyle & SS_CENTER)
1016 {
1017 int dx = (rcClient.right - rcAll.right) / 2;
1018 ::OffsetRect(&rcAll, dx, 0);
1019 }
1020 else if (dwStyle & SS_RIGHT)
1021 {
1022 int dx = rcClient.right - rcAll.right;
1023 ::OffsetRect(&rcAll, dx, 0);
1024 }
1025 }
1026
1027 cx = rcAll.right - rcAll.left;
1028 cy = rcAll.bottom - rcAll.top;
1029
1030 return true;
1031 }
1032
1033 // for command buttons only
1034 bool GetToolTipText(LPTSTR lpstrBuffer, int nLength) const
1035 {
1036 ATLASSERT(IsCommandButton());
1037 return GetHyperLink(lpstrBuffer, nLength);
1038 }
1039
1040 bool SetToolTipText(LPCTSTR lpstrToolTipText)
1041 {
1042 ATLASSERT(IsCommandButton());
1043 return SetHyperLink(lpstrToolTipText);
1044 }
1045
1046 // Operations
1047 BOOL SubclassWindow(HWND hWnd)
1048 {
1049 ATLASSERT(m_hWnd == NULL);
1050 ATLASSERT(::IsWindow(hWnd));
1051 #if (_MSC_VER >= 1300)
1052 BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits>::SubclassWin dow(hWnd);
1053 #else // !(_MSC_VER >= 1300)
1054 typedef ATL::CWindowImpl< T, TBase, TWinTraits> _baseClass;
1055 BOOL bRet = _baseClass::SubclassWindow(hWnd);
1056 #endif // !(_MSC_VER >= 1300)
1057 if(bRet)
1058 {
1059 T* pT = static_cast<T*>(this);
1060 pT->Init();
1061 }
1062 return bRet;
1063 }
1064
1065 bool Navigate()
1066 {
1067 ATLASSERT(::IsWindow(m_hWnd));
1068 bool bRet = true;
1069 if(IsNotifyButton())
1070 {
1071 NMHDR nmhdr = { m_hWnd, GetDlgCtrlID(), NM_CLICK };
1072 ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (L PARAM)&nmhdr);
1073 }
1074 else if(IsCommandButton())
1075 {
1076 ::SendMessage(GetParent(), WM_COMMAND, MAKEWPARAM(GetDlg CtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
1077 }
1078 else
1079 {
1080 ATLASSERT(m_lpstrHyperLink != NULL);
1081 #ifndef _WIN32_WCE
1082 DWORD_PTR dwRet = (DWORD_PTR)::ShellExecute(0, _T("open" ), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL);
1083 bRet = (dwRet > 32);
1084 #else // CE specific
1085 SHELLEXECUTEINFO shExeInfo = { sizeof(SHELLEXECUTEINFO), 0, 0, L"open", m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL, 0, 0, 0, 0, 0, 0, 0 };
1086 ::ShellExecuteEx(&shExeInfo);
1087 DWORD_PTR dwRet = (DWORD_PTR)shExeInfo.hInstApp;
1088 bRet = (dwRet == 0) || (dwRet > 32);
1089 #endif // _WIN32_WCE
1090 ATLASSERT(bRet);
1091 if(bRet)
1092 {
1093 m_bVisited = true;
1094 Invalidate();
1095 }
1096 }
1097 return bRet;
1098 }
1099
1100 // Message map and handlers
1101 BEGIN_MSG_MAP(CHyperLinkImpl)
1102 MESSAGE_HANDLER(WM_CREATE, OnCreate)
1103 #ifndef _WIN32_WCE
1104 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
1105 MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessag e)
1106 #endif // !_WIN32_WCE
1107 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
1108 MESSAGE_HANDLER(WM_PAINT, OnPaint)
1109 #ifndef _WIN32_WCE
1110 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
1111 #endif // !_WIN32_WCE
1112 MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
1113 MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
1114 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
1115 #ifndef _WIN32_WCE
1116 MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
1117 #endif // !_WIN32_WCE
1118 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
1119 MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
1120 MESSAGE_HANDLER(WM_CHAR, OnChar)
1121 MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
1122 MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
1123 MESSAGE_HANDLER(WM_ENABLE, OnEnable)
1124 MESSAGE_HANDLER(WM_GETFONT, OnGetFont)
1125 MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
1126 MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState)
1127 MESSAGE_HANDLER(WM_SIZE, OnSize)
1128 END_MSG_MAP()
1129
1130 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BO OL& /*bHandled*/)
1131 {
1132 T* pT = static_cast<T*>(this);
1133 pT->Init();
1134 return 0;
1135 }
1136
1137 #ifndef _WIN32_WCE
1138 LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, B OOL& bHandled)
1139 {
1140 if(m_tip.IsWindow())
1141 {
1142 m_tip.DestroyWindow();
1143 m_tip.m_hWnd = NULL;
1144 }
1145 bHandled = FALSE;
1146 return 1;
1147 }
1148
1149 LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bH andled)
1150 {
1151 MSG msg = { m_hWnd, uMsg, wParam, lParam };
1152 if(m_tip.IsWindow() && IsUsingToolTip())
1153 m_tip.RelayEvent(&msg);
1154 bHandled = FALSE;
1155 return 1;
1156 }
1157 #endif // !_WIN32_WCE
1158
1159 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPa ram*/, BOOL& /*bHandled*/)
1160 {
1161 return 1; // no background painting needed (we do it all durin g WM_PAINT)
1162 }
1163
1164 LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& b Handled)
1165 {
1166 if(!m_bPaintLabel)
1167 {
1168 bHandled = FALSE;
1169 return 1;
1170 }
1171
1172 T* pT = static_cast<T*>(this);
1173 if(wParam != NULL)
1174 {
1175 pT->DoEraseBackground((HDC)wParam);
1176 pT->DoPaint((HDC)wParam);
1177 }
1178 else
1179 {
1180 CPaintDC dc(m_hWnd);
1181 pT->DoEraseBackground(dc.m_hDC);
1182 pT->DoPaint(dc.m_hDC);
1183 }
1184
1185 return 0;
1186 }
1187
1188 LRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOO L& bHandled)
1189 {
1190 if(m_bPaintLabel)
1191 Invalidate();
1192 else
1193 bHandled = FALSE;
1194 return 0;
1195 }
1196
1197 LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOO L& bHandled)
1198 {
1199 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1200 if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRec t(&m_rcLink, pt))
1201 {
1202 ::SetCursor(m_hCursor);
1203 if(IsUnderlineHover())
1204 {
1205 if(!m_bHover)
1206 {
1207 m_bHover = true;
1208 InvalidateRect(&m_rcLink);
1209 UpdateWindow();
1210 #ifndef _WIN32_WCE
1211 StartTrackMouseLeave();
1212 #endif // !_WIN32_WCE
1213 }
1214 }
1215 }
1216 else
1217 {
1218 if(IsUnderlineHover())
1219 {
1220 if(m_bHover)
1221 {
1222 m_bHover = false;
1223 InvalidateRect(&m_rcLink);
1224 UpdateWindow();
1225 }
1226 }
1227 bHandled = FALSE;
1228 }
1229 return 0;
1230 }
1231
1232 #ifndef _WIN32_WCE
1233 LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ , BOOL& /*bHandled*/)
1234 {
1235 if(IsUnderlineHover() && m_bHover)
1236 {
1237 m_bHover = false;
1238 InvalidateRect(&m_rcLink);
1239 UpdateWindow();
1240 }
1241 return 0;
1242 }
1243 #endif // !_WIN32_WCE
1244
1245 LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, B OOL& /*bHandled*/)
1246 {
1247 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1248 if(::PtInRect(&m_rcLink, pt))
1249 {
1250 SetFocus();
1251 SetCapture();
1252 }
1253 return 0;
1254 }
1255
1256 LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOO L& /*bHandled*/)
1257 {
1258 if(GetCapture() == m_hWnd)
1259 {
1260 ReleaseCapture();
1261 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
1262 if(::PtInRect(&m_rcLink, pt))
1263 {
1264 T* pT = static_cast<T*>(this);
1265 pT->Navigate();
1266 }
1267 }
1268 return 0;
1269 }
1270
1271 LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /* bHandled*/)
1272 {
1273 if(wParam == VK_RETURN || wParam == VK_SPACE)
1274 {
1275 T* pT = static_cast<T*>(this);
1276 pT->Navigate();
1277 }
1278 return 0;
1279 }
1280
1281 LRESULT OnGetDlgCode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/ , BOOL& /*bHandled*/)
1282 {
1283 return DLGC_WANTCHARS;
1284 }
1285
1286 LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
1287 {
1288 POINT pt = { 0, 0 };
1289 GetCursorPos(&pt);
1290 ScreenToClient(&pt);
1291 if((m_lpstrHyperLink != NULL || IsCommandButton()) && ::PtInRec t(&m_rcLink, pt))
1292 {
1293 return TRUE;
1294 }
1295 bHandled = FALSE;
1296 return FALSE;
1297 }
1298
1299 LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BO OL& /*bHandled*/)
1300 {
1301 Invalidate();
1302 UpdateWindow();
1303 return 0;
1304 }
1305
1306 LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, B OOL& /*bHandled*/)
1307 {
1308 return (LRESULT)m_hFontNormal;
1309 }
1310
1311 LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*b Handled*/)
1312 {
1313 m_hFontNormal = (HFONT)wParam;
1314 if((BOOL)lParam)
1315 {
1316 Invalidate();
1317 UpdateWindow();
1318 }
1319 return 0;
1320 }
1321
1322 LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPara m*/, BOOL& /*bHandled*/)
1323 {
1324 // If the control is subclassed or superclassed, this message ca n cause
1325 // repainting without WM_PAINT. We don't use this state, so just do nothing.
1326 return 0;
1327 }
1328
1329 LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/)
1330 {
1331 T* pT = static_cast<T*>(this);
1332 pT->CalcLabelRect();
1333 pT->Invalidate();
1334 return 0;
1335 }
1336
1337 // Implementation
1338 void Init()
1339 {
1340 ATLASSERT(::IsWindow(m_hWnd));
1341
1342 // Check if we should paint a label
1343 const int cchBuff = 8;
1344 TCHAR szBuffer[cchBuff] = { 0 };
1345 if(::GetClassName(m_hWnd, szBuffer, cchBuff))
1346 {
1347 if(lstrcmpi(szBuffer, _T("static")) == 0)
1348 {
1349 ModifyStyle(0, SS_NOTIFY); // we need this
1350 DWORD dwStyle = GetStyle() & 0x000000FF;
1351 #ifndef _WIN32_WCE
1352 if(dwStyle == SS_ICON || dwStyle == SS_BLACKRECT || dwStyle == SS_GRAYRECT ||
1353 dwStyle == SS_WHITERECT || dwSty le == SS_BLACKFRAME || dwStyle == SS_GRAYFRAME ||
1354 dwStyle == SS_WHITEFRAME || dwSt yle == SS_OWNERDRAW ||
1355 dwStyle == SS_BITMAP || dwStyle == SS_ENHMETAFILE)
1356 #else // CE specific
1357 if(dwStyle == SS_ICON || dwStyle == SS_BITMAP)
1358 #endif // _WIN32_WCE
1359 m_bPaintLabel = false;
1360 }
1361 }
1362
1363 // create or load a cursor
1364 #if (WINVER >= 0x0500) || defined(_WIN32_WCE)
1365 m_hCursor = ::LoadCursor(NULL, IDC_HAND);
1366 #else
1367 m_hCursor = ::CreateCursor(ModuleHelper::GetModuleInstance(), _A tlHyperLink_CursorData.xHotSpot, _AtlHyperLink_CursorData.yHotSpot, _AtlHyperLin k_CursorData.cxWidth, _AtlHyperLink_CursorData.cyHeight, _AtlHyperLink_CursorDat a.arrANDPlane, _AtlHyperLink_CursorData.arrXORPlane);
1368 #endif
1369 ATLASSERT(m_hCursor != NULL);
1370
1371 // set font
1372 if(m_bPaintLabel)
1373 {
1374 ATL::CWindow wnd = GetParent();
1375 m_hFontNormal = wnd.GetFont();
1376 if(m_hFontNormal == NULL)
1377 m_hFontNormal = (HFONT)::GetStockObject(SYSTEM_F ONT);
1378 if(m_hFontNormal != NULL && m_hFont == NULL)
1379 {
1380 LOGFONT lf = { 0 };
1381 CFontHandle font = m_hFontNormal;
1382 font.GetLogFont(&lf);
1383 if(IsUsingTagsBold())
1384 lf.lfWeight = FW_BOLD;
1385 else if(!IsNotUnderlined())
1386 lf.lfUnderline = TRUE;
1387 m_hFont = ::CreateFontIndirect(&lf);
1388 m_bInternalLinkFont = true;
1389 ATLASSERT(m_hFont != NULL);
1390 }
1391 }
1392
1393 #ifndef _WIN32_WCE
1394 // create a tool tip
1395 m_tip.Create(m_hWnd);
1396 ATLASSERT(m_tip.IsWindow());
1397 #endif // !_WIN32_WCE
1398
1399 // set label (defaults to window text)
1400 if(m_lpstrLabel == NULL)
1401 {
1402 int nLen = GetWindowTextLength();
1403 if(nLen > 0)
1404 {
1405 CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> b uff;
1406 LPTSTR lpstrText = buff.Allocate(nLen + 1);
1407 ATLASSERT(lpstrText != NULL);
1408 if((lpstrText != NULL) && (GetWindowText(lpstrTe xt, nLen + 1) > 0))
1409 SetLabel(lpstrText);
1410 }
1411 }
1412
1413 T* pT = static_cast<T*>(this);
1414 pT->CalcLabelRect();
1415
1416 // set hyperlink (defaults to label), or just activate tool tip if already set
1417 if(m_lpstrHyperLink == NULL && !IsCommandButton())
1418 {
1419 if(m_lpstrLabel != NULL)
1420 SetHyperLink(m_lpstrLabel);
1421 }
1422 #ifndef _WIN32_WCE
1423 else
1424 {
1425 m_tip.Activate(TRUE);
1426 m_tip.AddTool(m_hWnd, m_lpstrHyperLink, &m_rcLink, 1);
1427 }
1428 #endif // !_WIN32_WCE
1429
1430 // set link colors
1431 if(m_bPaintLabel)
1432 {
1433 ATL::CRegKey rk;
1434 LONG lRet = rk.Open(HKEY_CURRENT_USER, _T("Software\\Mic rosoft\\Internet Explorer\\Settings"));
1435 if(lRet == 0)
1436 {
1437 const int cchValue = 12;
1438 TCHAR szValue[cchValue] = { 0 };
1439 #if (_ATL_VER >= 0x0700)
1440 ULONG ulCount = cchValue;
1441 lRet = rk.QueryStringValue(_T("Anchor Color"), s zValue, &ulCount);
1442 #else
1443 DWORD dwCount = cchValue * sizeof(TCHAR);
1444 lRet = rk.QueryValue(szValue, _T("Anchor Color") , &dwCount);
1445 #endif
1446 if(lRet == 0)
1447 {
1448 COLORREF clr = pT->_ParseColorString(szV alue);
1449 ATLASSERT(clr != CLR_INVALID);
1450 if(clr != CLR_INVALID)
1451 m_clrLink = clr;
1452 }
1453
1454 #if (_ATL_VER >= 0x0700)
1455 ulCount = cchValue;
1456 lRet = rk.QueryStringValue(_T("Anchor Color Visi ted"), szValue, &ulCount);
1457 #else
1458 dwCount = cchValue * sizeof(TCHAR);
1459 lRet = rk.QueryValue(szValue, _T("Anchor Color V isited"), &dwCount);
1460 #endif
1461 if(lRet == 0)
1462 {
1463 COLORREF clr = pT->_ParseColorString(szV alue);
1464 ATLASSERT(clr != CLR_INVALID);
1465 if(clr != CLR_INVALID)
1466 m_clrVisited = clr;
1467 }
1468 }
1469 }
1470 }
1471
1472 static COLORREF _ParseColorString(LPTSTR lpstr)
1473 {
1474 int c[3] = { -1, -1, -1 };
1475 LPTSTR p = NULL;
1476 for(int i = 0; i < 2; i++)
1477 {
1478 for(p = lpstr; *p != _T('\0'); p = ::CharNext(p))
1479 {
1480 if(*p == _T(','))
1481 {
1482 *p = _T('\0');
1483 c[i] = T::_xttoi(lpstr);
1484 lpstr = &p[1];
1485 break;
1486 }
1487 }
1488 if(c[i] == -1)
1489 return CLR_INVALID;
1490 }
1491 if(*lpstr == _T('\0'))
1492 return CLR_INVALID;
1493 c[2] = T::_xttoi(lpstr);
1494
1495 return RGB(c[0], c[1], c[2]);
1496 }
1497
1498 bool CalcLabelRect()
1499 {
1500 if(!::IsWindow(m_hWnd))
1501 return false;
1502 if(m_lpstrLabel == NULL && m_lpstrHyperLink == NULL)
1503 return false;
1504
1505 CClientDC dc(m_hWnd);
1506 RECT rcClient = { 0 };
1507 GetClientRect(&rcClient);
1508 m_rcLink = rcClient;
1509 if(!m_bPaintLabel)
1510 return true;
1511
1512 if(IsUsingTags())
1513 {
1514 // find tags and label parts
1515 LPTSTR lpstrLeft = NULL;
1516 int cchLeft = 0;
1517 LPTSTR lpstrLink = NULL;
1518 int cchLink = 0;
1519 LPTSTR lpstrRight = NULL;
1520 int cchRight = 0;
1521
1522 T* pT = static_cast<T*>(this);
1523 pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLin k, lpstrRight, cchRight);
1524 ATLASSERT(lpstrLink != NULL);
1525 ATLASSERT(cchLink > 0);
1526
1527 // get label part rects
1528 HFONT hFontOld = dc.SelectFont(m_hFontNormal);
1529
1530 RECT rcLeft = rcClient;
1531 if(lpstrLeft != NULL)
1532 dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | DT_WORDBREAK | DT_CALCRECT);
1533
1534 dc.SelectFont(m_hFont);
1535 RECT rcLink = rcClient;
1536 if(lpstrLeft != NULL)
1537 rcLink.left = rcLeft.right;
1538 dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | DT_WO RDBREAK | DT_CALCRECT);
1539
1540 dc.SelectFont(hFontOld);
1541
1542 m_rcLink = rcLink;
1543 }
1544 else
1545 {
1546 HFONT hOldFont = NULL;
1547 if(m_hFont != NULL)
1548 hOldFont = dc.SelectFont(m_hFont);
1549 LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
1550 DWORD dwStyle = GetStyle();
1551 int nDrawStyle = DT_LEFT;
1552 if (dwStyle & SS_CENTER)
1553 nDrawStyle = DT_CENTER;
1554 else if (dwStyle & SS_RIGHT)
1555 nDrawStyle = DT_RIGHT;
1556 dc.DrawText(lpstrText, -1, &m_rcLink, nDrawStyle | DT_WO RDBREAK | DT_CALCRECT);
1557 if(m_hFont != NULL)
1558 dc.SelectFont(hOldFont);
1559 if (dwStyle & SS_CENTER)
1560 {
1561 int dx = (rcClient.right - m_rcLink.right) / 2;
1562 ::OffsetRect(&m_rcLink, dx, 0);
1563 }
1564 else if (dwStyle & SS_RIGHT)
1565 {
1566 int dx = rcClient.right - m_rcLink.right;
1567 ::OffsetRect(&m_rcLink, dx, 0);
1568 }
1569 }
1570
1571 return true;
1572 }
1573
1574 void CalcLabelParts(LPTSTR& lpstrLeft, int& cchLeft, LPTSTR& lpstrLink, int& cchLink, LPTSTR& lpstrRight, int& cchRight) const
1575 {
1576 lpstrLeft = NULL;
1577 cchLeft = 0;
1578 lpstrLink = NULL;
1579 cchLink = 0;
1580 lpstrRight = NULL;
1581 cchRight = 0;
1582
1583 LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lps trHyperLink;
1584 int cchText = lstrlen(lpstrText);
1585 bool bOutsideLink = true;
1586 for(int i = 0; i < cchText; i++)
1587 {
1588 if(lpstrText[i] != _T('<'))
1589 continue;
1590
1591 if(bOutsideLink)
1592 {
1593 if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGN ORECASE, &lpstrText[i], 3, _T("<A>"), 3) == CSTR_EQUAL)
1594 {
1595 if(i > 0)
1596 {
1597 lpstrLeft = lpstrText;
1598 cchLeft = i;
1599 }
1600 lpstrLink = &lpstrText[i + 3];
1601 bOutsideLink = false;
1602 }
1603 }
1604 else
1605 {
1606 if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGN ORECASE, &lpstrText[i], 4, _T("</A>"), 4) == CSTR_EQUAL)
1607 {
1608 cchLink = i - 3 - cchLeft;
1609 if(lpstrText[i + 4] != 0)
1610 {
1611 lpstrRight = &lpstrText[i + 4];
1612 cchRight = cchText - (i + 4);
1613 break;
1614 }
1615 }
1616 }
1617 }
1618
1619 }
1620
1621 void DoEraseBackground(CDCHandle dc)
1622 {
1623 HBRUSH hBrush = (HBRUSH)::SendMessage(GetParent(), WM_CTLCOLORST ATIC, (WPARAM)dc.m_hDC, (LPARAM)m_hWnd);
1624 if(hBrush != NULL)
1625 {
1626 RECT rect = { 0 };
1627 GetClientRect(&rect);
1628 dc.FillRect(&rect, hBrush);
1629 }
1630 }
1631
1632 void DoPaint(CDCHandle dc)
1633 {
1634 if(IsUsingTags())
1635 {
1636 // find tags and label parts
1637 LPTSTR lpstrLeft = NULL;
1638 int cchLeft = 0;
1639 LPTSTR lpstrLink = NULL;
1640 int cchLink = 0;
1641 LPTSTR lpstrRight = NULL;
1642 int cchRight = 0;
1643
1644 T* pT = static_cast<T*>(this);
1645 pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLin k, lpstrRight, cchRight);
1646
1647 // get label part rects
1648 RECT rcClient = { 0 };
1649 GetClientRect(&rcClient);
1650
1651 dc.SetBkMode(TRANSPARENT);
1652 HFONT hFontOld = dc.SelectFont(m_hFontNormal);
1653
1654 if(lpstrLeft != NULL)
1655 dc.DrawText(lpstrLeft, cchLeft, &rcClient, DT_LE FT | DT_WORDBREAK);
1656
1657 COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m _bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT)));
1658 if(m_hFont != NULL && (!IsUnderlineHover() || (IsUnderli neHover() && m_bHover)))
1659 dc.SelectFont(m_hFont);
1660 else
1661 dc.SelectFont(m_hFontNormal);
1662
1663 dc.DrawText(lpstrLink, cchLink, &m_rcLink, DT_LEFT | DT_ WORDBREAK);
1664
1665 dc.SetTextColor(clrOld);
1666 dc.SelectFont(m_hFontNormal);
1667 if(lpstrRight != NULL)
1668 {
1669 RECT rcRight = { m_rcLink.right, m_rcLink.top, r cClient.right, rcClient.bottom };
1670 dc.DrawText(lpstrRight, cchRight, &rcRight, DT_L EFT | DT_WORDBREAK);
1671 }
1672
1673 if(GetFocus() == m_hWnd)
1674 dc.DrawFocusRect(&m_rcLink);
1675
1676 dc.SelectFont(hFontOld);
1677 }
1678 else
1679 {
1680 dc.SetBkMode(TRANSPARENT);
1681 COLORREF clrOld = dc.SetTextColor(IsWindowEnabled() ? (m _bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT)));
1682
1683 HFONT hFontOld = NULL;
1684 if(m_hFont != NULL && (!IsUnderlineHover() || (IsUnderli neHover() && m_bHover)))
1685 hFontOld = dc.SelectFont(m_hFont);
1686 else
1687 hFontOld = dc.SelectFont(m_hFontNormal);
1688
1689 LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
1690
1691 DWORD dwStyle = GetStyle();
1692 int nDrawStyle = DT_LEFT;
1693 if (dwStyle & SS_CENTER)
1694 nDrawStyle = DT_CENTER;
1695 else if (dwStyle & SS_RIGHT)
1696 nDrawStyle = DT_RIGHT;
1697
1698 dc.DrawText(lpstrText, -1, &m_rcLink, nDrawStyle | DT_WO RDBREAK);
1699
1700 if(GetFocus() == m_hWnd)
1701 dc.DrawFocusRect(&m_rcLink);
1702
1703 dc.SetTextColor(clrOld);
1704 dc.SelectFont(hFontOld);
1705 }
1706 }
1707
1708 #ifndef _WIN32_WCE
1709 BOOL StartTrackMouseLeave()
1710 {
1711 TRACKMOUSEEVENT tme = { 0 };
1712 tme.cbSize = sizeof(tme);
1713 tme.dwFlags = TME_LEAVE;
1714 tme.hwndTrack = m_hWnd;
1715 return _TrackMouseEvent(&tme);
1716 }
1717 #endif // !_WIN32_WCE
1718
1719 // Implementation helpers
1720 bool IsUnderlined() const
1721 {
1722 return ((m_dwExtendedStyle & (HLINK_NOTUNDERLINED | HLINK_UNDERL INEHOVER)) == 0);
1723 }
1724
1725 bool IsNotUnderlined() const
1726 {
1727 return ((m_dwExtendedStyle & HLINK_NOTUNDERLINED) != 0);
1728 }
1729
1730 bool IsUnderlineHover() const
1731 {
1732 return ((m_dwExtendedStyle & HLINK_UNDERLINEHOVER) != 0);
1733 }
1734
1735 bool IsCommandButton() const
1736 {
1737 return ((m_dwExtendedStyle & HLINK_COMMANDBUTTON) != 0);
1738 }
1739
1740 bool IsNotifyButton() const
1741 {
1742 return ((m_dwExtendedStyle & HLINK_NOTIFYBUTTON) == HLINK_NOTIFY BUTTON);
1743 }
1744
1745 bool IsUsingTags() const
1746 {
1747 return ((m_dwExtendedStyle & HLINK_USETAGS) != 0);
1748 }
1749
1750 bool IsUsingTagsBold() const
1751 {
1752 return ((m_dwExtendedStyle & HLINK_USETAGSBOLD) == HLINK_USETAGS BOLD);
1753 }
1754
1755 bool IsUsingToolTip() const
1756 {
1757 return ((m_dwExtendedStyle & HLINK_NOTOOLTIP) == 0);
1758 }
1759
1760 static int _xttoi(const TCHAR* nptr)
1761 {
1762 #ifndef _ATL_MIN_CRT
1763 return _ttoi(nptr);
1764 #else // _ATL_MIN_CRT
1765 while(*nptr == _T(' ')) // skip spaces
1766 ++nptr;
1767
1768 int c = (int)(_TUCHAR)*nptr++;
1769 int sign = c; // save sign indication
1770 if (c == _T('-') || c == _T('+'))
1771 c = (int)(_TUCHAR)*nptr++; // skip sign
1772
1773 int total = 0;
1774 while((TCHAR)c >= _T('0') && (TCHAR)c <= _T('9'))
1775 {
1776 total = 10 * total + ((TCHAR)c - _T('0')); // accumula te digit
1777 c = (int)(_TUCHAR)*nptr++; // get next char
1778 }
1779
1780 // return result, negated if necessary
1781 return ((TCHAR)sign != _T('-')) ? total : -total;
1782 #endif // _ATL_MIN_CRT
1783 }
1784 };
1785
1786
1787 class CHyperLink : public CHyperLinkImpl<CHyperLink>
1788 {
1789 public:
1790 DECLARE_WND_CLASS(_T("WTL_HyperLink"))
1791 };
1792
1793
1794 ///////////////////////////////////////////////////////////////////////////////
1795 // CWaitCursor - displays a wait cursor
1796
1797 class CWaitCursor
1798 {
1799 public:
1800 // Data
1801 HCURSOR m_hWaitCursor;
1802 HCURSOR m_hOldCursor;
1803 bool m_bInUse;
1804
1805 // Constructor/destructor
1806 CWaitCursor(bool bSet = true, LPCTSTR lpstrCursor = IDC_WAIT, bool bSys = true) : m_hOldCursor(NULL), m_bInUse(false)
1807 {
1808 HINSTANCE hInstance = bSys ? NULL : ModuleHelper::GetResourceIns tance();
1809 m_hWaitCursor = ::LoadCursor(hInstance, lpstrCursor);
1810 ATLASSERT(m_hWaitCursor != NULL);
1811
1812 if(bSet)
1813 Set();
1814 }
1815
1816 ~CWaitCursor()
1817 {
1818 Restore();
1819 }
1820
1821 // Methods
1822 bool Set()
1823 {
1824 if(m_bInUse)
1825 return false;
1826 m_hOldCursor = ::SetCursor(m_hWaitCursor);
1827 m_bInUse = true;
1828 return true;
1829 }
1830
1831 bool Restore()
1832 {
1833 if(!m_bInUse)
1834 return false;
1835 ::SetCursor(m_hOldCursor);
1836 m_bInUse = false;
1837 return true;
1838 }
1839 };
1840
1841
1842 ///////////////////////////////////////////////////////////////////////////////
1843 // CCustomWaitCursor - for custom and animated cursors
1844
1845 class CCustomWaitCursor : public CWaitCursor
1846 {
1847 public:
1848 // Constructor/destructor
1849 CCustomWaitCursor(ATL::_U_STRINGorID cursor, bool bSet = true, HINSTANCE hInstance = NULL) :
1850 CWaitCursor(false, IDC_WAIT, true)
1851 {
1852 if(hInstance == NULL)
1853 hInstance = ModuleHelper::GetResourceInstance();
1854 m_hWaitCursor = (HCURSOR)::LoadImage(hInstance, cursor.m_lpstr, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE);
1855
1856 if(bSet)
1857 Set();
1858 }
1859
1860 ~CCustomWaitCursor()
1861 {
1862 Restore();
1863 #if !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLATFORM_P SPC) || defined(WIN32_PLATFORM_WFSP)))
1864 ::DestroyCursor(m_hWaitCursor);
1865 #endif // !defined(_WIN32_WCE) || ((_WIN32_WCE >= 0x400) && !(defined(WIN32_PLAT FORM_PSPC) || defined(WIN32_PLATFORM_WFSP)))
1866 }
1867 };
1868
1869
1870 ///////////////////////////////////////////////////////////////////////////////
1871 // CMultiPaneStatusBarCtrl - Status Bar with multiple panes
1872
1873 template <class T, class TBase = CStatusBarCtrl>
1874 class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl : public ATL::CWindowImpl< T, TB ase >
1875 {
1876 public:
1877 DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
1878
1879 // Data
1880 enum { m_cxPaneMargin = 3 };
1881
1882 int m_nPanes;
1883 int* m_pPane;
1884
1885 // Constructor/destructor
1886 CMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL)
1887 { }
1888
1889 ~CMultiPaneStatusBarCtrlImpl()
1890 {
1891 delete [] m_pPane;
1892 }
1893
1894 // Methods
1895 HWND Create(HWND hWndParent, LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = A TL_IDW_STATUS_BAR)
1896 {
1897 #if (_MSC_VER >= 1300)
1898 return ATL::CWindowImpl< T, TBase >::Create(hWndParent, rcDefaul t, lpstrText, dwStyle, 0, nID);
1899 #else // !(_MSC_VER >= 1300)
1900 typedef ATL::CWindowImpl< T, TBase > _baseClass;
1901 return _baseClass::Create(hWndParent, rcDefault, lpstrText, dwSt yle, 0, nID);
1902 #endif // !(_MSC_VER >= 1300)
1903 }
1904
1905 HWND Create(HWND hWndParent, UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD d wStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEG RIP, UINT nID = ATL_IDW_STATUS_BAR)
1906 {
1907 const int cchMax = 128; // max text length is 127 for status b ars (+1 for null)
1908 TCHAR szText[cchMax];
1909 szText[0] = 0;
1910 ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szTex t, cchMax);
1911 return Create(hWndParent, szText, dwStyle, nID);
1912 }
1913
1914 BOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true)
1915 {
1916 ATLASSERT(::IsWindow(m_hWnd));
1917 ATLASSERT(nPanes > 0);
1918
1919 m_nPanes = nPanes;
1920 delete [] m_pPane;
1921 m_pPane = NULL;
1922
1923 ATLTRY(m_pPane = new int[nPanes]);
1924 ATLASSERT(m_pPane != NULL);
1925 if(m_pPane == NULL)
1926 return FALSE;
1927
1928 CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;
1929 int* pPanesPos = buff.Allocate(nPanes);
1930 ATLASSERT(pPanesPos != NULL);
1931 if(pPanesPos == NULL)
1932 return FALSE;
1933
1934 SecureHelper::memcpy_x(m_pPane, nPanes * sizeof(int), pPanes, nP anes * sizeof(int));
1935
1936 // get status bar DC and set font
1937 CClientDC dc(m_hWnd);
1938 HFONT hOldFont = dc.SelectFont(GetFont());
1939
1940 // get status bar borders
1941 int arrBorders[3] = { 0 };
1942 GetBorders(arrBorders);
1943
1944 const int cchBuff = 128;
1945 TCHAR szBuff[cchBuff] = { 0 };
1946 SIZE size = { 0, 0 };
1947 int cxLeft = arrBorders[0];
1948
1949 // calculate right edge of each part
1950 for(int i = 0; i < nPanes; i++)
1951 {
1952 if(pPanes[i] == ID_DEFAULT_PANE)
1953 {
1954 // make very large, will be resized later
1955 pPanesPos[i] = INT_MAX / 2;
1956 }
1957 else
1958 {
1959 ::LoadString(ModuleHelper::GetResourceInstance() , pPanes[i], szBuff, cchBuff);
1960 dc.GetTextExtent(szBuff, lstrlen(szBuff), &size) ;
1961 T* pT = static_cast<T*>(this);
1962 pT;
1963 pPanesPos[i] = cxLeft + size.cx + arrBorders[2] + 2 * pT->m_cxPaneMargin;
1964 }
1965 cxLeft = pPanesPos[i];
1966 }
1967
1968 BOOL bRet = SetParts(nPanes, pPanesPos);
1969
1970 if(bRet && bSetText)
1971 {
1972 for(int i = 0; i < nPanes; i++)
1973 {
1974 if(pPanes[i] != ID_DEFAULT_PANE)
1975 {
1976 ::LoadString(ModuleHelper::GetResourceIn stance(), pPanes[i], szBuff, cchBuff);
1977 SetPaneText(m_pPane[i], szBuff);
1978 }
1979 }
1980 }
1981
1982 dc.SelectFont(hOldFont);
1983 return bRet;
1984 }
1985
1986 bool GetPaneTextLength(int nPaneID, int* pcchLength = NULL, int* pnType = NULL) const
1987 {
1988 ATLASSERT(::IsWindow(m_hWnd));
1989 int nIndex = GetPaneIndexFromID(nPaneID);
1990 if(nIndex == -1)
1991 return false;
1992
1993 int nLength = GetTextLength(nIndex, pnType);
1994 if(pcchLength != NULL)
1995 *pcchLength = nLength;
1996
1997 return true;
1998 }
1999
2000 BOOL GetPaneText(int nPaneID, LPTSTR lpstrText, int* pcchLength = NULL, int* pnType = NULL) const
2001 {
2002 ATLASSERT(::IsWindow(m_hWnd));
2003 int nIndex = GetPaneIndexFromID(nPaneID);
2004 if(nIndex == -1)
2005 return FALSE;
2006
2007 int nLength = GetText(nIndex, lpstrText, pnType);
2008 if(pcchLength != NULL)
2009 *pcchLength = nLength;
2010
2011 return TRUE;
2012 }
2013
2014 BOOL SetPaneText(int nPaneID, LPCTSTR lpstrText, int nType = 0)
2015 {
2016 ATLASSERT(::IsWindow(m_hWnd));
2017 int nIndex = GetPaneIndexFromID(nPaneID);
2018 if(nIndex == -1)
2019 return FALSE;
2020
2021 return SetText(nIndex, lpstrText, nType);
2022 }
2023
2024 BOOL GetPaneRect(int nPaneID, LPRECT lpRect) const
2025 {
2026 ATLASSERT(::IsWindow(m_hWnd));
2027 int nIndex = GetPaneIndexFromID(nPaneID);
2028 if(nIndex == -1)
2029 return FALSE;
2030
2031 return GetRect(nIndex, lpRect);
2032 }
2033
2034 BOOL SetPaneWidth(int nPaneID, int cxWidth)
2035 {
2036 ATLASSERT(::IsWindow(m_hWnd));
2037 ATLASSERT(nPaneID != ID_DEFAULT_PANE); // Can't resize this on e
2038 int nIndex = GetPaneIndexFromID(nPaneID);
2039 if(nIndex == -1)
2040 return FALSE;
2041
2042 // get pane positions
2043 CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;
2044 int* pPanesPos = buff.Allocate(m_nPanes);
2045 if(pPanesPos == NULL)
2046 return FALSE;
2047 GetParts(m_nPanes, pPanesPos);
2048 // calculate offset
2049 int cxPaneWidth = pPanesPos[nIndex] - ((nIndex == 0) ? 0 : pPane sPos[nIndex - 1]);
2050 int cxOff = cxWidth - cxPaneWidth;
2051 // find variable width pane
2052 int nDef = m_nPanes;
2053 for(int i = 0; i < m_nPanes; i++)
2054 {
2055 if(m_pPane[i] == ID_DEFAULT_PANE)
2056 {
2057 nDef = i;
2058 break;
2059 }
2060 }
2061 // resize
2062 if(nIndex < nDef) // before default pane
2063 {
2064 for(int i = nIndex; i < nDef; i++)
2065 pPanesPos[i] += cxOff;
2066
2067 }
2068 else // after default one
2069 {
2070 for(int i = nDef; i < nIndex; i++)
2071 pPanesPos[i] -= cxOff;
2072 }
2073 // set pane postions
2074 return SetParts(m_nPanes, pPanesPos);
2075 }
2076
2077 #if (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
2078 BOOL GetPaneTipText(int nPaneID, LPTSTR lpstrText, int nSize) const
2079 {
2080 ATLASSERT(::IsWindow(m_hWnd));
2081 int nIndex = GetPaneIndexFromID(nPaneID);
2082 if(nIndex == -1)
2083 return FALSE;
2084
2085 GetTipText(nIndex, lpstrText, nSize);
2086 return TRUE;
2087 }
2088
2089 BOOL SetPaneTipText(int nPaneID, LPCTSTR lpstrText)
2090 {
2091 ATLASSERT(::IsWindow(m_hWnd));
2092 int nIndex = GetPaneIndexFromID(nPaneID);
2093 if(nIndex == -1)
2094 return FALSE;
2095
2096 SetTipText(nIndex, lpstrText);
2097 return TRUE;
2098 }
2099 #endif // (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)
2100
2101 #if ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE) && ( _WIN32_WCE >= 0x0500))
2102 BOOL GetPaneIcon(int nPaneID, HICON& hIcon) const
2103 {
2104 ATLASSERT(::IsWindow(m_hWnd));
2105 int nIndex = GetPaneIndexFromID(nPaneID);
2106 if(nIndex == -1)
2107 return FALSE;
2108
2109 hIcon = GetIcon(nIndex);
2110 return TRUE;
2111 }
2112
2113 BOOL SetPaneIcon(int nPaneID, HICON hIcon)
2114 {
2115 ATLASSERT(::IsWindow(m_hWnd));
2116 int nIndex = GetPaneIndexFromID(nPaneID);
2117 if(nIndex == -1)
2118 return FALSE;
2119
2120 return SetIcon(nIndex, hIcon);
2121 }
2122 #endif // ((_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)) || (defined(_WIN32_WCE ) && (_WIN32_WCE >= 0x0500))
2123
2124 // Message map and handlers
2125 BEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl< T >)
2126 MESSAGE_HANDLER(WM_SIZE, OnSize)
2127 END_MSG_MAP()
2128
2129 LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled */)
2130 {
2131 LRESULT lRet = DefWindowProc(uMsg, wParam, lParam);
2132 if(wParam != SIZE_MINIMIZED && m_nPanes > 0)
2133 {
2134 T* pT = static_cast<T*>(this);
2135 pT->UpdatePanesLayout();
2136 }
2137 return lRet;
2138 }
2139
2140 // Implementation
2141 BOOL UpdatePanesLayout()
2142 {
2143 // get pane positions
2144 CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;
2145 int* pPanesPos = buff.Allocate(m_nPanes);
2146 ATLASSERT(pPanesPos != NULL);
2147 if(pPanesPos == NULL)
2148 return FALSE;
2149 int nRet = GetParts(m_nPanes, pPanesPos);
2150 ATLASSERT(nRet == m_nPanes);
2151 if(nRet != m_nPanes)
2152 return FALSE;
2153 // calculate offset
2154 RECT rcClient = { 0 };
2155 GetClientRect(&rcClient);
2156 int cxOff = rcClient.right - pPanesPos[m_nPanes - 1];
2157 #ifndef _WIN32_WCE
2158 // Move panes left if size grip box is present
2159 if((GetStyle() & SBARS_SIZEGRIP) != 0)
2160 cxOff -= ::GetSystemMetrics(SM_CXVSCROLL) + ::GetSystemM etrics(SM_CXEDGE);
2161 #endif // !_WIN32_WCE
2162 // find variable width pane
2163 int i;
2164 for(i = 0; i < m_nPanes; i++)
2165 {
2166 if(m_pPane[i] == ID_DEFAULT_PANE)
2167 break;
2168 }
2169 // resize all panes from the variable one to the right
2170 if((i < m_nPanes) && (pPanesPos[i] + cxOff) > ((i == 0) ? 0 : pP anesPos[i - 1]))
2171 {
2172 for(; i < m_nPanes; i++)
2173 pPanesPos[i] += cxOff;
2174 }
2175 // set pane postions
2176 return SetParts(m_nPanes, pPanesPos);
2177 }
2178
2179 int GetPaneIndexFromID(int nPaneID) const
2180 {
2181 for(int i = 0; i < m_nPanes; i++)
2182 {
2183 if(m_pPane[i] == nPaneID)
2184 return i;
2185 }
2186
2187 return -1; // not found
2188 }
2189 };
2190
2191 class CMultiPaneStatusBarCtrl : public CMultiPaneStatusBarCtrlImpl<CMultiPaneSta tusBarCtrl>
2192 {
2193 public:
2194 DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName())
2195 };
2196
2197
2198 ///////////////////////////////////////////////////////////////////////////////
2199 // CPaneContainer - provides header with title and close button for panes
2200
2201 // pane container extended styles
2202 #define PANECNT_NOCLOSEBUTTON 0x00000001
2203 #define PANECNT_VERTICAL 0x00000002
2204 #define PANECNT_FLATBORDER 0x00000004
2205 #define PANECNT_NOBORDER 0x00000008
2206
2207 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlW inTraits>
2208 class ATL_NO_VTABLE CPaneContainerImpl : public ATL::CWindowImpl< T, TBase, TWin Traits >, public CCustomDraw< T >
2209 {
2210 public:
2211 DECLARE_WND_CLASS_EX(NULL, 0, -1)
2212
2213 // Constants
2214 enum
2215 {
2216 m_cxyBorder = 2,
2217 m_cxyTextOffset = 4,
2218 m_cxyBtnOffset = 1,
2219
2220 m_cchTitle = 80,
2221
2222 m_cxImageTB = 13,
2223 m_cyImageTB = 11,
2224 m_cxyBtnAddTB = 7,
2225
2226 m_cxToolBar = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + m_cxyB tnOffset,
2227
2228 m_xBtnImageLeft = 6,
2229 m_yBtnImageTop = 5,
2230 m_xBtnImageRight = 12,
2231 m_yBtnImageBottom = 11,
2232
2233 m_nCloseBtnID = ID_PANE_CLOSE
2234 };
2235
2236 // Data members
2237 CToolBarCtrl m_tb;
2238 ATL::CWindow m_wndClient;
2239 int m_cxyHeader;
2240 TCHAR m_szTitle[m_cchTitle];
2241 DWORD m_dwExtendedStyle; // Pane container specific extended styles
2242
2243
2244 // Constructor
2245 CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0)
2246 {
2247 m_szTitle[0] = 0;
2248 }
2249
2250 // Attributes
2251 DWORD GetPaneContainerExtendedStyle() const
2252 {
2253 return m_dwExtendedStyle;
2254 }
2255
2256 DWORD SetPaneContainerExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
2257 {
2258 DWORD dwPrevStyle = m_dwExtendedStyle;
2259 if(dwMask == 0)
2260 m_dwExtendedStyle = dwExtendedStyle;
2261 else
2262 m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwE xtendedStyle & dwMask);
2263 if(m_hWnd != NULL)
2264 {
2265 T* pT = static_cast<T*>(this);
2266 bool bUpdate = false;
2267
2268 if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) != 0) && ((m_d wExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)) // add close button
2269 {
2270 pT->CreateCloseButton();
2271 bUpdate = true;
2272 }
2273 else if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) == 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) != 0)) // remove close button
2274 {
2275 pT->DestroyCloseButton();
2276 bUpdate = true;
2277 }
2278
2279 if((dwPrevStyle & PANECNT_VERTICAL) != (m_dwExtendedStyl e & PANECNT_VERTICAL)) // change orientation
2280 {
2281 pT->CalcSize();
2282 bUpdate = true;
2283 }
2284
2285 if((dwPrevStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER )) !=
2286 (m_dwExtendedStyle & (PANECNT_FLATBORDER | PANECNT_NO BORDER))) // change border
2287 {
2288 bUpdate = true;
2289 }
2290
2291 if(bUpdate)
2292 pT->UpdateLayout();
2293 }
2294 return dwPrevStyle;
2295 }
2296
2297 HWND GetClient() const
2298 {
2299 return m_wndClient;
2300 }
2301
2302 HWND SetClient(HWND hWndClient)
2303 {
2304 HWND hWndOldClient = m_wndClient;
2305 m_wndClient = hWndClient;
2306 if(m_hWnd != NULL)
2307 {
2308 T* pT = static_cast<T*>(this);
2309 pT->UpdateLayout();
2310 }
2311 return hWndOldClient;
2312 }
2313
2314 BOOL GetTitle(LPTSTR lpstrTitle, int cchLength) const
2315 {
2316 ATLASSERT(lpstrTitle != NULL);
2317
2318 errno_t nRet = SecureHelper::strncpy_x(lpstrTitle, cchLength, m_ szTitle, _TRUNCATE);
2319
2320 return (nRet == 0 || nRet == STRUNCATE);
2321 }
2322
2323 BOOL SetTitle(LPCTSTR lpstrTitle)
2324 {
2325 ATLASSERT(lpstrTitle != NULL);
2326
2327 errno_t nRet = SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lp strTitle, _TRUNCATE);
2328 bool bRet = (nRet == 0 || nRet == STRUNCATE);
2329 if(bRet && m_hWnd != NULL)
2330 {
2331 T* pT = static_cast<T*>(this);
2332 pT->UpdateLayout();
2333 }
2334
2335 return bRet;
2336 }
2337
2338 int GetTitleLength() const
2339 {
2340 return lstrlen(m_szTitle);
2341 }
2342
2343 // Methods
2344 HWND Create(HWND hWndParent, LPCTSTR lpstrTitle = NULL, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
2345 DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
2346 {
2347 if(lpstrTitle != NULL)
2348 SecureHelper::strncpy_x(m_szTitle, m_cchTitle, lpstrTitl e, _TRUNCATE);
2349 #if (_MSC_VER >= 1300)
2350 return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndPare nt, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
2351 #else // !(_MSC_VER >= 1300)
2352 typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass;
2353 return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
2354 #endif // !(_MSC_VER >= 1300)
2355 }
2356
2357 HWND Create(HWND hWndParent, UINT uTitleID, DWORD dwStyle = WS_CHILD | W S_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
2358 DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
2359 {
2360 if(uTitleID != 0U)
2361 ::LoadString(ModuleHelper::GetResourceInstance(), uTitle ID, m_szTitle, m_cchTitle);
2362 #if (_MSC_VER >= 1300)
2363 return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndPare nt, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
2364 #else // !(_MSC_VER >= 1300)
2365 typedef ATL::CWindowImpl< T, TBase, TWinTraits > _baseClass;
2366 return _baseClass::Create(hWndParent, rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
2367 #endif // !(_MSC_VER >= 1300)
2368 }
2369
2370 BOOL EnableCloseButton(BOOL bEnable)
2371 {
2372 ATLASSERT(::IsWindow(m_hWnd));
2373 T* pT = static_cast<T*>(this);
2374 pT; // avoid level 4 warning
2375 return (m_tb.m_hWnd != NULL) ? m_tb.EnableButton(pT->m_nCloseBtn ID, bEnable) : FALSE;
2376 }
2377
2378 void UpdateLayout()
2379 {
2380 RECT rcClient = { 0 };
2381 GetClientRect(&rcClient);
2382 T* pT = static_cast<T*>(this);
2383 pT->UpdateLayout(rcClient.right, rcClient.bottom);
2384 }
2385
2386 // Message map and handlers
2387 BEGIN_MSG_MAP(CPaneContainerImpl)
2388 MESSAGE_HANDLER(WM_CREATE, OnCreate)
2389 MESSAGE_HANDLER(WM_SIZE, OnSize)
2390 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
2391 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
2392 MESSAGE_HANDLER(WM_PAINT, OnPaint)
2393 #ifndef _WIN32_WCE
2394 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
2395 #endif // !_WIN32_WCE
2396 MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
2397 MESSAGE_HANDLER(WM_COMMAND, OnCommand)
2398 FORWARD_NOTIFICATIONS()
2399 END_MSG_MAP()
2400
2401 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BO OL& /*bHandled*/)
2402 {
2403 T* pT = static_cast<T*>(this);
2404 pT->CalcSize();
2405
2406 if((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)
2407 pT->CreateCloseButton();
2408
2409 return 0;
2410 }
2411
2412 LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /* bHandled*/)
2413 {
2414 T* pT = static_cast<T*>(this);
2415 pT->UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
2416 return 0;
2417 }
2418
2419 LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
2420 {
2421 if(m_wndClient.m_hWnd != NULL)
2422 m_wndClient.SetFocus();
2423 return 0;
2424 }
2425
2426 LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lPa ram*/, BOOL& /*bHandled*/)
2427 {
2428 return 1; // no background needed
2429 }
2430
2431 LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& / *bHandled*/)
2432 {
2433 T* pT = static_cast<T*>(this);
2434 if(wParam != NULL)
2435 {
2436 pT->DrawPaneTitle((HDC)wParam);
2437
2438 if(m_wndClient.m_hWnd == NULL) // no client window
2439 pT->DrawPane((HDC)wParam);
2440 }
2441 else
2442 {
2443 CPaintDC dc(m_hWnd);
2444 pT->DrawPaneTitle(dc.m_hDC);
2445
2446 if(m_wndClient.m_hWnd == NULL) // no client window
2447 pT->DrawPane(dc.m_hDC);
2448 }
2449
2450 return 0;
2451 }
2452
2453 LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
2454 {
2455 if(m_tb.m_hWnd == NULL)
2456 {
2457 bHandled = FALSE;
2458 return 1;
2459 }
2460
2461 T* pT = static_cast<T*>(this);
2462 pT;
2463 LPNMHDR lpnmh = (LPNMHDR)lParam;
2464 LRESULT lRet = 0;
2465
2466 // pass toolbar custom draw notifications to the base class
2467 if(lpnmh->code == NM_CUSTOMDRAW && lpnmh->hwndFrom == m_tb.m_hWn d)
2468 lRet = CCustomDraw< T >::OnCustomDraw(0, lpnmh, bHandled );
2469 #ifndef _WIN32_WCE
2470 // tooltip notifications come with the tooltip window handle and button ID,
2471 // pass them to the parent if we don't handle them
2472 else if(lpnmh->code == TTN_GETDISPINFO && lpnmh->idFrom == pT->m _nCloseBtnID)
2473 bHandled = pT->GetToolTipText(lpnmh);
2474 #endif // !_WIN32_WCE
2475 // only let notifications not from the toolbar go to the parent
2476 else if(lpnmh->hwndFrom != m_tb.m_hWnd && lpnmh->idFrom != pT->m _nCloseBtnID)
2477 bHandled = FALSE;
2478
2479 return lRet;
2480 }
2481
2482 LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHa ndled)
2483 {
2484 // if command comes from the close button, substitute HWND of th e pane container instead
2485 if(m_tb.m_hWnd != NULL && (HWND)lParam == m_tb.m_hWnd)
2486 return ::SendMessage(GetParent(), WM_COMMAND, wParam, (L PARAM)m_hWnd);
2487
2488 bHandled = FALSE;
2489 return 1;
2490 }
2491
2492 // Custom draw overrides
2493 DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
2494 {
2495 return CDRF_NOTIFYITEMDRAW; // we need per-item notifications
2496 }
2497
2498 DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)
2499 {
2500 CDCHandle dc = lpNMCustomDraw->hdc;
2501 #if (_WIN32_IE >= 0x0400)
2502 RECT& rc = lpNMCustomDraw->rc;
2503 #else // !(_WIN32_IE >= 0x0400)
2504 RECT rc;
2505 m_tb.GetItemRect(0, &rc);
2506 #endif // !(_WIN32_IE >= 0x0400)
2507
2508 dc.FillRect(&rc, COLOR_3DFACE);
2509
2510 return CDRF_NOTIFYPOSTPAINT;
2511 }
2512
2513 DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)
2514 {
2515 CDCHandle dc = lpNMCustomDraw->hdc;
2516 #if (_WIN32_IE >= 0x0400)
2517 RECT& rc = lpNMCustomDraw->rc;
2518 #else // !(_WIN32_IE >= 0x0400)
2519 RECT rc = { 0 };
2520 m_tb.GetItemRect(0, &rc);
2521 #endif // !(_WIN32_IE >= 0x0400)
2522
2523 RECT rcImage = { m_xBtnImageLeft, m_yBtnImageTop, m_xBtnImageRig ht + 1, m_yBtnImageBottom + 1 };
2524 ::OffsetRect(&rcImage, rc.left, rc.top);
2525 T* pT = static_cast<T*>(this);
2526
2527 if((lpNMCustomDraw->uItemState & CDIS_DISABLED) != 0)
2528 {
2529 RECT rcShadow = rcImage;
2530 ::OffsetRect(&rcShadow, 1, 1);
2531 CPen pen1;
2532 pen1.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGH T));
2533 pT->DrawButtonImage(dc, rcShadow, pen1);
2534 CPen pen2;
2535 pen2.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW ));
2536 pT->DrawButtonImage(dc, rcImage, pen2);
2537 }
2538 else
2539 {
2540 if((lpNMCustomDraw->uItemState & CDIS_SELECTED) != 0)
2541 ::OffsetRect(&rcImage, 1, 1);
2542 CPen pen;
2543 pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT)) ;
2544 pT->DrawButtonImage(dc, rcImage, pen);
2545 }
2546
2547 return CDRF_DODEFAULT; // continue with the default item paint ing
2548 }
2549
2550 // Implementation - overrideable methods
2551 void UpdateLayout(int cxWidth, int cyHeight)
2552 {
2553 ATLASSERT(::IsWindow(m_hWnd));
2554 RECT rect = { 0 };
2555
2556 if(IsVertical())
2557 {
2558 ::SetRect(&rect, 0, 0, m_cxyHeader, cyHeight);
2559 if(m_tb.m_hWnd != NULL)
2560 m_tb.SetWindowPos(NULL, m_cxyBorder, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
2561
2562 if(m_wndClient.m_hWnd != NULL)
2563 m_wndClient.SetWindowPos(NULL, m_cxyHeader, 0, c xWidth - m_cxyHeader, cyHeight, SWP_NOZORDER);
2564 else
2565 rect.right = cxWidth;
2566 }
2567 else
2568 {
2569 ::SetRect(&rect, 0, 0, cxWidth, m_cxyHeader);
2570 if(m_tb.m_hWnd != NULL)
2571 m_tb.SetWindowPos(NULL, rect.right - m_cxToolBar , m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE );
2572
2573 if(m_wndClient.m_hWnd != NULL)
2574 m_wndClient.SetWindowPos(NULL, 0, m_cxyHeader, c xWidth, cyHeight - m_cxyHeader, SWP_NOZORDER);
2575 else
2576 rect.bottom = cyHeight;
2577 }
2578
2579 InvalidateRect(&rect);
2580 }
2581
2582 void CreateCloseButton()
2583 {
2584 ATLASSERT(m_tb.m_hWnd == NULL);
2585 // create toolbar for the "x" button
2586 m_tb.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_ CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIG N | CCS_NOMOVEY | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT, 0);
2587 ATLASSERT(m_tb.IsWindow());
2588
2589 if(m_tb.m_hWnd != NULL)
2590 {
2591 T* pT = static_cast<T*>(this);
2592 pT; // avoid level 4 warning
2593
2594 m_tb.SetButtonStructSize();
2595
2596 TBBUTTON tbbtn = { 0 };
2597 tbbtn.idCommand = pT->m_nCloseBtnID;
2598 tbbtn.fsState = TBSTATE_ENABLED;
2599 tbbtn.fsStyle = TBSTYLE_BUTTON;
2600 m_tb.AddButtons(1, &tbbtn);
2601
2602 m_tb.SetBitmapSize(m_cxImageTB, m_cyImageTB);
2603 m_tb.SetButtonSize(m_cxImageTB + m_cxyBtnAddTB, m_cyImag eTB + m_cxyBtnAddTB);
2604
2605 if(IsVertical())
2606 m_tb.SetWindowPos(NULL, m_cxyBorder + m_cxyBtnOf fset, m_cxyBorder + m_cxyBtnOffset, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m _cxyBtnAddTB, SWP_NOZORDER | SWP_NOACTIVATE);
2607 else
2608 m_tb.SetWindowPos(NULL, 0, 0, m_cxImageTB + m_cx yBtnAddTB, m_cyImageTB + m_cxyBtnAddTB, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVA TE);
2609 }
2610 }
2611
2612 void DestroyCloseButton()
2613 {
2614 if(m_tb.m_hWnd != NULL)
2615 m_tb.DestroyWindow();
2616 }
2617
2618 void CalcSize()
2619 {
2620 T* pT = static_cast<T*>(this);
2621 CFontHandle font = pT->GetTitleFont();
2622 LOGFONT lf = { 0 };
2623 font.GetLogFont(lf);
2624 if(IsVertical())
2625 {
2626 m_cxyHeader = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder;
2627 }
2628 else
2629 {
2630 int cyFont = abs(lf.lfHeight) + m_cxyBorder + 2 * m_cxyT extOffset;
2631 int cyBtn = m_cyImageTB + m_cxyBtnAddTB + m_cxyBorder + 2 * m_cxyBtnOffset;
2632 m_cxyHeader = __max(cyFont, cyBtn);
2633 }
2634 }
2635
2636 HFONT GetTitleFont() const
2637 {
2638 return AtlGetDefaultGuiFont();
2639 }
2640
2641 #ifndef _WIN32_WCE
2642 BOOL GetToolTipText(LPNMHDR /*lpnmh*/)
2643 {
2644 return FALSE;
2645 }
2646 #endif // !_WIN32_WCE
2647
2648 void DrawPaneTitle(CDCHandle dc)
2649 {
2650 RECT rect = { 0 };
2651 GetClientRect(&rect);
2652
2653 UINT uBorder = BF_LEFT | BF_TOP | BF_ADJUST;
2654 if(IsVertical())
2655 {
2656 rect.right = rect.left + m_cxyHeader;
2657 uBorder |= BF_BOTTOM;
2658 }
2659 else
2660 {
2661 rect.bottom = rect.top + m_cxyHeader;
2662 uBorder |= BF_RIGHT;
2663 }
2664
2665 if((m_dwExtendedStyle & PANECNT_NOBORDER) == 0)
2666 {
2667 if((m_dwExtendedStyle & PANECNT_FLATBORDER) != 0)
2668 uBorder |= BF_FLAT;
2669 dc.DrawEdge(&rect, EDGE_ETCHED, uBorder);
2670 }
2671 dc.FillRect(&rect, COLOR_3DFACE);
2672
2673 if(!IsVertical()) // draw title only for horizontal pane conta iner
2674 {
2675 dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
2676 dc.SetBkMode(TRANSPARENT);
2677 T* pT = static_cast<T*>(this);
2678 HFONT hFontOld = dc.SelectFont(pT->GetTitleFont());
2679 rect.left += m_cxyTextOffset;
2680 rect.right -= m_cxyTextOffset;
2681 if(m_tb.m_hWnd != NULL)
2682 rect.right -= m_cxToolBar;;
2683 #ifndef _WIN32_WCE
2684 dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELIN E | DT_VCENTER | DT_END_ELLIPSIS);
2685 #else // CE specific
2686 dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELIN E | DT_VCENTER);
2687 #endif // _WIN32_WCE
2688 dc.SelectFont(hFontOld);
2689 }
2690 }
2691
2692 // called only if pane is empty
2693 void DrawPane(CDCHandle dc)
2694 {
2695 RECT rect = { 0 };
2696 GetClientRect(&rect);
2697 if(IsVertical())
2698 rect.left += m_cxyHeader;
2699 else
2700 rect.top += m_cxyHeader;
2701 if((GetExStyle() & WS_EX_CLIENTEDGE) == 0)
2702 dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
2703 dc.FillRect(&rect, COLOR_APPWORKSPACE);
2704 }
2705
2706 // drawing helper - draws "x" button image
2707 void DrawButtonImage(CDCHandle dc, RECT& rcImage, HPEN hPen)
2708 {
2709 #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 400)
2710 HPEN hPenOld = dc.SelectPen(hPen);
2711
2712 dc.MoveTo(rcImage.left, rcImage.top);
2713 dc.LineTo(rcImage.right, rcImage.bottom);
2714 dc.MoveTo(rcImage.left + 1, rcImage.top);
2715 dc.LineTo(rcImage.right + 1, rcImage.bottom);
2716
2717 dc.MoveTo(rcImage.left, rcImage.bottom - 1);
2718 dc.LineTo(rcImage.right, rcImage.top - 1);
2719 dc.MoveTo(rcImage.left + 1, rcImage.bottom - 1);
2720 dc.LineTo(rcImage.right + 1, rcImage.top - 1);
2721
2722 dc.SelectPen(hPenOld);
2723 #else // (_WIN32_WCE < 400)
2724 rcImage;
2725 hPen;
2726 // no support for the "x" button image
2727 #endif // (_WIN32_WCE < 400)
2728 }
2729
2730 bool IsVertical() const
2731 {
2732 return ((m_dwExtendedStyle & PANECNT_VERTICAL) != 0);
2733 }
2734 };
2735
2736 class CPaneContainer : public CPaneContainerImpl<CPaneContainer>
2737 {
2738 public:
2739 DECLARE_WND_CLASS_EX(_T("WTL_PaneContainer"), 0, -1)
2740 };
2741
2742
2743 ///////////////////////////////////////////////////////////////////////////////
2744 // CSortListViewCtrl - implements sorting for a listview control
2745
2746 // sort listview extended styles
2747 #define SORTLV_USESHELLBITMAPS 0x00000001
2748
2749 // Notification sent to parent when sort column is changed by user clicking head er.
2750 #define SLVN_SORTCHANGED LVN_LAST
2751
2752 // A LPNMSORTLISTVIEW is sent with the SLVN_SORTCHANGED notification
2753 typedef struct tagNMSORTLISTVIEW
2754 {
2755 NMHDR hdr;
2756 int iNewSortColumn;
2757 int iOldSortColumn;
2758 } NMSORTLISTVIEW, *LPNMSORTLISTVIEW;
2759
2760 // Column sort types. Can be set on a per-column basis with the SetColumnSortTyp e method.
2761 enum
2762 {
2763 LVCOLSORT_NONE,
2764 LVCOLSORT_TEXT, // default
2765 LVCOLSORT_TEXTNOCASE,
2766 LVCOLSORT_LONG,
2767 LVCOLSORT_DOUBLE,
2768 LVCOLSORT_DECIMAL,
2769 LVCOLSORT_DATETIME,
2770 LVCOLSORT_DATE,
2771 LVCOLSORT_TIME,
2772 LVCOLSORT_CUSTOM,
2773 LVCOLSORT_LAST = LVCOLSORT_CUSTOM
2774 };
2775
2776
2777 template <class T>
2778 class CSortListViewImpl
2779 {
2780 public:
2781 enum
2782 {
2783 m_cchCmpTextMax = 32, // overrideable
2784 m_cxSortImage = 16,
2785 m_cySortImage = 15,
2786 m_cxSortArrow = 11,
2787 m_cySortArrow = 6,
2788 m_iSortUp = 0, // index of sort bitmaps
2789 m_iSortDown = 1,
2790 m_nShellSortUpID = 133
2791 };
2792
2793 // passed to LVCompare functions as lParam1 and lParam2
2794 struct LVCompareParam
2795 {
2796 int iItem;
2797 DWORD_PTR dwItemData;
2798 union
2799 {
2800 long lValue;
2801 double dblValue;
2802 DECIMAL decValue;
2803 LPCTSTR pszValue;
2804 };
2805 };
2806
2807 // passed to LVCompare functions as the lParamSort parameter
2808 struct LVSortInfo
2809 {
2810 T* pT;
2811 int iSortCol;
2812 bool bDescending;
2813 };
2814
2815 bool m_bSortDescending;
2816 bool m_bCommCtrl6;
2817 int m_iSortColumn;
2818 CBitmap m_bmSort[2];
2819 int m_fmtOldSortCol;
2820 HBITMAP m_hbmOldSortCol;
2821 DWORD m_dwSortLVExtendedStyle;
2822 ATL::CSimpleArray<WORD> m_arrColSortType;
2823 bool m_bUseWaitCursor;
2824
2825 CSortListViewImpl() :
2826 m_bSortDescending(false),
2827 m_bCommCtrl6(false),
2828 m_iSortColumn(-1),
2829 m_fmtOldSortCol(0),
2830 m_hbmOldSortCol(NULL),
2831 m_dwSortLVExtendedStyle(SORTLV_USESHELLBITMAPS),
2832 m_bUseWaitCursor(true)
2833 {
2834 #ifndef _WIN32_WCE
2835 DWORD dwMajor = 0;
2836 DWORD dwMinor = 0;
2837 HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
2838 m_bCommCtrl6 = SUCCEEDED(hRet) && dwMajor >= 6;
2839 #endif // !_WIN32_WCE
2840 }
2841
2842 // Attributes
2843 void SetSortColumn(int iCol)
2844 {
2845 T* pT = static_cast<T*>(this);
2846 ATLASSERT(::IsWindow(pT->m_hWnd));
2847 CHeaderCtrl header = pT->GetHeader();
2848 ATLASSERT(header.m_hWnd != NULL);
2849 ATLASSERT(iCol >= -1 && iCol < m_arrColSortType.GetSize());
2850
2851 int iOldSortCol = m_iSortColumn;
2852 m_iSortColumn = iCol;
2853 if(m_bCommCtrl6)
2854 {
2855 #ifndef HDF_SORTUP
2856 const int HDF_SORTUP = 0x0400;
2857 #endif // HDF_SORTUP
2858 #ifndef HDF_SORTDOWN
2859 const int HDF_SORTDOWN = 0x0200;
2860 #endif // HDF_SORTDOWN
2861 const int nMask = HDF_SORTUP | HDF_SORTDOWN;
2862 HDITEM hditem = { HDI_FORMAT };
2863 if(iOldSortCol != iCol && iOldSortCol >= 0 && header.Get Item(iOldSortCol, &hditem))
2864 {
2865 hditem.fmt &= ~nMask;
2866 header.SetItem(iOldSortCol, &hditem);
2867 }
2868 if(iCol >= 0 && header.GetItem(iCol, &hditem))
2869 {
2870 hditem.fmt &= ~nMask;
2871 hditem.fmt |= m_bSortDescending ? HDF_SORTDOWN : HDF_SORTUP;
2872 header.SetItem(iCol, &hditem);
2873 }
2874 return;
2875 }
2876
2877 if(m_bmSort[m_iSortUp].IsNull())
2878 pT->CreateSortBitmaps();
2879
2880 // restore previous sort column's bitmap, if any, and format
2881 HDITEM hditem = { HDI_BITMAP | HDI_FORMAT };
2882 if(iOldSortCol != iCol && iOldSortCol >= 0)
2883 {
2884 hditem.hbm = m_hbmOldSortCol;
2885 hditem.fmt = m_fmtOldSortCol;
2886 header.SetItem(iOldSortCol, &hditem);
2887 }
2888
2889 // save new sort column's bitmap and format, and add our sort bi tmap
2890 if(iCol >= 0 && header.GetItem(iCol, &hditem))
2891 {
2892 if(iOldSortCol != iCol)
2893 {
2894 m_fmtOldSortCol = hditem.fmt;
2895 m_hbmOldSortCol = hditem.hbm;
2896 }
2897 hditem.fmt &= ~HDF_IMAGE;
2898 hditem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT;
2899 int i = m_bSortDescending ? m_iSortDown : m_iSortUp;
2900 hditem.hbm = m_bmSort[i];
2901 header.SetItem(iCol, &hditem);
2902 }
2903 }
2904
2905 int GetSortColumn() const
2906 {
2907 return m_iSortColumn;
2908 }
2909
2910 void SetColumnSortType(int iCol, WORD wType)
2911 {
2912 ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize());
2913 ATLASSERT(wType >= LVCOLSORT_NONE && wType <= LVCOLSORT_LAST);
2914 m_arrColSortType[iCol] = wType;
2915 }
2916
2917 WORD GetColumnSortType(int iCol) const
2918 {
2919 ATLASSERT((iCol >= 0) && iCol < m_arrColSortType.GetSize());
2920 return m_arrColSortType[iCol];
2921 }
2922
2923 int GetColumnCount() const
2924 {
2925 const T* pT = static_cast<const T*>(this);
2926 ATLASSERT(::IsWindow(pT->m_hWnd));
2927 CHeaderCtrl header = pT->GetHeader();
2928 return header.m_hWnd != NULL ? header.GetItemCount() : 0;
2929 }
2930
2931 bool IsSortDescending() const
2932 {
2933 return m_bSortDescending;
2934 }
2935
2936 DWORD GetSortListViewExtendedStyle() const
2937 {
2938 return m_dwSortLVExtendedStyle;
2939 }
2940
2941 DWORD SetSortListViewExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
2942 {
2943 DWORD dwPrevStyle = m_dwSortLVExtendedStyle;
2944 if(dwMask == 0)
2945 m_dwSortLVExtendedStyle = dwExtendedStyle;
2946 else
2947 m_dwSortLVExtendedStyle = (m_dwSortLVExtendedStyle & ~dw Mask) | (dwExtendedStyle & dwMask);
2948 return dwPrevStyle;
2949 }
2950
2951 // Operations
2952 bool DoSortItems(int iCol, bool bDescending = false)
2953 {
2954 T* pT = static_cast<T*>(this);
2955 ATLASSERT(::IsWindow(pT->m_hWnd));
2956 ATLASSERT(iCol >= 0 && iCol < m_arrColSortType.GetSize());
2957
2958 WORD wType = m_arrColSortType[iCol];
2959 if(wType == LVCOLSORT_NONE)
2960 return false;
2961
2962 int nCount = pT->GetItemCount();
2963 if(nCount < 2)
2964 {
2965 m_bSortDescending = bDescending;
2966 SetSortColumn(iCol);
2967 return true;
2968 }
2969
2970 CWaitCursor waitCursor(false);
2971 if(m_bUseWaitCursor)
2972 waitCursor.Set();
2973
2974 LVCompareParam* pParam = NULL;
2975 ATLTRY(pParam = new LVCompareParam[nCount]);
2976 PFNLVCOMPARE pFunc = NULL;
2977 TCHAR pszTemp[pT->m_cchCmpTextMax];
2978 bool bStrValue = false;
2979
2980 switch(wType)
2981 {
2982 case LVCOLSORT_TEXT:
2983 pFunc = (PFNLVCOMPARE)pT->LVCompareText;
2984 case LVCOLSORT_TEXTNOCASE:
2985 if(pFunc == NULL)
2986 pFunc = (PFNLVCOMPARE)pT->LVCompareTextNoCase;
2987 case LVCOLSORT_CUSTOM:
2988 {
2989 if(pFunc == NULL)
2990 pFunc = (PFNLVCOMPARE)pT->LVCompareCusto m;
2991
2992 for(int i = 0; i < nCount; i++)
2993 {
2994 pParam[i].iItem = i;
2995 pParam[i].dwItemData = pT->GetItemData(i );
2996 pParam[i].pszValue = new TCHAR[pT->m_cch CmpTextMax];
2997 pT->GetItemText(i, iCol, (LPTSTR)pParam[ i].pszValue, pT->m_cchCmpTextMax);
2998 pT->SetItemData(i, (DWORD_PTR)&pParam[i] );
2999 }
3000 bStrValue = true;
3001 }
3002 break;
3003 case LVCOLSORT_LONG:
3004 {
3005 pFunc = (PFNLVCOMPARE)pT->LVCompareLong;
3006 for(int i = 0; i < nCount; i++)
3007 {
3008 pParam[i].iItem = i;
3009 pParam[i].dwItemData = pT->GetItemData(i );
3010 pT->GetItemText(i, iCol, pszTemp, pT->m_ cchCmpTextMax);
3011 pParam[i].lValue = pT->StrToLong(pszTemp );
3012 pT->SetItemData(i, (DWORD_PTR)&pParam[i] );
3013 }
3014 }
3015 break;
3016 case LVCOLSORT_DOUBLE:
3017 {
3018 pFunc = (PFNLVCOMPARE)pT->LVCompareDouble;
3019 for(int i = 0; i < nCount; i++)
3020 {
3021 pParam[i].iItem = i;
3022 pParam[i].dwItemData = pT->GetItemData(i );
3023 pT->GetItemText(i, iCol, pszTemp, pT->m_ cchCmpTextMax);
3024 pParam[i].dblValue = pT->StrToDouble(psz Temp);
3025 pT->SetItemData(i, (DWORD_PTR)&pParam[i] );
3026 }
3027 }
3028 break;
3029 case LVCOLSORT_DECIMAL:
3030 {
3031 pFunc = (PFNLVCOMPARE)pT->LVCompareDecimal;
3032 for(int i = 0; i < nCount; i++)
3033 {
3034 pParam[i].iItem = i;
3035 pParam[i].dwItemData = pT->GetItemData(i );
3036 pT->GetItemText(i, iCol, pszTemp, pT->m_ cchCmpTextMax);
3037 pT->StrToDecimal(pszTemp, &pParam[i].dec Value);
3038 pT->SetItemData(i, (DWORD_PTR)&pParam[i] );
3039 }
3040 }
3041 break;
3042 case LVCOLSORT_DATETIME:
3043 case LVCOLSORT_DATE:
3044 case LVCOLSORT_TIME:
3045 {
3046 pFunc = (PFNLVCOMPARE)pT->LVCompareDouble;
3047 DWORD dwFlags = LOCALE_NOUSEROVERRIDE;
3048 if(wType == LVCOLSORT_DATE)
3049 dwFlags |= VAR_DATEVALUEONLY;
3050 else if(wType == LVCOLSORT_TIME)
3051 dwFlags |= VAR_TIMEVALUEONLY;
3052 for(int i = 0; i < nCount; i++)
3053 {
3054 pParam[i].iItem = i;
3055 pParam[i].dwItemData = pT->GetItemData(i );
3056 pT->GetItemText(i, iCol, pszTemp, pT->m_ cchCmpTextMax);
3057 pParam[i].dblValue = pT->DateStrToDouble (pszTemp, dwFlags);
3058 pT->SetItemData(i, (DWORD_PTR)&pParam[i] );
3059 }
3060 }
3061 break;
3062 default:
3063 ATLTRACE2(atlTraceUI, 0, _T("Unknown value for sort type in CSortListViewImpl::DoSortItems()\n"));
3064 break;
3065 } // switch(wType)
3066
3067 ATLASSERT(pFunc != NULL);
3068 LVSortInfo lvsi = { pT, iCol, bDescending };
3069 bool bRet = ((BOOL)pT->DefWindowProc(LVM_SORTITEMS, (WPARAM)&lvs i, (LPARAM)pFunc) != FALSE);
3070 for(int i = 0; i < nCount; i++)
3071 {
3072 DWORD_PTR dwItemData = pT->GetItemData(i);
3073 LVCompareParam* p = (LVCompareParam*)dwItemData;
3074 ATLASSERT(p != NULL);
3075 if(bStrValue)
3076 delete [] (TCHAR*)p->pszValue;
3077 pT->SetItemData(i, p->dwItemData);
3078 }
3079 delete [] pParam;
3080
3081 if(bRet)
3082 {
3083 m_bSortDescending = bDescending;
3084 SetSortColumn(iCol);
3085 }
3086
3087 if(m_bUseWaitCursor)
3088 waitCursor.Restore();
3089
3090 return bRet;
3091 }
3092
3093 void CreateSortBitmaps()
3094 {
3095 if((m_dwSortLVExtendedStyle & SORTLV_USESHELLBITMAPS) != 0)
3096 {
3097 bool bFree = false;
3098 LPCTSTR pszModule = _T("shell32.dll");
3099 HINSTANCE hShell = ::GetModuleHandle(pszModule);
3100
3101 if (hShell == NULL)
3102 {
3103 hShell = ::LoadLibrary(pszModule);
3104 bFree = true;
3105 }
3106
3107 if (hShell != NULL)
3108 {
3109 bool bSuccess = true;
3110 for(int i = m_iSortUp; i <= m_iSortDown; i++)
3111 {
3112 if(!m_bmSort[i].IsNull())
3113 m_bmSort[i].DeleteObject();
3114 m_bmSort[i] = (HBITMAP)::LoadImage(hShel l, MAKEINTRESOURCE(m_nShellSortUpID + i),
3115 #ifndef _WIN32_WCE
3116 IMAGE_BITMAP, 0, 0, LR_LOADMAP3D COLORS);
3117 #else // CE specific
3118 IMAGE_BITMAP, 0, 0, 0);
3119 #endif // _WIN32_WCE
3120 if(m_bmSort[i].IsNull())
3121 {
3122 bSuccess = false;
3123 break;
3124 }
3125 }
3126 if(bFree)
3127 ::FreeLibrary(hShell);
3128 if(bSuccess)
3129 return;
3130 }
3131 }
3132
3133 T* pT = static_cast<T*>(this);
3134 for(int i = m_iSortUp; i <= m_iSortDown; i++)
3135 {
3136 if(!m_bmSort[i].IsNull())
3137 m_bmSort[i].DeleteObject();
3138
3139 CDC dcMem;
3140 CClientDC dc(::GetDesktopWindow());
3141 dcMem.CreateCompatibleDC(dc.m_hDC);
3142 m_bmSort[i].CreateCompatibleBitmap(dc.m_hDC, m_cxSortIma ge, m_cySortImage);
3143 HBITMAP hbmOld = dcMem.SelectBitmap(m_bmSort[i]);
3144 RECT rc = {0,0,m_cxSortImage, m_cySortImage};
3145 pT->DrawSortBitmap(dcMem.m_hDC, i, &rc);
3146 dcMem.SelectBitmap(hbmOld);
3147 dcMem.DeleteDC();
3148 }
3149 }
3150
3151 void NotifyParentSortChanged(int iNewSortCol, int iOldSortCol)
3152 {
3153 T* pT = static_cast<T*>(this);
3154 int nID = pT->GetDlgCtrlID();
3155 NMSORTLISTVIEW nm = { { pT->m_hWnd, nID, SLVN_SORTCHANGED }, iNe wSortCol, iOldSortCol };
3156 ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)& nm);
3157 }
3158
3159 // Overrideables
3160 int CompareItemsCustom(LVCompareParam* /*pItem1*/, LVCompareParam* /*pIt em2*/, int /*iSortCol*/)
3161 {
3162 // pItem1 and pItem2 contain valid iItem, dwItemData, and pszVal ue members.
3163 // If item1 > item2 return 1, if item1 < item2 return -1, else r eturn 0.
3164 return 0;
3165 }
3166
3167 void DrawSortBitmap(CDCHandle dc, int iBitmap, LPRECT prc)
3168 {
3169 dc.FillRect(prc, ::GetSysColorBrush(COLOR_BTNFACE));
3170 HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADO W));
3171 CPen pen;
3172 pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNSHADOW));
3173 HPEN hpenOld = dc.SelectPen(pen);
3174 POINT ptOrg = { (m_cxSortImage - m_cxSortArrow) / 2, (m_cySortIm age - m_cySortArrow) / 2 };
3175 if(iBitmap == m_iSortUp)
3176 {
3177 POINT pts[3] =
3178 {
3179 { ptOrg.x + m_cxSortArrow / 2, ptOrg.y },
3180 { ptOrg.x, ptOrg.y + m_cySortArrow - 1 },
3181 { ptOrg.x + m_cxSortArrow - 1, ptOrg.y + m_cySor tArrow - 1 }
3182 };
3183 dc.Polygon(pts, 3);
3184 }
3185 else
3186 {
3187 POINT pts[3] =
3188 {
3189 { ptOrg.x, ptOrg.y },
3190 { ptOrg.x + m_cxSortArrow / 2, ptOrg.y + m_cySor tArrow - 1 },
3191 { ptOrg.x + m_cxSortArrow - 1, ptOrg.y }
3192 };
3193 dc.Polygon(pts, 3);
3194 }
3195 dc.SelectBrush(hbrOld);
3196 dc.SelectPen(hpenOld);
3197 }
3198
3199 double DateStrToDouble(LPCTSTR lpstr, DWORD dwFlags)
3200 {
3201 ATLASSERT(lpstr != NULL);
3202 if(lpstr == NULL || lpstr[0] == _T('\0'))
3203 return 0;
3204
3205 USES_CONVERSION;
3206 HRESULT hRet = E_FAIL;
3207 DATE dRet = 0;
3208 if (FAILED(hRet = ::VarDateFromStr((LPOLESTR)T2COLE(lpstr), LANG _USER_DEFAULT, dwFlags, &dRet)))
3209 {
3210 ATLTRACE2(atlTraceUI, 0, _T("VarDateFromStr failed with result of 0x%8.8X\n"), hRet);
3211 dRet = 0;
3212 }
3213 return dRet;
3214 }
3215
3216 long StrToLong(LPCTSTR lpstr)
3217 {
3218 ATLASSERT(lpstr != NULL);
3219 if(lpstr == NULL || lpstr[0] == _T('\0'))
3220 return 0;
3221
3222 USES_CONVERSION;
3223 HRESULT hRet = E_FAIL;
3224 long lRet = 0;
3225 if (FAILED(hRet = ::VarI4FromStr((LPOLESTR)T2COLE(lpstr), LANG_U SER_DEFAULT, LOCALE_NOUSEROVERRIDE, &lRet)))
3226 {
3227 ATLTRACE2(atlTraceUI, 0, _T("VarI4FromStr failed with re sult of 0x%8.8X\n"), hRet);
3228 lRet = 0;
3229 }
3230 return lRet;
3231 }
3232
3233 double StrToDouble(LPCTSTR lpstr)
3234 {
3235 ATLASSERT(lpstr != NULL);
3236 if(lpstr == NULL || lpstr[0] == _T('\0'))
3237 return 0;
3238
3239 USES_CONVERSION;
3240 HRESULT hRet = E_FAIL;
3241 double dblRet = 0;
3242 if (FAILED(hRet = ::VarR8FromStr((LPOLESTR)T2COLE(lpstr), LANG_U SER_DEFAULT, LOCALE_NOUSEROVERRIDE, &dblRet)))
3243 {
3244 ATLTRACE2(atlTraceUI, 0, _T("VarR8FromStr failed with re sult of 0x%8.8X\n"), hRet);
3245 dblRet = 0;
3246 }
3247 return dblRet;
3248 }
3249
3250 bool StrToDecimal(LPCTSTR lpstr, DECIMAL* pDecimal)
3251 {
3252 ATLASSERT(lpstr != NULL);
3253 ATLASSERT(pDecimal != NULL);
3254 if(lpstr == NULL || pDecimal == NULL)
3255 return false;
3256
3257 USES_CONVERSION;
3258 HRESULT hRet = E_FAIL;
3259 if (FAILED(hRet = ::VarDecFromStr((LPOLESTR)T2COLE(lpstr), LANG_ USER_DEFAULT, LOCALE_NOUSEROVERRIDE, pDecimal)))
3260 {
3261 ATLTRACE2(atlTraceUI, 0, _T("VarDecFromStr failed with r esult of 0x%8.8X\n"), hRet);
3262 pDecimal->Lo64 = 0;
3263 pDecimal->Hi32 = 0;
3264 pDecimal->signscale = 0;
3265 return false;
3266 }
3267 return true;
3268 }
3269
3270 // Overrideable PFNLVCOMPARE functions
3271 static int CALLBACK LVCompareText(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
3272 {
3273 ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NU LL);
3274
3275 LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
3276 LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
3277 LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
3278
3279 int nRet = lstrcmp(pParam1->pszValue, pParam2->pszValue);
3280 return pInfo->bDescending ? -nRet : nRet;
3281 }
3282
3283 static int CALLBACK LVCompareTextNoCase(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
3284 {
3285 ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NU LL);
3286
3287 LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
3288 LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
3289 LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
3290
3291 int nRet = lstrcmpi(pParam1->pszValue, pParam2->pszValue);
3292 return pInfo->bDescending ? -nRet : nRet;
3293 }
3294
3295 static int CALLBACK LVCompareLong(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
3296 {
3297 ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NU LL);
3298
3299 LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
3300 LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
3301 LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
3302
3303 int nRet = 0;
3304 if(pParam1->lValue > pParam2->lValue)
3305 nRet = 1;
3306 else if(pParam1->lValue < pParam2->lValue)
3307 nRet = -1;
3308 return pInfo->bDescending ? -nRet : nRet;
3309 }
3310
3311 static int CALLBACK LVCompareDouble(LPARAM lParam1, LPARAM lParam2, LPAR AM lParamSort)
3312 {
3313 ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NU LL);
3314
3315 LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
3316 LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
3317 LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
3318
3319 int nRet = 0;
3320 if(pParam1->dblValue > pParam2->dblValue)
3321 nRet = 1;
3322 else if(pParam1->dblValue < pParam2->dblValue)
3323 nRet = -1;
3324 return pInfo->bDescending ? -nRet : nRet;
3325 }
3326
3327 static int CALLBACK LVCompareCustom(LPARAM lParam1, LPARAM lParam2, LPAR AM lParamSort)
3328 {
3329 ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NU LL);
3330
3331 LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
3332 LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
3333 LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
3334
3335 int nRet = pInfo->pT->CompareItemsCustom(pParam1, pParam2, pInfo ->iSortCol);
3336 return pInfo->bDescending ? -nRet : nRet;
3337 }
3338
3339 #ifndef _WIN32_WCE
3340 static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPA RAM lParamSort)
3341 {
3342 ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NU LL);
3343
3344 LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
3345 LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
3346 LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
3347
3348 int nRet = (int)::VarDecCmp(&pParam1->decValue, &pParam2->decVal ue);
3349 nRet--;
3350 return pInfo->bDescending ? -nRet : nRet;
3351 }
3352 #else
3353 // Compare mantissas, ignore sign and scale
3354 static int CompareMantissas(const DECIMAL& decLeft, const DECIMAL& decRi ght)
3355 {
3356 if (decLeft.Hi32 < decRight.Hi32)
3357 {
3358 return -1;
3359 }
3360 if (decLeft.Hi32 > decRight.Hi32)
3361 {
3362 return 1;
3363 }
3364 // Here, decLeft.Hi32 == decRight.Hi32
3365 if (decLeft.Lo64 < decRight.Lo64)
3366 {
3367 return -1;
3368 }
3369 if (decLeft.Lo64 > decRight.Lo64)
3370 {
3371 return 1;
3372 }
3373 return 0;
3374 }
3375
3376 // return values: VARCMP_LT, VARCMP_EQ, VARCMP_GT, VARCMP_NULL
3377 static HRESULT VarDecCmp(const DECIMAL* pdecLeft, const DECIMAL* pdecRig ht)
3378 {
3379 static const ULONG powersOfTen[] =
3380 {
3381 10ul,
3382 100ul,
3383 1000ul,
3384 10000ul,
3385 100000ul,
3386 1000000ul,
3387 10000000ul,
3388 100000000ul,
3389 1000000000ul
3390 };
3391 static const int largestPower = sizeof(powersOfTen) / sizeof(pow ersOfTen[0]);
3392 if (!pdecLeft || !pdecRight)
3393 {
3394 return VARCMP_NULL;
3395 }
3396
3397 // Degenerate case - at least one comparand is of the form
3398 // [+-]0*10^N (denormalized zero)
3399 bool bLeftZero = (!pdecLeft->Lo64 && !pdecLeft->Hi32);
3400 bool bRightZero = (!pdecRight->Lo64 && !pdecRight->Hi32);
3401 if (bLeftZero && bRightZero)
3402 {
3403 return VARCMP_EQ;
3404 }
3405 bool bLeftNeg = ((pdecLeft->sign & DECIMAL_NEG) != 0);
3406 bool bRightNeg = ((pdecRight->sign & DECIMAL_NEG) != 0);
3407 if (bLeftZero)
3408 {
3409 return (bRightNeg ? VARCMP_GT : VARCMP_LT);
3410 }
3411 // This also covers the case where the comparands have different signs
3412 if (bRightZero || bLeftNeg != bRightNeg)
3413 {
3414 return (bLeftNeg ? VARCMP_LT : VARCMP_GT);
3415 }
3416
3417 // Here both comparands have the same sign and need to be compar ed
3418 // on mantissa and scale. The result is obvious when
3419 // 1. Scales are equal (then compare mantissas)
3420 // 2. A number with smaller scale is also the one with larger ma ntissa
3421 // (then this number is obviously larger)
3422 // In the remaining case, we would multiply the number with smal ler
3423 // scale by 10 and simultaneously increment its scale (which amo unts to
3424 // adding trailing zeros after decimal point), until the numbers fall under
3425 // one of the two cases above
3426 DECIMAL temp;
3427 bool bInvert = bLeftNeg; // the final result needs to be inverte d
3428 if (pdecLeft->scale < pdecRight->scale)
3429 {
3430 temp = *pdecLeft;
3431 }
3432 else
3433 {
3434 temp = *pdecRight;
3435 pdecRight = pdecLeft;
3436 bInvert = !bInvert;
3437 }
3438
3439 // Now temp is the number with smaller (or equal) scale, and
3440 // we can modify it freely without touching original parameters
3441 int comp;
3442 while ((comp = CompareMantissas(temp, *pdecRight)) < 0 &&
3443 temp.scale < pdecRight->scale)
3444 {
3445 // Multiply by an appropriate power of 10
3446 int scaleDiff = pdecRight->scale - temp.scale;
3447 if (scaleDiff > largestPower)
3448 {
3449 // Keep the multiplier representable in 32bit
3450 scaleDiff = largestPower;
3451 }
3452 DWORDLONG power = powersOfTen[scaleDiff - 1];
3453 // Multiply temp's mantissa by power
3454 DWORDLONG product = temp.Lo32 * power;
3455 ULONG carry = static_cast<ULONG>(product >> 32);
3456 temp.Lo32 = static_cast<ULONG>(product);
3457 product = temp.Mid32 * power + carry;
3458 carry = static_cast<ULONG>(product >> 32);
3459 temp.Mid32 = static_cast<ULONG>(product);
3460 product = temp.Hi32 * power + carry;
3461 if (static_cast<ULONG>(product >> 32))
3462 {
3463 // Multiplication overflowed - pdecLeft is clear ly larger
3464 break;
3465 }
3466 temp.Hi32 = static_cast<ULONG>(product);
3467 temp.scale = (BYTE)(temp.scale + scaleDiff);
3468 }
3469 if (temp.scale < pdecRight->scale)
3470 {
3471 comp = 1;
3472 }
3473 if (bInvert)
3474 {
3475 comp = -comp;
3476 }
3477 return (comp > 0 ? VARCMP_GT : comp < 0 ? VARCMP_LT : VARCMP_EQ) ;
3478 }
3479
3480 static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPA RAM lParamSort)
3481 {
3482 ATLASSERT(lParam1 != NULL && lParam2 != NULL && lParamSort != NU LL);
3483
3484 LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
3485 LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
3486 LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
3487
3488 int nRet = (int)VarDecCmp(&pParam1->decValue, &pParam2->decValue );
3489 nRet--;
3490 return pInfo->bDescending ? -nRet : nRet;
3491 }
3492 #endif // !_WIN32_WCE
3493
3494 BEGIN_MSG_MAP(CSortListViewImpl)
3495 MESSAGE_HANDLER(LVM_INSERTCOLUMN, OnInsertColumn)
3496 MESSAGE_HANDLER(LVM_DELETECOLUMN, OnDeleteColumn)
3497 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, OnHeaderItemClick)
3498 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, OnHeaderItemClick)
3499 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
3500 END_MSG_MAP()
3501
3502 LRESULT OnInsertColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /* bHandled*/)
3503 {
3504 T* pT = static_cast<T*>(this);
3505 LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
3506 if(lRet == -1)
3507 return -1;
3508
3509 WORD wType = 0;
3510 m_arrColSortType.Add(wType);
3511 int nCount = m_arrColSortType.GetSize();
3512 ATLASSERT(nCount == GetColumnCount());
3513
3514 for(int i = nCount - 1; i > lRet; i--)
3515 m_arrColSortType[i] = m_arrColSortType[i - 1];
3516 m_arrColSortType[(int)lRet] = LVCOLSORT_TEXT;
3517
3518 if(lRet <= m_iSortColumn)
3519 m_iSortColumn++;
3520
3521 return lRet;
3522 }
3523
3524 LRESULT OnDeleteColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /* bHandled*/)
3525 {
3526 T* pT = static_cast<T*>(this);
3527 LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
3528 if(lRet == 0)
3529 return 0;
3530
3531 int iCol = (int)wParam;
3532 if(m_iSortColumn == iCol)
3533 m_iSortColumn = -1;
3534 else if(m_iSortColumn > iCol)
3535 m_iSortColumn--;
3536 m_arrColSortType.RemoveAt(iCol);
3537
3538 return lRet;
3539 }
3540
3541 LRESULT OnHeaderItemClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
3542 {
3543 LPNMHEADER p = (LPNMHEADER)pnmh;
3544 if(p->iButton == 0)
3545 {
3546 int iOld = m_iSortColumn;
3547 bool bDescending = (m_iSortColumn == p->iItem) ? !m_bSor tDescending : false;
3548 if(DoSortItems(p->iItem, bDescending))
3549 NotifyParentSortChanged(p->iItem, iOld);
3550 }
3551 bHandled = FALSE;
3552 return 0;
3553 }
3554
3555 LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
3556 {
3557 #ifndef _WIN32_WCE
3558 if(wParam == SPI_SETNONCLIENTMETRICS)
3559 GetSystemSettings();
3560 #else // CE specific
3561 wParam; // avoid level 4 warning
3562 GetSystemSettings();
3563 #endif // _WIN32_WCE
3564 bHandled = FALSE;
3565 return 0;
3566 }
3567
3568 void GetSystemSettings()
3569 {
3570 if(!m_bCommCtrl6 && !m_bmSort[m_iSortUp].IsNull())
3571 {
3572 T* pT = static_cast<T*>(this);
3573 pT->CreateSortBitmaps();
3574 if(m_iSortColumn != -1)
3575 SetSortColumn(m_iSortColumn);
3576 }
3577 }
3578
3579 };
3580
3581
3582 typedef ATL::CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLING S | LVS_REPORT | LVS_SHOWSELALWAYS , WS_EX_CLIENTEDGE> CSortListViewCtrlTraits ;
3583
3584 template <class T, class TBase = CListViewCtrl, class TWinTraits = CSortListView CtrlTraits>
3585 class ATL_NO_VTABLE CSortListViewCtrlImpl: public ATL::CWindowImpl<T, TBase, TWi nTraits>, public CSortListViewImpl<T>
3586 {
3587 public:
3588 DECLARE_WND_SUPERCLASS(NULL, TBase::GetWndClassName())
3589
3590 bool SortItems(int iCol, bool bDescending = false)
3591 {
3592 return DoSortItems(iCol, bDescending);
3593 }
3594
3595 BEGIN_MSG_MAP(CSortListViewCtrlImpl)
3596 MESSAGE_HANDLER(LVM_INSERTCOLUMN, CSortListViewImpl<T>::OnInsert Column)
3597 MESSAGE_HANDLER(LVM_DELETECOLUMN, CSortListViewImpl<T>::OnDelete Column)
3598 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, CSortListViewImpl<T>::OnHead erItemClick)
3599 NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, CSortListViewImpl<T>::OnHead erItemClick)
3600 MESSAGE_HANDLER(WM_SETTINGCHANGE, CSortListViewImpl<T>::OnSettin gChange)
3601 END_MSG_MAP()
3602 };
3603
3604 class CSortListViewCtrl : public CSortListViewCtrlImpl<CSortListViewCtrl>
3605 {
3606 public:
3607 DECLARE_WND_SUPERCLASS(_T("WTL_SortListViewCtrl"), GetWndClassName())
3608 };
3609
3610
3611 ///////////////////////////////////////////////////////////////////////////////
3612 // CTabView - implements tab view window
3613
3614 // TabView Notifications
3615 #define TBVN_PAGEACTIVATED (0U-741)
3616 #define TBVN_CONTEXTMENU (0U-742)
3617
3618 // Notification data for TBVN_CONTEXTMENU
3619 struct TBVCONTEXTMENUINFO
3620 {
3621 NMHDR hdr;
3622 POINT pt;
3623 };
3624
3625 typedef TBVCONTEXTMENUINFO* LPTBVCONTEXTMENUINFO;
3626
3627
3628 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlW inTraits>
3629 class ATL_NO_VTABLE CTabViewImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>
3630 {
3631 public:
3632 DECLARE_WND_CLASS_EX(NULL, 0, COLOR_APPWORKSPACE)
3633
3634 // Declarations and enums
3635 struct TABVIEWPAGE
3636 {
3637 HWND hWnd;
3638 LPTSTR lpstrTitle;
3639 LPVOID pData;
3640 };
3641
3642 struct TCITEMEXTRA
3643 {
3644 TCITEMHEADER tciheader;
3645 TABVIEWPAGE tvpage;
3646
3647 operator LPTCITEM() { return (LPTCITEM)this; }
3648 };
3649
3650 enum
3651 {
3652 m_nTabID = 1313,
3653 m_cxMoveMark = 6,
3654 m_cyMoveMark = 3,
3655 m_nMenuItemsMax = (ID_WINDOW_TABLAST - ID_WINDOW_TABFIRST + 1)
3656 };
3657
3658 // Data members
3659 ATL::CContainedWindowT<CTabCtrl> m_tab;
3660 int m_cyTabHeight;
3661
3662 int m_nActivePage;
3663
3664 int m_nInsertItem;
3665 POINT m_ptStartDrag;
3666
3667 CMenuHandle m_menu;
3668
3669 int m_cchTabTextLength;
3670
3671 int m_nMenuItemsCount;
3672
3673 ATL::CWindow m_wndTitleBar;
3674 LPTSTR m_lpstrTitleBarBase;
3675 int m_cchTitleBarLength;
3676
3677 CImageList m_ilDrag;
3678
3679 bool m_bDestroyPageOnRemove:1;
3680 bool m_bDestroyImageList:1;
3681 bool m_bActivePageMenuItem:1;
3682 bool m_bActiveAsDefaultMenuItem:1;
3683 bool m_bEmptyMenuItem:1;
3684 bool m_bWindowsMenuItem:1;
3685 // internal
3686 bool m_bTabCapture:1;
3687 bool m_bTabDrag:1;
3688
3689 // Constructor/destructor
3690 CTabViewImpl() :
3691 m_nActivePage(-1),
3692 m_cyTabHeight(0),
3693 m_tab(this, 1),
3694 m_nInsertItem(-1),
3695 m_cchTabTextLength(30),
3696 m_nMenuItemsCount(10),
3697 m_lpstrTitleBarBase(NULL),
3698 m_cchTitleBarLength(100),
3699 m_bDestroyPageOnRemove(true),
3700 m_bDestroyImageList(true),
3701 m_bActivePageMenuItem(true),
3702 m_bActiveAsDefaultMenuItem(false),
3703 m_bEmptyMenuItem(false),
3704 m_bWindowsMenuItem(false),
3705 m_bTabCapture(false),
3706 m_bTabDrag(false)
3707 {
3708 m_ptStartDrag.x = 0;
3709 m_ptStartDrag.y = 0;
3710 }
3711
3712 ~CTabViewImpl()
3713 {
3714 delete [] m_lpstrTitleBarBase;
3715 }
3716
3717 // Message filter function - to be called from PreTranslateMessage of the main w indow
3718 BOOL PreTranslateMessage(MSG* pMsg)
3719 {
3720 if(IsWindow() == FALSE)
3721 return FALSE;
3722
3723 BOOL bRet = FALSE;
3724
3725 // Check for TabView built-in accelerators (Ctrl+Tab/Ctrl+Shift+ Tab - next/previous page)
3726 int nCount = GetPageCount();
3727 if(nCount > 0)
3728 {
3729 bool bControl = (::GetKeyState(VK_CONTROL) < 0);
3730 if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_ TAB) && bControl)
3731 {
3732 if(nCount > 1)
3733 {
3734 int nPage = m_nActivePage;
3735 bool bShift = (::GetKeyState(VK_SHIFT) < 0);
3736 if(bShift)
3737 nPage = (nPage > 0) ? (nPage - 1 ) : (nCount - 1);
3738 else
3739 nPage = ((nPage >= 0) && (nPage < (nCount - 1))) ? (nPage + 1) : 0;
3740
3741 SetActivePage(nPage);
3742 T* pT = static_cast<T*>(this);
3743 pT->OnPageActivated(m_nActivePage);
3744 }
3745
3746 bRet = TRUE;
3747 }
3748 }
3749
3750 // If we are doing drag-drop, check for Escape key that cancels it
3751 if(bRet == FALSE)
3752 {
3753 if(m_bTabCapture && pMsg->message == WM_KEYDOWN && pMsg- >wParam == VK_ESCAPE)
3754 {
3755 ::ReleaseCapture();
3756 bRet = TRUE;
3757 }
3758 }
3759
3760 // Pass the message to the active page
3761 if(bRet == FALSE)
3762 {
3763 if(m_nActivePage != -1)
3764 bRet = (BOOL)::SendMessage(GetPageHWND(m_nActive Page), WM_FORWARDMSG, 0, (LPARAM)pMsg);
3765 }
3766
3767 return bRet;
3768 }
3769
3770 // Attributes
3771 int GetPageCount() const
3772 {
3773 ATLASSERT(::IsWindow(m_hWnd));
3774 return m_tab.GetItemCount();
3775 }
3776
3777 int GetActivePage() const
3778 {
3779 return m_nActivePage;
3780 }
3781
3782 void SetActivePage(int nPage)
3783 {
3784 ATLASSERT(::IsWindow(m_hWnd));
3785 ATLASSERT(IsValidPageIndex(nPage));
3786
3787 T* pT = static_cast<T*>(this);
3788
3789 SetRedraw(FALSE);
3790
3791 if(m_nActivePage != -1)
3792 ::ShowWindow(GetPageHWND(m_nActivePage), FALSE);
3793 m_nActivePage = nPage;
3794 m_tab.SetCurSel(m_nActivePage);
3795 ::ShowWindow(GetPageHWND(m_nActivePage), TRUE);
3796
3797 pT->UpdateLayout();
3798
3799 SetRedraw(TRUE);
3800 RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATE NOW | RDW_ALLCHILDREN);
3801
3802 if(::GetFocus() != m_tab.m_hWnd)
3803 ::SetFocus(GetPageHWND(m_nActivePage));
3804
3805 pT->UpdateTitleBar();
3806 pT->UpdateMenu();
3807 }
3808
3809 HIMAGELIST GetImageList() const
3810 {
3811 ATLASSERT(::IsWindow(m_hWnd));
3812 return m_tab.GetImageList();
3813 }
3814
3815 HIMAGELIST SetImageList(HIMAGELIST hImageList)
3816 {
3817 ATLASSERT(::IsWindow(m_hWnd));
3818 return m_tab.SetImageList(hImageList);
3819 }
3820
3821 void SetWindowMenu(HMENU hMenu)
3822 {
3823 ATLASSERT(::IsWindow(m_hWnd));
3824
3825 m_menu = hMenu;
3826
3827 T* pT = static_cast<T*>(this);
3828 pT->UpdateMenu();
3829 }
3830
3831 void SetTitleBarWindow(HWND hWnd)
3832 {
3833 ATLASSERT(::IsWindow(m_hWnd));
3834
3835 delete [] m_lpstrTitleBarBase;
3836 m_lpstrTitleBarBase = NULL;
3837
3838 m_wndTitleBar = hWnd;
3839 if(hWnd == NULL)
3840 return;
3841
3842 int cchLen = m_wndTitleBar.GetWindowTextLength() + 1;
3843 ATLTRY(m_lpstrTitleBarBase = new TCHAR[cchLen]);
3844 if(m_lpstrTitleBarBase != NULL)
3845 {
3846 m_wndTitleBar.GetWindowText(m_lpstrTitleBarBase, cchLen) ;
3847 T* pT = static_cast<T*>(this);
3848 pT->UpdateTitleBar();
3849 }
3850 }
3851
3852 // Page attributes
3853 HWND GetPageHWND(int nPage) const
3854 {
3855 ATLASSERT(::IsWindow(m_hWnd));
3856 ATLASSERT(IsValidPageIndex(nPage));
3857
3858 TCITEMEXTRA tcix = { 0 };
3859 tcix.tciheader.mask = TCIF_PARAM;
3860 m_tab.GetItem(nPage, tcix);
3861
3862 return tcix.tvpage.hWnd;
3863 }
3864
3865 LPCTSTR GetPageTitle(int nPage) const
3866 {
3867 ATLASSERT(::IsWindow(m_hWnd));
3868 ATLASSERT(IsValidPageIndex(nPage));
3869
3870 TCITEMEXTRA tcix = { 0 };
3871 tcix.tciheader.mask = TCIF_PARAM;
3872 if(m_tab.GetItem(nPage, tcix) == FALSE)
3873 return NULL;
3874
3875 return tcix.tvpage.lpstrTitle;
3876 }
3877
3878 bool SetPageTitle(int nPage, LPCTSTR lpstrTitle)
3879 {
3880 ATLASSERT(::IsWindow(m_hWnd));
3881 ATLASSERT(IsValidPageIndex(nPage));
3882
3883 T* pT = static_cast<T*>(this);
3884
3885 int cchBuff = lstrlen(lpstrTitle) + 1;
3886 LPTSTR lpstrBuff = NULL;
3887 ATLTRY(lpstrBuff = new TCHAR[cchBuff]);
3888 if(lpstrBuff == NULL)
3889 return false;
3890
3891 SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle);
3892 TCITEMEXTRA tcix = { 0 };
3893 tcix.tciheader.mask = TCIF_PARAM;
3894 if(m_tab.GetItem(nPage, tcix) == FALSE)
3895 return false;
3896
3897 CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
3898 LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);
3899 if(lpstrTabText == NULL)
3900 return false;
3901
3902 delete [] tcix.tvpage.lpstrTitle;
3903
3904 pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1);
3905
3906 tcix.tciheader.mask = TCIF_TEXT | TCIF_PARAM;
3907 tcix.tciheader.pszText = lpstrTabText;
3908 tcix.tvpage.lpstrTitle = lpstrBuff;
3909 if(m_tab.SetItem(nPage, tcix) == FALSE)
3910 return false;
3911
3912 pT->UpdateTitleBar();
3913 pT->UpdateMenu();
3914
3915 return true;
3916 }
3917
3918 LPVOID GetPageData(int nPage) const
3919 {
3920 ATLASSERT(::IsWindow(m_hWnd));
3921 ATLASSERT(IsValidPageIndex(nPage));
3922
3923 TCITEMEXTRA tcix = { 0 };
3924 tcix.tciheader.mask = TCIF_PARAM;
3925 m_tab.GetItem(nPage, tcix);
3926
3927 return tcix.tvpage.pData;
3928 }
3929
3930 LPVOID SetPageData(int nPage, LPVOID pData)
3931 {
3932 ATLASSERT(::IsWindow(m_hWnd));
3933 ATLASSERT(IsValidPageIndex(nPage));
3934
3935 TCITEMEXTRA tcix = { 0 };
3936 tcix.tciheader.mask = TCIF_PARAM;
3937 m_tab.GetItem(nPage, tcix);
3938 LPVOID pDataOld = tcix.tvpage.pData;
3939
3940 tcix.tvpage.pData = pData;
3941 m_tab.SetItem(nPage, tcix);
3942
3943 return pDataOld;
3944 }
3945
3946 int GetPageImage(int nPage) const
3947 {
3948 ATLASSERT(::IsWindow(m_hWnd));
3949 ATLASSERT(IsValidPageIndex(nPage));
3950
3951 TCITEMEXTRA tcix = { 0 };
3952 tcix.tciheader.mask = TCIF_IMAGE;
3953 m_tab.GetItem(nPage, tcix);
3954
3955 return tcix.tciheader.iImage;
3956 }
3957
3958 int SetPageImage(int nPage, int nImage)
3959 {
3960 ATLASSERT(::IsWindow(m_hWnd));
3961 ATLASSERT(IsValidPageIndex(nPage));
3962
3963 TCITEMEXTRA tcix = { 0 };
3964 tcix.tciheader.mask = TCIF_IMAGE;
3965 m_tab.GetItem(nPage, tcix);
3966 int nImageOld = tcix.tciheader.iImage;
3967
3968 tcix.tciheader.iImage = nImage;
3969 m_tab.SetItem(nPage, tcix);
3970
3971 return nImageOld;
3972 }
3973
3974 // Operations
3975 bool AddPage(HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL)
3976 {
3977 return InsertPage(GetPageCount(), hWndView, lpstrTitle, nImage, pData);
3978 }
3979
3980 bool InsertPage(int nPage, HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL)
3981 {
3982 ATLASSERT(::IsWindow(m_hWnd));
3983 ATLASSERT(nPage == GetPageCount() || IsValidPageIndex(nPage));
3984
3985 T* pT = static_cast<T*>(this);
3986
3987 int cchBuff = lstrlen(lpstrTitle) + 1;
3988 LPTSTR lpstrBuff = NULL;
3989 ATLTRY(lpstrBuff = new TCHAR[cchBuff]);
3990 if(lpstrBuff == NULL)
3991 return false;
3992
3993 SecureHelper::strcpy_x(lpstrBuff, cchBuff, lpstrTitle);
3994
3995 CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
3996 LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);
3997 if(lpstrTabText == NULL)
3998 return false;
3999
4000 pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1);
4001
4002 SetRedraw(FALSE);
4003
4004 TCITEMEXTRA tcix = { 0 };
4005 tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
4006 tcix.tciheader.pszText = lpstrTabText;
4007 tcix.tciheader.iImage = nImage;
4008 tcix.tvpage.hWnd = hWndView;
4009 tcix.tvpage.lpstrTitle = lpstrBuff;
4010 tcix.tvpage.pData = pData;
4011 int nItem = m_tab.InsertItem(nPage, tcix);
4012 if(nItem == -1)
4013 {
4014 delete [] lpstrBuff;
4015 SetRedraw(TRUE);
4016 return false;
4017 }
4018
4019 SetActivePage(nItem);
4020 pT->OnPageActivated(m_nActivePage);
4021
4022 if(GetPageCount() == 1)
4023 pT->ShowTabControl(true);
4024
4025 pT->UpdateLayout();
4026
4027 SetRedraw(TRUE);
4028 RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATE NOW | RDW_ALLCHILDREN);
4029
4030 return true;
4031 }
4032
4033 void RemovePage(int nPage)
4034 {
4035 ATLASSERT(::IsWindow(m_hWnd));
4036 ATLASSERT(IsValidPageIndex(nPage));
4037
4038 T* pT = static_cast<T*>(this);
4039
4040 SetRedraw(FALSE);
4041
4042 if(GetPageCount() == 1)
4043 pT->ShowTabControl(false);
4044
4045 if(m_bDestroyPageOnRemove)
4046 ::DestroyWindow(GetPageHWND(nPage));
4047 else
4048 ::ShowWindow(GetPageHWND(nPage), FALSE);
4049 LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(nPage);
4050 delete [] lpstrTitle;
4051
4052 ATLVERIFY(m_tab.DeleteItem(nPage) != FALSE);
4053
4054 if(m_nActivePage == nPage)
4055 {
4056 m_nActivePage = -1;
4057
4058 if(nPage > 0)
4059 {
4060 SetActivePage(nPage - 1);
4061 }
4062 else if(GetPageCount() > 0)
4063 {
4064 SetActivePage(nPage);
4065 }
4066 else
4067 {
4068 SetRedraw(TRUE);
4069 Invalidate();
4070 UpdateWindow();
4071 pT->UpdateTitleBar();
4072 pT->UpdateMenu();
4073 }
4074 }
4075 else
4076 {
4077 nPage = (nPage < m_nActivePage) ? (m_nActivePage - 1) : m_nActivePage;
4078 m_nActivePage = -1;
4079 SetActivePage(nPage);
4080 }
4081
4082 pT->OnPageActivated(m_nActivePage);
4083 }
4084
4085 void RemoveAllPages()
4086 {
4087 ATLASSERT(::IsWindow(m_hWnd));
4088
4089 if(GetPageCount() == 0)
4090 return;
4091
4092 T* pT = static_cast<T*>(this);
4093
4094 SetRedraw(FALSE);
4095
4096 pT->ShowTabControl(false);
4097
4098 for(int i = 0; i < GetPageCount(); i++)
4099 {
4100 if(m_bDestroyPageOnRemove)
4101 ::DestroyWindow(GetPageHWND(i));
4102 else
4103 ::ShowWindow(GetPageHWND(i), FALSE);
4104 LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(i);
4105 delete [] lpstrTitle;
4106 }
4107 m_tab.DeleteAllItems();
4108
4109 m_nActivePage = -1;
4110 pT->OnPageActivated(m_nActivePage);
4111
4112 SetRedraw(TRUE);
4113 Invalidate();
4114 UpdateWindow();
4115
4116 pT->UpdateTitleBar();
4117 pT->UpdateMenu();
4118 }
4119
4120 int PageIndexFromHwnd(HWND hWnd) const
4121 {
4122 int nIndex = -1;
4123
4124 for(int i = 0; i < GetPageCount(); i++)
4125 {
4126 if(GetPageHWND(i) == hWnd)
4127 {
4128 nIndex = i;
4129 break;
4130 }
4131 }
4132
4133 return nIndex;
4134 }
4135
4136 void BuildWindowMenu(HMENU hMenu, int nMenuItemsCount = 10, bool bEmptyM enuItem = true, bool bWindowsMenuItem = true, bool bActivePageMenuItem = true, b ool bActiveAsDefaultMenuItem = false)
4137 {
4138 ATLASSERT(::IsWindow(m_hWnd));
4139
4140 CMenuHandle menu = hMenu;
4141 T* pT = static_cast<T*>(this);
4142 pT; // avoid level 4 warning
4143 int nFirstPos = 0;
4144
4145 // Find first menu item in our range
4146 #ifndef _WIN32_WCE
4147 for(nFirstPos = 0; nFirstPos < menu.GetMenuItemCount(); nFirstPo s++)
4148 {
4149 UINT nID = menu.GetMenuItemID(nFirstPos);
4150 if((nID >= ID_WINDOW_TABFIRST && nID <= ID_WINDOW_TABLAS T) || nID == ID_WINDOW_SHOWTABLIST)
4151 break;
4152 }
4153 #else // CE specific
4154 for(nFirstPos = 0; ; nFirstPos++)
4155 {
4156 CMenuItemInfo mii;
4157 mii.fMask = MIIM_ID;
4158 BOOL bRet = menu.GetMenuItemInfo(nFirstPos, TRUE, &mii);
4159 if(bRet == FALSE)
4160 break;
4161 if((mii.wID >= ID_WINDOW_TABFIRST && mii.wID <= ID_WINDO W_TABLAST) || mii.wID == ID_WINDOW_SHOWTABLIST)
4162 break;
4163 }
4164 #endif // _WIN32_WCE
4165
4166 // Remove all menu items for tab pages
4167 BOOL bRet = TRUE;
4168 while(bRet != FALSE)
4169 bRet = menu.DeleteMenu(nFirstPos, MF_BYPOSITION);
4170
4171 // Add separator if it's not already there
4172 int nPageCount = GetPageCount();
4173 if((bWindowsMenuItem || (nPageCount > 0)) && (nFirstPos > 0))
4174 {
4175 CMenuItemInfo mii;
4176 mii.fMask = MIIM_TYPE;
4177 menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii);
4178 if((nFirstPos <= 0) || ((mii.fType & MFT_SEPARATOR) == 0 ))
4179 {
4180 menu.AppendMenu(MF_SEPARATOR);
4181 nFirstPos++;
4182 }
4183 }
4184
4185 // Add menu items for all pages
4186 if(nPageCount > 0)
4187 {
4188 // Append menu items for all pages
4189 const int cchPrefix = 3; // 2 digits + space
4190 nMenuItemsCount = __min(min(nPageCount, nMenuItemsCount) , (int)m_nMenuItemsMax);
4191 ATLASSERT(nMenuItemsCount < 100); // 2 digits only
4192 if(nMenuItemsCount >= 100)
4193 nMenuItemsCount = 99;
4194
4195 for(int i = 0; i < nMenuItemsCount; i++)
4196 {
4197 LPCTSTR lpstrTitle = GetPageTitle(i);
4198 int nLen = lstrlen(lpstrTitle);
4199 CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> b uff;
4200 LPTSTR lpstrText = buff.Allocate(cchPrefix + nLe n + 1);
4201 ATLASSERT(lpstrText != NULL);
4202 if(lpstrText != NULL)
4203 {
4204 LPCTSTR lpstrFormat = (i < 9) ? _T("&%i %s") : _T("%i %s");
4205 SecureHelper::wsprintf_x(lpstrText, cchP refix + nLen + 1, lpstrFormat, i + 1, lpstrTitle);
4206 menu.AppendMenu(MF_STRING, ID_WINDOW_TAB FIRST + i, lpstrText);
4207 }
4208 }
4209
4210 // Mark active page
4211 if(bActivePageMenuItem && (m_nActivePage != -1))
4212 {
4213 #ifndef _WIN32_WCE
4214 if(bActiveAsDefaultMenuItem)
4215 {
4216 menu.SetMenuDefaultItem((UINT)-1, TRUE) ;
4217 menu.SetMenuDefaultItem(nFirstPos + m_nA ctivePage, TRUE);
4218 }
4219 else
4220 #else // CE specific
4221 bActiveAsDefaultMenuItem; // avoid level 4 war ning
4222 #endif // _WIN32_WCE
4223 {
4224 menu.CheckMenuRadioItem(nFirstPos, nFirs tPos + nMenuItemsCount, nFirstPos + m_nActivePage, MF_BYPOSITION);
4225 }
4226 }
4227 }
4228 else
4229 {
4230 if(bEmptyMenuItem)
4231 {
4232 menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WI NDOW_TABFIRST, pT->GetEmptyListText());
4233 menu.EnableMenuItem(ID_WINDOW_TABFIRST, MF_GRAYE D);
4234 }
4235
4236 // Remove separator if nothing else is there
4237 if(!bEmptyMenuItem && !bWindowsMenuItem && (nFirstPos > 0))
4238 {
4239 CMenuItemInfo mii;
4240 mii.fMask = MIIM_TYPE;
4241 menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii);
4242 if((mii.fType & MFT_SEPARATOR) != 0)
4243 menu.DeleteMenu(nFirstPos - 1, MF_BYPOSI TION);
4244 }
4245 }
4246
4247 // Add "Windows..." menu item
4248 if(bWindowsMenuItem)
4249 menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_SHO WTABLIST, pT->GetWindowsMenuItemText());
4250 }
4251
4252 // Message map and handlers
4253 BEGIN_MSG_MAP(CTabViewImpl)
4254 MESSAGE_HANDLER(WM_CREATE, OnCreate)
4255 MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
4256 MESSAGE_HANDLER(WM_SIZE, OnSize)
4257 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
4258 NOTIFY_HANDLER(m_nTabID, TCN_SELCHANGE, OnTabChanged)
4259 NOTIFY_ID_HANDLER(m_nTabID, OnTabNotification)
4260 #ifndef _WIN32_WCE
4261 NOTIFY_CODE_HANDLER(TTN_GETDISPINFO, OnTabGetDispInfo)
4262 #endif // !_WIN32_WCE
4263 FORWARD_NOTIFICATIONS()
4264 ALT_MSG_MAP(1) // tab control
4265 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnTabLButtonDown)
4266 MESSAGE_HANDLER(WM_LBUTTONUP, OnTabLButtonUp)
4267 MESSAGE_HANDLER(WM_CAPTURECHANGED, OnTabCaptureChanged)
4268 MESSAGE_HANDLER(WM_MOUSEMOVE, OnTabMouseMove)
4269 MESSAGE_HANDLER(WM_RBUTTONUP, OnTabRButtonUp)
4270 MESSAGE_HANDLER(WM_SYSKEYDOWN, OnTabSysKeyDown)
4271 END_MSG_MAP()
4272
4273 LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BO OL& /*bHandled*/)
4274 {
4275 T* pT = static_cast<T*>(this);
4276 pT->CreateTabControl();
4277
4278 return 0;
4279 }
4280
4281 LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, B OOL& /*bHandled*/)
4282 {
4283 RemoveAllPages();
4284
4285 if(m_bDestroyImageList)
4286 {
4287 CImageList il = m_tab.SetImageList(NULL);
4288 if(il.m_hImageList != NULL)
4289 il.Destroy();
4290 }
4291
4292 return 0;
4293 }
4294
4295 LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL & /*bHandled*/)
4296 {
4297 T* pT = static_cast<T*>(this);
4298 pT->UpdateLayout();
4299 return 0;
4300 }
4301
4302 LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
4303 {
4304 if(m_nActivePage != -1)
4305 ::SetFocus(GetPageHWND(m_nActivePage));
4306 return 0;
4307 }
4308
4309 LRESULT OnTabChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled* /)
4310 {
4311 SetActivePage(m_tab.GetCurSel());
4312 T* pT = static_cast<T*>(this);
4313 pT->OnPageActivated(m_nActivePage);
4314
4315 return 0;
4316 }
4317
4318 LRESULT OnTabNotification(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHan dled*/)
4319 {
4320 // nothing to do - this just blocks all tab control
4321 // notifications from being propagated further
4322 return 0;
4323 }
4324
4325 #ifndef _WIN32_WCE
4326 LRESULT OnTabGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
4327 {
4328 LPNMTTDISPINFO pTTDI = (LPNMTTDISPINFO)pnmh;
4329 if(pTTDI->hdr.hwndFrom == m_tab.GetTooltips())
4330 {
4331 T* pT = static_cast<T*>(this);
4332 pT->UpdateTooltipText(pTTDI);
4333 }
4334 else
4335 {
4336 bHandled = FALSE;
4337 }
4338
4339 return 0;
4340 }
4341 #endif // !_WIN32_WCE
4342
4343 // Tab control message handlers
4344 LRESULT OnTabLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam , BOOL& bHandled)
4345 {
4346 if(m_tab.GetItemCount() > 1)
4347 {
4348 m_bTabCapture = true;
4349 m_tab.SetCapture();
4350
4351 m_ptStartDrag.x = GET_X_LPARAM(lParam);
4352 m_ptStartDrag.y = GET_Y_LPARAM(lParam);
4353 }
4354
4355 bHandled = FALSE;
4356 return 0;
4357 }
4358
4359 LRESULT OnTabLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
4360 {
4361 if(m_bTabCapture)
4362 {
4363 if(m_bTabDrag)
4364 {
4365 TCHITTESTINFO hti = { 0 };
4366 hti.pt.x = GET_X_LPARAM(lParam);
4367 hti.pt.y = GET_Y_LPARAM(lParam);
4368 int nItem = m_tab.HitTest(&hti);
4369 if(nItem != -1)
4370 MovePage(m_nActivePage, nItem);
4371 }
4372
4373 ::ReleaseCapture();
4374 }
4375
4376 bHandled = FALSE;
4377 return 0;
4378 }
4379
4380 LRESULT OnTabCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*l Param*/, BOOL& bHandled)
4381 {
4382 if(m_bTabCapture)
4383 {
4384 m_bTabCapture = false;
4385
4386 if(m_bTabDrag)
4387 {
4388 m_bTabDrag = false;
4389 T* pT = static_cast<T*>(this);
4390 pT->DrawMoveMark(-1);
4391
4392 #ifndef _WIN32_WCE
4393 m_ilDrag.DragLeave(GetDesktopWindow());
4394 #endif // !_WIN32_WCE
4395 m_ilDrag.EndDrag();
4396
4397 m_ilDrag.Destroy();
4398 m_ilDrag.m_hImageList = NULL;
4399 }
4400 }
4401
4402 bHandled = FALSE;
4403 return 0;
4404 }
4405
4406 LRESULT OnTabMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
4407 {
4408 bHandled = FALSE;
4409
4410 if(m_bTabCapture)
4411 {
4412 POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
4413
4414 if(!m_bTabDrag)
4415 {
4416 #ifndef _WIN32_WCE
4417 if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) > = ::GetSystemMetrics(SM_CXDRAG) ||
4418 abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) > = ::GetSystemMetrics(SM_CYDRAG))
4419 #else // CE specific
4420 if(abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) > = 4 ||
4421 abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) > = 4)
4422 #endif // _WIN32_WCE
4423 {
4424 T* pT = static_cast<T*>(this);
4425 pT->GenerateDragImage(m_nActivePage);
4426
4427 int cxCursor = ::GetSystemMetrics(SM_CXC URSOR);
4428 int cyCursor = ::GetSystemMetrics(SM_CYC URSOR);
4429 m_ilDrag.BeginDrag(0, -(cxCursor / 2), - (cyCursor / 2));
4430 #ifndef _WIN32_WCE
4431 POINT ptEnter = m_ptStartDrag;
4432 m_tab.ClientToScreen(&ptEnter);
4433 m_ilDrag.DragEnter(GetDesktopWindow(), p tEnter);
4434 #endif // !_WIN32_WCE
4435
4436 m_bTabDrag = true;
4437 }
4438 }
4439
4440 if(m_bTabDrag)
4441 {
4442 TCHITTESTINFO hti = { 0 };
4443 hti.pt = pt;
4444 int nItem = m_tab.HitTest(&hti);
4445
4446 T* pT = static_cast<T*>(this);
4447 pT->SetMoveCursor(nItem != -1);
4448
4449 if(m_nInsertItem != nItem)
4450 pT->DrawMoveMark(nItem);
4451
4452 m_ilDrag.DragShowNolock((nItem != -1) ? TRUE : F ALSE);
4453 m_tab.ClientToScreen(&pt);
4454 m_ilDrag.DragMove(pt);
4455
4456 bHandled = TRUE;
4457 }
4458 }
4459
4460 return 0;
4461 }
4462
4463 LRESULT OnTabRButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
4464 {
4465 TCHITTESTINFO hti = { 0 };
4466 hti.pt.x = GET_X_LPARAM(lParam);
4467 hti.pt.y = GET_Y_LPARAM(lParam);
4468 int nItem = m_tab.HitTest(&hti);
4469 if(nItem != -1)
4470 {
4471 T* pT = static_cast<T*>(this);
4472 pT->OnContextMenu(nItem, hti.pt);
4473 }
4474
4475 return 0;
4476 }
4477
4478 LRESULT OnTabSysKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
4479 {
4480 bool bShift = (::GetKeyState(VK_SHIFT) < 0);
4481 if(wParam == VK_F10 && bShift)
4482 {
4483 if(m_nActivePage != -1)
4484 {
4485 RECT rect = { 0 };
4486 m_tab.GetItemRect(m_nActivePage, &rect);
4487 POINT pt = { rect.left, rect.bottom };
4488 T* pT = static_cast<T*>(this);
4489 pT->OnContextMenu(m_nActivePage, pt);
4490 }
4491 }
4492 else
4493 {
4494 bHandled = FALSE;
4495 }
4496
4497 return 0;
4498 }
4499
4500 // Implementation helpers
4501 bool IsValidPageIndex(int nPage) const
4502 {
4503 return (nPage >= 0 && nPage < GetPageCount());
4504 }
4505
4506 bool MovePage(int nMovePage, int nInsertBeforePage)
4507 {
4508 ATLASSERT(IsValidPageIndex(nMovePage));
4509 ATLASSERT(IsValidPageIndex(nInsertBeforePage));
4510
4511 if(!IsValidPageIndex(nMovePage) || !IsValidPageIndex(nInsertBefo rePage))
4512 return false;
4513
4514 if(nMovePage == nInsertBeforePage)
4515 return true; // nothing to do
4516
4517 CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
4518 LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);
4519 if(lpstrTabText == NULL)
4520 return false;
4521 TCITEMEXTRA tcix = { 0 };
4522 tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
4523 tcix.tciheader.pszText = lpstrTabText;
4524 tcix.tciheader.cchTextMax = m_cchTabTextLength + 1;
4525 BOOL bRet = m_tab.GetItem(nMovePage, tcix);
4526 ATLASSERT(bRet != FALSE);
4527 if(bRet == FALSE)
4528 return false;
4529
4530 int nInsertItem = (nInsertBeforePage > nMovePage) ? nInsertBefor ePage + 1 : nInsertBeforePage;
4531 int nNewItem = m_tab.InsertItem(nInsertItem, tcix);
4532 ATLASSERT(nNewItem == nInsertItem);
4533 if(nNewItem != nInsertItem)
4534 {
4535 ATLVERIFY(m_tab.DeleteItem(nNewItem));
4536 return false;
4537 }
4538
4539 if(nMovePage > nInsertBeforePage)
4540 ATLVERIFY(m_tab.DeleteItem(nMovePage + 1) != FALSE);
4541 else if(nMovePage < nInsertBeforePage)
4542 ATLVERIFY(m_tab.DeleteItem(nMovePage) != FALSE);
4543
4544 SetActivePage(nInsertBeforePage);
4545 T* pT = static_cast<T*>(this);
4546 pT->OnPageActivated(m_nActivePage);
4547
4548 return true;
4549 }
4550
4551 // Implementation overrideables
4552 bool CreateTabControl()
4553 {
4554 #ifndef _WIN32_WCE
4555 m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_TOOLTIPS, 0, m_nTabID);
4556 #else // CE specific
4557 m_tab.Create(m_hWnd, rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN, 0, m_nTabID);
4558 #endif // _WIN32_WCE
4559 ATLASSERT(m_tab.m_hWnd != NULL);
4560 if(m_tab.m_hWnd == NULL)
4561 return false;
4562
4563 m_tab.SetFont(AtlGetDefaultGuiFont());
4564
4565 m_tab.SetItemExtra(sizeof(TABVIEWPAGE));
4566
4567 T* pT = static_cast<T*>(this);
4568 m_cyTabHeight = pT->CalcTabHeight();
4569
4570 return true;
4571 }
4572
4573 int CalcTabHeight()
4574 {
4575 int nCount = m_tab.GetItemCount();
4576 TCITEMEXTRA tcix = { 0 };
4577 tcix.tciheader.mask = TCIF_TEXT;
4578 tcix.tciheader.pszText = _T("NS");
4579 int nIndex = m_tab.InsertItem(nCount, tcix);
4580
4581 RECT rect = { 0, 0, 1000, 1000 };
4582 m_tab.AdjustRect(FALSE, &rect);
4583
4584 RECT rcWnd = { 0, 0, 1000, rect.top };
4585 ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetE xStyle());
4586
4587 int nHeight = rcWnd.bottom - rcWnd.top;
4588
4589 m_tab.DeleteItem(nIndex);
4590
4591 return nHeight;
4592 }
4593
4594 void ShowTabControl(bool bShow)
4595 {
4596 m_tab.ShowWindow(bShow ? SW_SHOWNOACTIVATE : SW_HIDE);
4597 }
4598
4599 void UpdateLayout()
4600 {
4601 RECT rect;
4602 GetClientRect(&rect);
4603
4604 if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0))
4605 m_tab.SetWindowPos(NULL, 0, 0, rect.right - rect.left, m _cyTabHeight, SWP_NOZORDER);
4606
4607 if(m_nActivePage != -1)
4608 ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, m_cy TabHeight, rect.right - rect.left, rect.bottom - rect.top - m_cyTabHeight, SWP_N OZORDER);
4609 }
4610
4611 void UpdateMenu()
4612 {
4613 if(m_menu.m_hMenu != NULL)
4614 BuildWindowMenu(m_menu, m_nMenuItemsCount, m_bEmptyMenuI tem, m_bWindowsMenuItem, m_bActivePageMenuItem, m_bActiveAsDefaultMenuItem);
4615 }
4616
4617 void UpdateTitleBar()
4618 {
4619 if(!m_wndTitleBar.IsWindow() || m_lpstrTitleBarBase == NULL)
4620 return; // nothing to do
4621
4622 if(m_nActivePage != -1)
4623 {
4624 T* pT = static_cast<T*>(this);
4625 LPCTSTR lpstrTitle = pT->GetPageTitle(m_nActivePage);
4626 LPCTSTR lpstrDivider = pT->GetTitleDividerText();
4627 int cchBuffer = m_cchTitleBarLength + lstrlen(lpstrDivid er) + lstrlen(m_lpstrTitleBarBase) + 1;
4628 CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
4629 LPTSTR lpstrPageTitle = buff.Allocate(cchBuffer);
4630 ATLASSERT(lpstrPageTitle != NULL);
4631 if(lpstrPageTitle != NULL)
4632 {
4633 pT->ShortenTitle(lpstrTitle, lpstrPageTitle, m_c chTitleBarLength + 1);
4634 SecureHelper::strcat_x(lpstrPageTitle, cchBuffer , lpstrDivider);
4635 SecureHelper::strcat_x(lpstrPageTitle, cchBuffer , m_lpstrTitleBarBase);
4636 }
4637 else
4638 {
4639 lpstrPageTitle = m_lpstrTitleBarBase;
4640 }
4641
4642 m_wndTitleBar.SetWindowText(lpstrPageTitle);
4643 }
4644 else
4645 {
4646 m_wndTitleBar.SetWindowText(m_lpstrTitleBarBase);
4647 }
4648 }
4649
4650 void DrawMoveMark(int nItem)
4651 {
4652 T* pT = static_cast<T*>(this);
4653
4654 if(m_nInsertItem != -1)
4655 {
4656 RECT rect = { 0 };
4657 pT->GetMoveMarkRect(rect);
4658 m_tab.InvalidateRect(&rect);
4659 }
4660
4661 m_nInsertItem = nItem;
4662
4663 if(m_nInsertItem != -1)
4664 {
4665 CClientDC dc(m_tab.m_hWnd);
4666
4667 RECT rect = { 0 };
4668 pT->GetMoveMarkRect(rect);
4669
4670 CPen pen;
4671 pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEX T));
4672 CBrush brush;
4673 brush.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT));
4674
4675 HPEN hPenOld = dc.SelectPen(pen);
4676 HBRUSH hBrushOld = dc.SelectBrush(brush);
4677
4678 int x = rect.left;
4679 int y = rect.top;
4680 POINT ptsTop[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y + m_cyMoveMark } };
4681 dc.Polygon(ptsTop, 3);
4682
4683 y = rect.bottom - 1;
4684 POINT ptsBottom[3] = { { x, y }, { x + m_cxMoveMark, y } , { x + (m_cxMoveMark / 2), y - m_cyMoveMark } };
4685 dc.Polygon(ptsBottom, 3);
4686
4687 dc.SelectPen(hPenOld);
4688 dc.SelectBrush(hBrushOld);
4689 }
4690 }
4691
4692 void GetMoveMarkRect(RECT& rect) const
4693 {
4694 m_tab.GetClientRect(&rect);
4695
4696 RECT rcItem = { 0 };
4697 m_tab.GetItemRect(m_nInsertItem, &rcItem);
4698
4699 if(m_nInsertItem <= m_nActivePage)
4700 {
4701 rect.left = rcItem.left - m_cxMoveMark / 2 - 1;
4702 rect.right = rcItem.left + m_cxMoveMark / 2;
4703 }
4704 else
4705 {
4706 rect.left = rcItem.right - m_cxMoveMark / 2 - 1;
4707 rect.right = rcItem.right + m_cxMoveMark / 2;
4708 }
4709 }
4710
4711 void SetMoveCursor(bool bCanMove)
4712 {
4713 ::SetCursor(::LoadCursor(NULL, bCanMove ? IDC_ARROW : IDC_NO));
4714 }
4715
4716 void GenerateDragImage(int nItem)
4717 {
4718 ATLASSERT(IsValidPageIndex(nItem));
4719
4720 #ifndef _WIN32_WCE
4721 RECT rcItem = { 0 };
4722 m_tab.GetItemRect(nItem, &rcItem);
4723 ::InflateRect(&rcItem, 2, 2); // make bigger to cover selected item
4724 #else // CE specific
4725 nItem; // avoid level 4 warning
4726 RECT rcItem = { 0, 0, 40, 20 };
4727 #endif // _WIN32_WCE
4728
4729 ATLASSERT(m_ilDrag.m_hImageList == NULL);
4730 m_ilDrag.Create(rcItem.right - rcItem.left, rcItem.bottom - rcIt em.top, ILC_COLORDDB | ILC_MASK, 1, 1);
4731
4732 CClientDC dc(m_hWnd);
4733 CDC dcMem;
4734 dcMem.CreateCompatibleDC(dc);
4735 ATLASSERT(dcMem.m_hDC != NULL);
4736 dcMem.SetViewportOrg(-rcItem.left, -rcItem.top);
4737
4738 CBitmap bmp;
4739 bmp.CreateCompatibleBitmap(dc, rcItem.right - rcItem.left, rcIte m.bottom - rcItem.top);
4740 ATLASSERT(bmp.m_hBitmap != NULL);
4741
4742 HBITMAP hBmpOld = dcMem.SelectBitmap(bmp);
4743 #ifndef _WIN32_WCE
4744 m_tab.SendMessage(WM_PRINTCLIENT, (WPARAM)dcMem.m_hDC);
4745 #else // CE specific
4746 dcMem.Rectangle(&rcItem);
4747 #endif // _WIN32_WCE
4748 dcMem.SelectBitmap(hBmpOld);
4749
4750 ATLVERIFY(m_ilDrag.Add(bmp.m_hBitmap, RGB(255, 0, 255)) != -1);
4751 }
4752
4753 void ShortenTitle(LPCTSTR lpstrTitle, LPTSTR lpstrShortTitle, int cchSho rtTitle)
4754 {
4755 if(lstrlen(lpstrTitle) >= cchShortTitle)
4756 {
4757 LPCTSTR lpstrEllipsis = _T("...");
4758 int cchEllipsis = lstrlen(lpstrEllipsis);
4759 SecureHelper::strncpy_x(lpstrShortTitle, cchShortTitle, lpstrTitle, cchShortTitle - cchEllipsis - 1);
4760 SecureHelper::strcat_x(lpstrShortTitle, cchShortTitle, l pstrEllipsis);
4761 }
4762 else
4763 {
4764 SecureHelper::strcpy_x(lpstrShortTitle, cchShortTitle, l pstrTitle);
4765 }
4766 }
4767
4768 #ifndef _WIN32_WCE
4769 void UpdateTooltipText(LPNMTTDISPINFO pTTDI)
4770 {
4771 ATLASSERT(pTTDI != NULL);
4772 pTTDI->lpszText = (LPTSTR)GetPageTitle((int)pTTDI->hdr.idFrom);
4773 }
4774 #endif // !_WIN32_WCE
4775
4776 // Text for menu items and title bar - override to provide different strings
4777 static LPCTSTR GetEmptyListText()
4778 {
4779 return _T("(Empty)");
4780 }
4781
4782 static LPCTSTR GetWindowsMenuItemText()
4783 {
4784 return _T("&Windows...");
4785 }
4786
4787 static LPCTSTR GetTitleDividerText()
4788 {
4789 return _T(" - ");
4790 }
4791
4792 // Notifications - override to provide different behavior
4793 void OnPageActivated(int nPage)
4794 {
4795 NMHDR nmhdr = { 0 };
4796 nmhdr.hwndFrom = m_hWnd;
4797 nmhdr.idFrom = nPage;
4798 nmhdr.code = TBVN_PAGEACTIVATED;
4799 ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&n mhdr);
4800 }
4801
4802 void OnContextMenu(int nPage, POINT pt)
4803 {
4804 m_tab.ClientToScreen(&pt);
4805
4806 TBVCONTEXTMENUINFO cmi = { 0 };
4807 cmi.hdr.hwndFrom = m_hWnd;
4808 cmi.hdr.idFrom = nPage;
4809 cmi.hdr.code = TBVN_CONTEXTMENU;
4810 cmi.pt = pt;
4811 ::SendMessage(GetParent(), WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&c mi);
4812 }
4813 };
4814
4815
4816 class CTabView : public CTabViewImpl<CTabView>
4817 {
4818 public:
4819 DECLARE_WND_CLASS_EX(_T("WTL_TabView"), 0, COLOR_APPWORKSPACE)
4820 };
4821
4822 }; // namespace WTL
4823
4824 #endif // __ATLCTRLX_H__
OLDNEW
« no previous file with comments | « third_party/wtl/include/atlctrlw.h ('k') | third_party/wtl/include/atlddx.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698