OLD | NEW |
| (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__ | |
OLD | NEW |