]> git.sesse.net Git - casparcg/blob - WTL80/include/atlscrl.h
2.0.2: INFO TEMPLATE works on both compressed and uncompressed templates.
[casparcg] / WTL80 / include / atlscrl.h
1 // Windows Template Library - WTL version 8.0\r
2 // Copyright (C) Microsoft Corporation. All rights reserved.\r
3 //\r
4 // This file is a part of the Windows Template Library.\r
5 // The use and distribution terms for this software are covered by the\r
6 // Common Public License 1.0 (http://opensource.org/osi3.0/licenses/cpl1.0.php)\r
7 // which can be found in the file CPL.TXT at the root of this distribution.\r
8 // By using this software in any fashion, you are agreeing to be bound by\r
9 // the terms of this license. You must not remove this notice, or\r
10 // any other, from this software.\r
11 \r
12 #ifndef __ATLSCRL_H__\r
13 #define __ATLSCRL_H__\r
14 \r
15 #pragma once\r
16 \r
17 #ifndef __cplusplus\r
18         #error ATL requires C++ compilation (use a .cpp suffix)\r
19 #endif\r
20 \r
21 #ifndef __ATLAPP_H__\r
22         #error atlscrl.h requires atlapp.h to be included first\r
23 #endif\r
24 \r
25 #ifndef __ATLWIN_H__\r
26         #error atlscrl.h requires atlwin.h to be included first\r
27 #endif\r
28 \r
29 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\r
30   #include <zmouse.h>\r
31 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\r
32 \r
33 #ifndef GET_WHEEL_DELTA_WPARAM\r
34   #define GET_WHEEL_DELTA_WPARAM(wParam)  ((short)HIWORD(wParam))\r
35 #endif\r
36 \r
37 #ifndef WM_MOUSEHWHEEL\r
38   #define WM_MOUSEHWHEEL                  0x020E\r
39 #endif\r
40 \r
41 \r
42 ///////////////////////////////////////////////////////////////////////////////\r
43 // Classes in this file:\r
44 //\r
45 // CScrollImpl<T>\r
46 // CScrollWindowImpl<T, TBase, TWinTraits>\r
47 // CMapScrollImpl<T>\r
48 // CMapScrollWindowImpl<T, TBase, TWinTraits>\r
49 // CFSBWindowT<TBase>\r
50 // CZoomScrollImpl<T>\r
51 // CZoomScrollWindowImpl<T, TBase, TWinTraits>\r
52 // CScrollContainerImpl<T, TBase, TWinTraits>\r
53 // CScrollContainer\r
54 \r
55 namespace WTL\r
56 {\r
57 \r
58 ///////////////////////////////////////////////////////////////////////////////\r
59 // CScrollImpl - Provides scrolling support to any window\r
60 \r
61 // Scroll extended styles\r
62 #define SCRL_SCROLLCHILDREN     0x00000001\r
63 #define SCRL_ERASEBACKGROUND    0x00000002\r
64 #define SCRL_NOTHUMBTRACKING    0x00000004\r
65 #if (WINVER >= 0x0500)\r
66 #define SCRL_SMOOTHSCROLL       0x00000008\r
67 #endif // (WINVER >= 0x0500)\r
68 #define SCRL_DISABLENOSCROLLV   0x00000010\r
69 #define SCRL_DISABLENOSCROLLH   0x00000020\r
70 #define SCRL_DISABLENOSCROLL    (SCRL_DISABLENOSCROLLV | SCRL_DISABLENOSCROLLH)\r
71 \r
72 \r
73 template <class T>\r
74 class CScrollImpl\r
75 {\r
76 public:\r
77         enum { uSCROLL_FLAGS = SW_INVALIDATE };\r
78 \r
79         POINT m_ptOffset;\r
80         SIZE m_sizeAll;\r
81         SIZE m_sizeLine;\r
82         SIZE m_sizePage;\r
83         SIZE m_sizeClient;\r
84         int m_zDelta;              // current wheel value\r
85         int m_nWheelLines;         // number of lines to scroll on wheel\r
86 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\r
87         // Note that this message must be forwarded from a top level window\r
88         UINT m_uMsgMouseWheel;     // MSH_MOUSEWHEEL\r
89 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\r
90         int m_zHDelta;              // current horizontal wheel value\r
91         int m_nHWheelChars;         // number of chars to scroll on horizontal wheel\r
92         UINT m_uScrollFlags;\r
93         DWORD m_dwExtendedStyle;   // scroll specific extended styles\r
94 \r
95 // Constructor\r
96         CScrollImpl() : m_zDelta(0), m_nWheelLines(3), \r
97 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\r
98                         m_uMsgMouseWheel(0U), \r
99 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\r
100                         m_zHDelta(0), m_nHWheelChars(3), \r
101                         m_uScrollFlags(0U), m_dwExtendedStyle(0)\r
102         {\r
103                 m_ptOffset.x = 0;\r
104                 m_ptOffset.y = 0;\r
105                 m_sizeAll.cx = 0;\r
106                 m_sizeAll.cy = 0;\r
107                 m_sizePage.cx = 0;\r
108                 m_sizePage.cy = 0;\r
109                 m_sizeLine.cx = 0;\r
110                 m_sizeLine.cy = 0;\r
111                 m_sizeClient.cx = 0;\r
112                 m_sizeClient.cy = 0;\r
113 \r
114                 SetScrollExtendedStyle(SCRL_SCROLLCHILDREN | SCRL_ERASEBACKGROUND);\r
115         }\r
116 \r
117 // Attributes & Operations\r
118         DWORD GetScrollExtendedStyle() const\r
119         {\r
120                 return m_dwExtendedStyle;\r
121         }\r
122 \r
123         DWORD SetScrollExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)\r
124         {\r
125                 DWORD dwPrevStyle = m_dwExtendedStyle;\r
126                 if(dwMask == 0)\r
127                         m_dwExtendedStyle = dwExtendedStyle;\r
128                 else\r
129                         m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);\r
130                 // cache scroll flags\r
131                 T* pT = static_cast<T*>(this);\r
132                 pT;   // avoid level 4 warning\r
133                 m_uScrollFlags = pT->uSCROLL_FLAGS | (IsScrollingChildren() ? SW_SCROLLCHILDREN : 0) | (IsErasingBackground() ? SW_ERASE : 0);\r
134 #if (WINVER >= 0x0500) && !defined(_WIN32_WCE)\r
135                 m_uScrollFlags |= (IsSmoothScroll() ? SW_SMOOTHSCROLL : 0);\r
136 #endif // (WINVER >= 0x0500) && !defined(_WIN32_WCE)\r
137                 return dwPrevStyle;\r
138         }\r
139 \r
140         // offset operations\r
141         void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE)\r
142         {\r
143                 T* pT = static_cast<T*>(this);\r
144                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
145 \r
146                 pT->AdjustScrollOffset(x, y);\r
147 \r
148                 int dx = m_ptOffset.x - x;\r
149                 int dy = m_ptOffset.y - y;\r
150                 m_ptOffset.x = x;\r
151                 m_ptOffset.y = y;\r
152 \r
153                 // block: set horizontal scroll bar\r
154                 {\r
155                         SCROLLINFO si = { sizeof(SCROLLINFO) };\r
156                         si.fMask = SIF_POS;\r
157                         if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)\r
158                                 si.fMask |= SIF_DISABLENOSCROLL;\r
159                         si.nPos = m_ptOffset.x;\r
160                         pT->SetScrollInfo(SB_HORZ, &si, bRedraw);\r
161                 }\r
162 \r
163                 // block: set vertical scroll bar\r
164                 {\r
165                         SCROLLINFO si = { sizeof(SCROLLINFO) };\r
166                         si.fMask = SIF_POS;\r
167                         if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)\r
168                                 si.fMask |= SIF_DISABLENOSCROLL;\r
169                         si.nPos = m_ptOffset.y;\r
170                         pT->SetScrollInfo(SB_VERT, &si, bRedraw);\r
171                 }\r
172 \r
173                 // Move all children if needed\r
174                 if(IsScrollingChildren() && (dx != 0 || dy != 0))\r
175                 {\r
176                         for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))\r
177                         {\r
178                                 RECT rect = { 0 };\r
179                                 ::GetWindowRect(hWndChild, &rect);\r
180                                 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1);\r
181                                 ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);\r
182                         }\r
183                 }\r
184 \r
185                 if(bRedraw)\r
186                         pT->Invalidate();\r
187         }\r
188 \r
189         void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE)\r
190         {\r
191                 SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw);\r
192         }\r
193 \r
194         void GetScrollOffset(POINT& ptOffset) const\r
195         {\r
196                 ptOffset = m_ptOffset;\r
197         }\r
198 \r
199         // size operations\r
200         void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true)\r
201         {\r
202                 T* pT = static_cast<T*>(this);\r
203                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
204 \r
205                 m_sizeAll.cx = cx;\r
206                 m_sizeAll.cy = cy;\r
207 \r
208                 int x = 0;\r
209                 int y = 0;\r
210                 if(!bResetOffset)\r
211                 {\r
212                         x = m_ptOffset.x;\r
213                         y = m_ptOffset.y;\r
214                         pT->AdjustScrollOffset(x, y);\r
215                 }\r
216 \r
217                 int dx = m_ptOffset.x - x;\r
218                 int dy = m_ptOffset.y - y;\r
219                 m_ptOffset.x = x;\r
220                 m_ptOffset.y = y;\r
221 \r
222                 // block: set horizontal scroll bar\r
223                 {\r
224                         SCROLLINFO si = { sizeof(SCROLLINFO) };\r
225                         si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;\r
226                         if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)\r
227                                 si.fMask |= SIF_DISABLENOSCROLL;\r
228                         si.nMin = 0;\r
229                         si.nMax = m_sizeAll.cx - 1;\r
230                         si.nPage = m_sizeClient.cx;\r
231                         si.nPos = m_ptOffset.x;\r
232                         pT->SetScrollInfo(SB_HORZ, &si, bRedraw);\r
233                 }\r
234 \r
235                 // block: set vertical scroll bar\r
236                 {\r
237                         SCROLLINFO si = { sizeof(SCROLLINFO) };\r
238                         si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;\r
239                         if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)\r
240                                 si.fMask |= SIF_DISABLENOSCROLL;\r
241                         si.nMin = 0;\r
242                         si.nMax = m_sizeAll.cy - 1;\r
243                         si.nPage = m_sizeClient.cy;\r
244                         si.nPos = m_ptOffset.y;\r
245                         pT->SetScrollInfo(SB_VERT, &si, bRedraw);\r
246                 }\r
247 \r
248                 // Move all children if needed\r
249                 if(IsScrollingChildren() && (dx != 0 || dy != 0))\r
250                 {\r
251                         for(HWND hWndChild = ::GetWindow(pT->m_hWnd, GW_CHILD); hWndChild != NULL; hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT))\r
252                         {\r
253                                 RECT rect = { 0 };\r
254                                 ::GetWindowRect(hWndChild, &rect);\r
255                                 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 1);\r
256                                 ::SetWindowPos(hWndChild, NULL, rect.left + dx, rect.top + dy, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);\r
257                         }\r
258                 }\r
259 \r
260                 SetScrollLine(0, 0);\r
261                 SetScrollPage(0, 0);\r
262 \r
263                 if(bRedraw)\r
264                         pT->Invalidate();\r
265         }\r
266 \r
267         void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true)\r
268         {\r
269                 SetScrollSize(size.cx, size.cy, bRedraw, bResetOffset);\r
270         }\r
271 \r
272         void GetScrollSize(SIZE& sizeWnd) const\r
273         {\r
274                 sizeWnd = m_sizeAll;\r
275         }\r
276 \r
277         // line operations\r
278         void SetScrollLine(int cxLine, int cyLine)\r
279         {\r
280                 ATLASSERT(cxLine >= 0 && cyLine >= 0);\r
281                 ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0);\r
282 \r
283                 m_sizeLine.cx = T::CalcLineOrPage(cxLine, m_sizeAll.cx, 100);\r
284                 m_sizeLine.cy = T::CalcLineOrPage(cyLine, m_sizeAll.cy, 100);\r
285         }\r
286 \r
287         void SetScrollLine(SIZE sizeLine)\r
288         {\r
289                 SetScrollLine(sizeLine.cx, sizeLine.cy);\r
290         }\r
291 \r
292         void GetScrollLine(SIZE& sizeLine) const\r
293         {\r
294                 sizeLine = m_sizeLine;\r
295         }\r
296 \r
297         // page operations\r
298         void SetScrollPage(int cxPage, int cyPage)\r
299         {\r
300                 ATLASSERT(cxPage >= 0 && cyPage >= 0);\r
301                 ATLASSERT(m_sizeAll.cx != 0 && m_sizeAll.cy != 0);\r
302 \r
303                 m_sizePage.cx = T::CalcLineOrPage(cxPage, m_sizeAll.cx, 10);\r
304                 m_sizePage.cy = T::CalcLineOrPage(cyPage, m_sizeAll.cy, 10);\r
305         }\r
306 \r
307         void SetScrollPage(SIZE sizePage)\r
308         {\r
309                 SetScrollPage(sizePage.cx, sizePage.cy);\r
310         }\r
311 \r
312         void GetScrollPage(SIZE& sizePage) const\r
313         {\r
314                 sizePage = m_sizePage;\r
315         }\r
316 \r
317         // commands\r
318         void ScrollLineDown()\r
319         {\r
320                 T* pT = static_cast<T*>(this);\r
321                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
322                 pT->DoScroll(SB_VERT, SB_LINEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\r
323         }\r
324 \r
325         void ScrollLineUp()\r
326         {\r
327                 T* pT = static_cast<T*>(this);\r
328                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
329                 pT->DoScroll(SB_VERT, SB_LINEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\r
330         }\r
331 \r
332         void ScrollPageDown()\r
333         {\r
334                 T* pT = static_cast<T*>(this);\r
335                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
336                 pT->DoScroll(SB_VERT, SB_PAGEDOWN, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\r
337         }\r
338 \r
339         void ScrollPageUp()\r
340         {\r
341                 T* pT = static_cast<T*>(this);\r
342                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
343                 pT->DoScroll(SB_VERT, SB_PAGEUP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\r
344         }\r
345 \r
346         void ScrollTop()\r
347         {\r
348                 T* pT = static_cast<T*>(this);\r
349                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
350                 pT->DoScroll(SB_VERT, SB_TOP, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\r
351         }\r
352 \r
353         void ScrollBottom()\r
354         {\r
355                 T* pT = static_cast<T*>(this);\r
356                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
357                 pT->DoScroll(SB_VERT, SB_BOTTOM, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\r
358         }\r
359 \r
360         void ScrollLineRight()\r
361         {\r
362                 T* pT = static_cast<T*>(this);\r
363                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
364                 pT->DoScroll(SB_HORZ, SB_LINEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\r
365         }\r
366 \r
367         void ScrollLineLeft()\r
368         {\r
369                 T* pT = static_cast<T*>(this);\r
370                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
371                 pT->DoScroll(SB_HORZ, SB_LINEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\r
372         }\r
373 \r
374         void ScrollPageRight()\r
375         {\r
376                 T* pT = static_cast<T*>(this);\r
377                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
378                 pT->DoScroll(SB_HORZ, SB_PAGEDOWN, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\r
379         }\r
380 \r
381         void ScrollPageLeft()\r
382         {\r
383                 T* pT = static_cast<T*>(this);\r
384                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
385                 pT->DoScroll(SB_HORZ, SB_PAGEUP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\r
386         }\r
387 \r
388         void ScrollAllLeft()\r
389         {\r
390                 T* pT = static_cast<T*>(this);\r
391                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
392                 pT->DoScroll(SB_HORZ, SB_TOP, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\r
393         }\r
394 \r
395         void ScrollAllRight()\r
396         {\r
397                 T* pT = static_cast<T*>(this);\r
398                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
399                 pT->DoScroll(SB_HORZ, SB_BOTTOM, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\r
400         }\r
401 \r
402         // scroll to make point/view/window visible\r
403         void ScrollToView(POINT pt)\r
404         {\r
405                 T* pT = static_cast<T*>(this);\r
406                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
407                 RECT rect = { pt.x, pt.y, pt.x, pt.y };\r
408                 pT->ScrollToView(rect);\r
409         }\r
410 \r
411         void ScrollToView(RECT& rect)\r
412         {\r
413                 T* pT = static_cast<T*>(this);\r
414                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
415 \r
416                 RECT rcClient = { 0 };\r
417                 pT->GetClientRect(&rcClient);\r
418 \r
419                 int x = m_ptOffset.x;\r
420                 if(rect.left < m_ptOffset.x)\r
421                         x = rect.left;\r
422                 else if(rect.right > (m_ptOffset.x + rcClient.right))\r
423                         x = rect.right - rcClient.right;\r
424 \r
425                 int y = m_ptOffset.y;\r
426                 if(rect.top < m_ptOffset.y)\r
427                         y = rect.top;\r
428                 else if(rect.bottom > (m_ptOffset.y + rcClient.bottom))\r
429                         y = rect.bottom - rcClient.bottom;\r
430 \r
431                 SetScrollOffset(x, y);\r
432         }\r
433 \r
434         void ScrollToView(HWND hWnd)\r
435         {\r
436                 T* pT = static_cast<T*>(this);\r
437                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
438 \r
439                 RECT rect = { 0 };\r
440                 ::GetWindowRect(hWnd, &rect);\r
441                 ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rect, 2);\r
442                 ScrollToView(rect);\r
443         }\r
444 \r
445         BEGIN_MSG_MAP(CScrollImpl)\r
446                 MESSAGE_HANDLER(WM_CREATE, OnCreate)\r
447                 MESSAGE_HANDLER(WM_VSCROLL, OnVScroll)\r
448                 MESSAGE_HANDLER(WM_HSCROLL, OnHScroll)\r
449                 MESSAGE_HANDLER(WM_MOUSEWHEEL, OnMouseWheel)\r
450 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\r
451                 MESSAGE_HANDLER(m_uMsgMouseWheel, OnMouseWheel)\r
452 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\r
453                 MESSAGE_HANDLER(WM_MOUSEHWHEEL, OnMouseHWheel)\r
454                 MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)\r
455                 MESSAGE_HANDLER(WM_SIZE, OnSize)\r
456                 MESSAGE_HANDLER(WM_PAINT, OnPaint)\r
457 #ifndef _WIN32_WCE\r
458                 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\r
459 #endif // !_WIN32_WCE\r
460         // standard scroll commands\r
461         ALT_MSG_MAP(1)\r
462                 COMMAND_ID_HANDLER(ID_SCROLL_UP, OnScrollUp)\r
463                 COMMAND_ID_HANDLER(ID_SCROLL_DOWN, OnScrollDown)\r
464                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, OnScrollPageUp)\r
465                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, OnScrollPageDown)\r
466                 COMMAND_ID_HANDLER(ID_SCROLL_TOP, OnScrollTop)\r
467                 COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, OnScrollBottom)\r
468                 COMMAND_ID_HANDLER(ID_SCROLL_LEFT, OnScrollLeft)\r
469                 COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, OnScrollRight)\r
470                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, OnScrollPageLeft)\r
471                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, OnScrollPageRight)\r
472                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, OnScrollAllLeft)\r
473                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, OnScrollAllRight)\r
474         END_MSG_MAP()\r
475 \r
476         LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\r
477         {\r
478                 GetSystemSettings();\r
479                 bHandled = FALSE;\r
480                 return 1;\r
481         }\r
482 \r
483         LRESULT OnVScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
484         {\r
485                 T* pT = static_cast<T*>(this);\r
486                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
487                 pT->DoScroll(SB_VERT, (int)(short)LOWORD(wParam), (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\r
488                 return 0;\r
489         }\r
490 \r
491         LRESULT OnHScroll(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
492         {\r
493                 T* pT = static_cast<T*>(this);\r
494                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
495                 pT->DoScroll(SB_HORZ, (int)(short)LOWORD(wParam), (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\r
496                 return 0;\r
497         }\r
498 \r
499         LRESULT OnMouseWheel(UINT uMsg, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
500         {\r
501                 T* pT = static_cast<T*>(this);\r
502                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
503 \r
504 #if (_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE)\r
505                 uMsg;\r
506                 int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam);\r
507 #else\r
508                 int zDelta = (uMsg == WM_MOUSEWHEEL) ? (int)GET_WHEEL_DELTA_WPARAM(wParam) : (int)wParam;\r
509 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400) || defined(_WIN32_WCE))\r
510                 int nScrollCode = (m_nWheelLines == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGEUP : SB_PAGEDOWN) : ((zDelta > 0) ? SB_LINEUP : SB_LINEDOWN);\r
511                 m_zDelta += zDelta;   // cumulative\r
512                 int zTotal = (m_nWheelLines == WHEEL_PAGESCROLL) ? abs(m_zDelta) : abs(m_zDelta) * m_nWheelLines;\r
513                 if(m_sizeAll.cy > m_sizeClient.cy)\r
514                 {\r
515                         for(int i = 0; i < zTotal; i += WHEEL_DELTA)\r
516                         {\r
517                                 pT->DoScroll(SB_VERT, nScrollCode, (int&)m_ptOffset.y, m_sizeAll.cy, m_sizePage.cy, m_sizeLine.cy);\r
518                                 pT->UpdateWindow();\r
519                         }\r
520                 }\r
521                 else            // can't scroll vertically, scroll horizontally\r
522                 {\r
523                         for(int i = 0; i < zTotal; i += WHEEL_DELTA)\r
524                         {\r
525                                 pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\r
526                                 pT->UpdateWindow();\r
527                         }\r
528                 }\r
529                 m_zDelta %= WHEEL_DELTA;\r
530 \r
531                 return 0;\r
532         }\r
533 \r
534         LRESULT OnMouseHWheel(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
535         {\r
536                 T* pT = static_cast<T*>(this);\r
537                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
538 \r
539                 int zDelta = (int)GET_WHEEL_DELTA_WPARAM(wParam);\r
540                 int nScrollCode = (m_nHWheelChars == WHEEL_PAGESCROLL) ? ((zDelta > 0) ? SB_PAGERIGHT : SB_PAGELEFT) : ((zDelta > 0) ? SB_LINERIGHT : SB_LINELEFT);\r
541                 m_zHDelta += zDelta;   // cumulative\r
542                 int zTotal = (m_nHWheelChars == WHEEL_PAGESCROLL) ? abs(m_zHDelta) : abs(m_zHDelta) * m_nHWheelChars;\r
543                 if(m_sizeAll.cx > m_sizeClient.cx)\r
544                 {\r
545                         for(int i = 0; i < zTotal; i += WHEEL_DELTA)\r
546                         {\r
547                                 pT->DoScroll(SB_HORZ, nScrollCode, (int&)m_ptOffset.x, m_sizeAll.cx, m_sizePage.cx, m_sizeLine.cx);\r
548                                 pT->UpdateWindow();\r
549                         }\r
550                 }\r
551                 m_zHDelta %= WHEEL_DELTA;\r
552 \r
553                 return 0;\r
554         }\r
555 \r
556         LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
557         {\r
558                 GetSystemSettings();\r
559                 return 0;\r
560         }\r
561 \r
562         LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\r
563         {\r
564                 T* pT = static_cast<T*>(this);\r
565                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
566 \r
567                 m_sizeClient.cx = GET_X_LPARAM(lParam);\r
568                 m_sizeClient.cy = GET_Y_LPARAM(lParam);\r
569 \r
570                 // block: set horizontal scroll bar\r
571                 {\r
572                         SCROLLINFO si = { sizeof(SCROLLINFO) };\r
573                         si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;\r
574                         si.nMin = 0;\r
575                         si.nMax = m_sizeAll.cx - 1;\r
576                         if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLH) != 0)\r
577                                 si.fMask |= SIF_DISABLENOSCROLL;\r
578                         si.nPage = m_sizeClient.cx;\r
579                         si.nPos = m_ptOffset.x;\r
580                         pT->SetScrollInfo(SB_HORZ, &si, TRUE);\r
581                 }\r
582 \r
583                 // block: set vertical scroll bar\r
584                 {\r
585                         SCROLLINFO si = { sizeof(SCROLLINFO) };\r
586                         si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;\r
587                         si.nMin = 0;\r
588                         si.nMax = m_sizeAll.cy - 1;\r
589                         if((m_dwExtendedStyle & SCRL_DISABLENOSCROLLV) != 0)\r
590                                 si.fMask |= SIF_DISABLENOSCROLL;\r
591                         si.nPage = m_sizeClient.cy;\r
592                         si.nPos = m_ptOffset.y;\r
593                         pT->SetScrollInfo(SB_VERT, &si, TRUE);\r
594                 }\r
595 \r
596                 int x = m_ptOffset.x;\r
597                 int y = m_ptOffset.y;\r
598                 if(pT->AdjustScrollOffset(x, y))\r
599                 {\r
600                         // Children will be moved in SetScrollOffset, if needed\r
601                         pT->ScrollWindowEx(m_ptOffset.x - x, m_ptOffset.y - y, (m_uScrollFlags & ~SCRL_SCROLLCHILDREN));\r
602                         SetScrollOffset(x, y, FALSE);\r
603                 }\r
604 \r
605                 bHandled = FALSE;\r
606                 return 1;\r
607         }\r
608 \r
609         LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
610         {\r
611                 T* pT = static_cast<T*>(this);\r
612                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
613                 if(wParam != NULL)\r
614                 {\r
615                         CDCHandle dc = (HDC)wParam;\r
616                         POINT ptViewportOrg = { 0, 0 };\r
617                         dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);\r
618                         pT->DoPaint(dc);\r
619                         dc.SetViewportOrg(ptViewportOrg);\r
620                 }\r
621                 else\r
622                 {\r
623                         CPaintDC dc(pT->m_hWnd);\r
624                         dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);\r
625                         pT->DoPaint(dc.m_hDC);\r
626                 }\r
627                 return 0;\r
628         }\r
629 \r
630         // scrolling handlers\r
631         LRESULT OnScrollUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
632         {\r
633                 ScrollLineUp();\r
634                 return 0;\r
635         }\r
636 \r
637         LRESULT OnScrollDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
638         {\r
639                 ScrollLineDown();\r
640                 return 0;\r
641         }\r
642 \r
643         LRESULT OnScrollPageUp(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
644         {\r
645                 ScrollPageUp();\r
646                 return 0;\r
647         }\r
648 \r
649         LRESULT OnScrollPageDown(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
650         {\r
651                 ScrollPageDown();\r
652                 return 0;\r
653         }\r
654 \r
655         LRESULT OnScrollTop(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
656         {\r
657                 ScrollTop();\r
658                 return 0;\r
659         }\r
660 \r
661         LRESULT OnScrollBottom(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
662         {\r
663                 ScrollBottom();\r
664                 return 0;\r
665         }\r
666 \r
667         LRESULT OnScrollLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
668         {\r
669                 ScrollLineLeft();\r
670                 return 0;\r
671         }\r
672 \r
673         LRESULT OnScrollRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
674         {\r
675                 ScrollLineRight();\r
676                 return 0;\r
677         }\r
678 \r
679         LRESULT OnScrollPageLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
680         {\r
681                 ScrollPageLeft();\r
682                 return 0;\r
683         }\r
684 \r
685         LRESULT OnScrollPageRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
686         {\r
687                 ScrollPageRight();\r
688                 return 0;\r
689         }\r
690 \r
691         LRESULT OnScrollAllLeft(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
692         {\r
693                 ScrollAllLeft();\r
694                 return 0;\r
695         }\r
696 \r
697         LRESULT OnScrollAllRight(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)\r
698         {\r
699                 ScrollAllRight();\r
700                 return 0;\r
701         }\r
702 \r
703 // Overrideables\r
704         void DoPaint(CDCHandle /*dc*/)\r
705         {\r
706                 // must be implemented in a derived class\r
707                 ATLASSERT(FALSE);\r
708         }\r
709 \r
710 // Implementation\r
711         void DoScroll(int nType, int nScrollCode, int& cxyOffset, int cxySizeAll, int cxySizePage, int cxySizeLine)\r
712         {\r
713                 T* pT = static_cast<T*>(this);\r
714                 RECT rect = { 0 };\r
715                 pT->GetClientRect(&rect);\r
716                 int cxyClient = (nType == SB_VERT) ? rect.bottom : rect.right;\r
717                 int cxyMax = cxySizeAll - cxyClient;\r
718 \r
719                 if(cxyMax < 0)   // can't scroll, client area is bigger\r
720                         return;\r
721 \r
722                 bool bUpdate = true;\r
723                 int cxyScroll = 0;\r
724 \r
725                 switch(nScrollCode)\r
726                 {\r
727                 case SB_TOP:            // top or all left\r
728                         cxyScroll = cxyOffset;\r
729                         cxyOffset = 0;\r
730                         break;\r
731                 case SB_BOTTOM:         // bottom or all right\r
732                         cxyScroll = cxyOffset - cxyMax;\r
733                         cxyOffset = cxyMax;\r
734                         break;\r
735                 case SB_LINEUP:         // line up or line left\r
736                         if(cxyOffset >= cxySizeLine)\r
737                         {\r
738                                 cxyScroll = cxySizeLine;\r
739                                 cxyOffset -= cxySizeLine;\r
740                         }\r
741                         else\r
742                         {\r
743                                 cxyScroll = cxyOffset;\r
744                                 cxyOffset = 0;\r
745                         }\r
746                         break;\r
747                 case SB_LINEDOWN:       // line down or line right\r
748                         if(cxyOffset < cxyMax - cxySizeLine)\r
749                         {\r
750                                 cxyScroll = -cxySizeLine;\r
751                                 cxyOffset += cxySizeLine;\r
752                         }\r
753                         else\r
754                         {\r
755                                 cxyScroll = cxyOffset - cxyMax;\r
756                                 cxyOffset = cxyMax;\r
757                         }\r
758                         break;\r
759                 case SB_PAGEUP:         // page up or page left\r
760                         if(cxyOffset >= cxySizePage)\r
761                         {\r
762                                 cxyScroll = cxySizePage;\r
763                                 cxyOffset -= cxySizePage;\r
764                         }\r
765                         else\r
766                         {\r
767                                 cxyScroll = cxyOffset;\r
768                                 cxyOffset = 0;\r
769                         }\r
770                         break;\r
771                 case SB_PAGEDOWN:       // page down or page right\r
772                         if(cxyOffset < cxyMax - cxySizePage)\r
773                         {\r
774                                 cxyScroll = -cxySizePage;\r
775                                 cxyOffset += cxySizePage;\r
776                         }\r
777                         else\r
778                         {\r
779                                 cxyScroll = cxyOffset - cxyMax;\r
780                                 cxyOffset = cxyMax;\r
781                         }\r
782                         break;\r
783                 case SB_THUMBTRACK:\r
784                         if(IsNoThumbTracking())\r
785                                 break;\r
786                         // else fall through\r
787                 case SB_THUMBPOSITION:\r
788                         {\r
789                                 SCROLLINFO si = { sizeof(SCROLLINFO), SIF_TRACKPOS };\r
790                                 if(pT->GetScrollInfo(nType, &si))\r
791                                 {\r
792                                         cxyScroll = cxyOffset - si.nTrackPos;\r
793                                         cxyOffset = si.nTrackPos;\r
794                                 }\r
795                         }\r
796                         break;\r
797                 case SB_ENDSCROLL:\r
798                 default:\r
799                         bUpdate = false;\r
800                         break;\r
801                 }\r
802 \r
803                 if(bUpdate && cxyScroll != 0)\r
804                 {\r
805                         pT->SetScrollPos(nType, cxyOffset, TRUE);\r
806                         if(nType == SB_VERT)\r
807                                 pT->ScrollWindowEx(0, cxyScroll, m_uScrollFlags);\r
808                         else\r
809                                 pT->ScrollWindowEx(cxyScroll, 0, m_uScrollFlags);\r
810                 }\r
811         }\r
812 \r
813         static int CalcLineOrPage(int nVal, int nMax, int nDiv)\r
814         {\r
815                 if(nVal == 0)\r
816                 {\r
817                         nVal = nMax / nDiv;\r
818                         if(nVal < 1)\r
819                                 nVal = 1;\r
820                 }\r
821                 else if(nVal > nMax)\r
822                 {\r
823                         nVal = nMax;\r
824                 }\r
825 \r
826                 return nVal;\r
827         }\r
828 \r
829         bool AdjustScrollOffset(int& x, int& y)\r
830         {\r
831                 int xOld = x;\r
832                 int yOld = y;\r
833 \r
834                 int cxMax = m_sizeAll.cx - m_sizeClient.cx;\r
835                 if(x > cxMax)\r
836                         x = (cxMax >= 0) ? cxMax : 0;\r
837                 else if(x < 0)\r
838                         x = 0;\r
839 \r
840                 int cyMax = m_sizeAll.cy - m_sizeClient.cy;\r
841                 if(y > cyMax)\r
842                         y = (cyMax >= 0) ? cyMax : 0;\r
843                 else if(y < 0)\r
844                         y = 0;\r
845 \r
846                 return (x != xOld || y != yOld);\r
847         }\r
848 \r
849         void GetSystemSettings()\r
850         {\r
851 #ifndef _WIN32_WCE\r
852 #ifndef SPI_GETWHEELSCROLLLINES\r
853                 const UINT SPI_GETWHEELSCROLLLINES = 104;\r
854 #endif // !SPI_GETWHEELSCROLLLINES\r
855                 ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &m_nWheelLines, 0);\r
856 \r
857 #ifndef SPI_GETWHEELSCROLLCHARS\r
858                 const UINT SPI_GETWHEELSCROLLCHARS = 0x006C;\r
859 #endif // !SPI_GETWHEELSCROLLCHARS\r
860                 ::SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &m_nHWheelChars, 0);\r
861 \r
862 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\r
863                 if(m_uMsgMouseWheel != 0)\r
864                         m_uMsgMouseWheel = ::RegisterWindowMessage(MSH_MOUSEWHEEL);\r
865 \r
866                 HWND hWndWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);\r
867                 if(::IsWindow(hWndWheel))\r
868                 {\r
869                         UINT uMsgScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES);\r
870                         if(uMsgScrollLines != 0)\r
871                                 m_nWheelLines = (int)::SendMessage(hWndWheel, uMsgScrollLines, 0, 0L);\r
872                 }\r
873 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\r
874 #endif // !_WIN32_WCE\r
875         }\r
876 \r
877         bool IsScrollingChildren() const\r
878         {\r
879                 return (m_dwExtendedStyle & SCRL_SCROLLCHILDREN) != 0;\r
880         }\r
881 \r
882         bool IsErasingBackground() const\r
883         {\r
884                 return (m_dwExtendedStyle & SCRL_ERASEBACKGROUND) != 0;\r
885         }\r
886 \r
887         bool IsNoThumbTracking() const\r
888         {\r
889                 return (m_dwExtendedStyle & SCRL_NOTHUMBTRACKING) != 0;\r
890         }\r
891 \r
892 #if (WINVER >= 0x0500)\r
893         bool IsSmoothScroll() const\r
894         {\r
895                 return (m_dwExtendedStyle & SCRL_SMOOTHSCROLL) != 0;\r
896         }\r
897 #endif // (WINVER >= 0x0500)\r
898 };\r
899 \r
900 \r
901 ///////////////////////////////////////////////////////////////////////////////\r
902 // CScrollWindowImpl - Implements a scrollable window\r
903 \r
904 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\r
905 class ATL_NO_VTABLE CScrollWindowImpl : public ATL::CWindowImpl<T, TBase, TWinTraits>, public CScrollImpl< T >\r
906 {\r
907 public:\r
908         BEGIN_MSG_MAP(CScrollWindowImpl)\r
909                 MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\r
910                 MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\r
911                 MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\r
912 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\r
913                 MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\r
914 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400)) && !defined(_WIN32_WCE)\r
915                 MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\r
916                 MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\r
917                 MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)\r
918                 MESSAGE_HANDLER(WM_PAINT, CScrollImpl< T >::OnPaint)\r
919 #ifndef _WIN32_WCE\r
920                 MESSAGE_HANDLER(WM_PRINTCLIENT, CScrollImpl< T >::OnPaint)\r
921 #endif // !_WIN32_WCE\r
922         ALT_MSG_MAP(1)\r
923                 COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\r
924                 COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\r
925                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\r
926                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\r
927                 COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\r
928                 COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\r
929                 COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\r
930                 COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\r
931                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\r
932                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\r
933                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\r
934                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\r
935         END_MSG_MAP()\r
936 };\r
937 \r
938 \r
939 ///////////////////////////////////////////////////////////////////////////////\r
940 // CMapScrollImpl - Provides mapping and scrolling support to any window\r
941 \r
942 #ifndef _WIN32_WCE\r
943 \r
944 template <class T>\r
945 class CMapScrollImpl : public CScrollImpl< T >\r
946 {\r
947 public:\r
948         int m_nMapMode;\r
949         RECT m_rectLogAll;\r
950         SIZE m_sizeLogLine;\r
951         SIZE m_sizeLogPage;\r
952 \r
953 // Constructor\r
954         CMapScrollImpl() : m_nMapMode(MM_TEXT)\r
955         {\r
956                 ::SetRectEmpty(&m_rectLogAll);\r
957                 m_sizeLogPage.cx = 0;\r
958                 m_sizeLogPage.cy = 0;\r
959                 m_sizeLogLine.cx = 0;\r
960                 m_sizeLogLine.cy = 0;\r
961         }\r
962 \r
963 // Attributes & Operations\r
964         // mapping mode operations\r
965         void SetScrollMapMode(int nMapMode)\r
966         {\r
967                 ATLASSERT(nMapMode >= MM_MIN && nMapMode <= MM_MAX_FIXEDSCALE);\r
968                 m_nMapMode = nMapMode;\r
969         }\r
970 \r
971         int GetScrollMapMode() const\r
972         {\r
973                 ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\r
974                 return m_nMapMode;\r
975         }\r
976 \r
977         // offset operations\r
978         void SetScrollOffset(int x, int y, BOOL bRedraw = TRUE)\r
979         {\r
980                 ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\r
981                 POINT ptOff = { x, y };\r
982                 // block: convert logical to device units\r
983                 {\r
984                         CWindowDC dc(NULL);\r
985                         dc.SetMapMode(m_nMapMode);\r
986                         dc.LPtoDP(&ptOff);\r
987                 }\r
988                 CScrollImpl< T >::SetScrollOffset(ptOff, bRedraw);\r
989         }\r
990 \r
991         void SetScrollOffset(POINT ptOffset, BOOL bRedraw = TRUE)\r
992         {\r
993                 SetScrollOffset(ptOffset.x, ptOffset.y, bRedraw);\r
994         }\r
995 \r
996         void GetScrollOffset(POINT& ptOffset) const\r
997         {\r
998                 ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\r
999                 ptOffset = m_ptOffset;\r
1000                 // block: convert device to logical units\r
1001                 {\r
1002                         CWindowDC dc(NULL);\r
1003                         dc.SetMapMode(m_nMapMode);\r
1004                         dc.DPtoLP(&ptOffset);\r
1005                 }\r
1006         }\r
1007 \r
1008         // size operations\r
1009         void SetScrollSize(int xMin, int yMin, int xMax, int yMax, BOOL bRedraw = TRUE, bool bResetOffset = true)\r
1010         {\r
1011                 ATLASSERT(xMax > xMin && yMax > yMin);\r
1012                 ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\r
1013 \r
1014                 ::SetRect(&m_rectLogAll, xMin, yMin, xMax, yMax);\r
1015 \r
1016                 SIZE sizeAll = { 0 };\r
1017                 sizeAll.cx = xMax - xMin + 1;\r
1018                 sizeAll.cy = yMax - yMin + 1;\r
1019                 // block: convert logical to device units\r
1020                 {\r
1021                         CWindowDC dc(NULL);\r
1022                         dc.SetMapMode(m_nMapMode);\r
1023                         dc.LPtoDP(&sizeAll);\r
1024                 }\r
1025                 CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset);\r
1026                 SetScrollLine(0, 0);\r
1027                 SetScrollPage(0, 0);\r
1028         }\r
1029 \r
1030         void SetScrollSize(RECT& rcScroll, BOOL bRedraw = TRUE, bool bResetOffset = true)\r
1031         {\r
1032                 SetScrollSize(rcScroll.left, rcScroll.top, rcScroll.right, rcScroll.bottom, bRedraw, bResetOffset);\r
1033         }\r
1034 \r
1035         void SetScrollSize(int cx, int cy, BOOL bRedraw = TRUE, bool bResetOffset = true)\r
1036         {\r
1037                 SetScrollSize(0, 0, cx, cy, bRedraw, bResetOffset);\r
1038         }\r
1039 \r
1040         void SetScrollSize(SIZE size, BOOL bRedraw = TRUE, bool bResetOffset = true)\r
1041         {\r
1042                 SetScrollSize(0, 0, size.cx, size.cy, bRedraw, bResetOffset);\r
1043         }\r
1044 \r
1045         void GetScrollSize(RECT& rcScroll) const\r
1046         {\r
1047                 ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\r
1048                 rcScroll = m_rectLogAll;\r
1049         }\r
1050 \r
1051         // line operations\r
1052         void SetScrollLine(int cxLine, int cyLine)\r
1053         {\r
1054                 ATLASSERT(cxLine >= 0 && cyLine >= 0);\r
1055                 ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\r
1056 \r
1057                 m_sizeLogLine.cx = cxLine;\r
1058                 m_sizeLogLine.cy = cyLine;\r
1059                 SIZE sizeLine = m_sizeLogLine;\r
1060                 // block: convert logical to device units\r
1061                 {\r
1062                         CWindowDC dc(NULL);\r
1063                         dc.SetMapMode(m_nMapMode);\r
1064                         dc.LPtoDP(&sizeLine);\r
1065                 }\r
1066                 CScrollImpl< T >::SetScrollLine(sizeLine);\r
1067         }\r
1068 \r
1069         void SetScrollLine(SIZE sizeLine)\r
1070         {\r
1071                 SetScrollLine(sizeLine.cx, sizeLine.cy);\r
1072         }\r
1073 \r
1074         void GetScrollLine(SIZE& sizeLine) const\r
1075         {\r
1076                 ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\r
1077                 sizeLine = m_sizeLogLine;\r
1078         }\r
1079 \r
1080         // page operations\r
1081         void SetScrollPage(int cxPage, int cyPage)\r
1082         {\r
1083                 ATLASSERT(cxPage >= 0 && cyPage >= 0);\r
1084                 ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\r
1085 \r
1086                 m_sizeLogPage.cx = cxPage;\r
1087                 m_sizeLogPage.cy = cyPage;\r
1088                 SIZE sizePage = m_sizeLogPage;\r
1089                 // block: convert logical to device units\r
1090                 {\r
1091                         CWindowDC dc(NULL);\r
1092                         dc.SetMapMode(m_nMapMode);\r
1093                         dc.LPtoDP(&sizePage);\r
1094                 }\r
1095                 CScrollImpl< T >::SetScrollPage(sizePage);\r
1096         }\r
1097 \r
1098         void SetScrollPage(SIZE sizePage)\r
1099         {\r
1100                 SetScrollPage(sizePage.cx, sizePage.cy);\r
1101         }\r
1102 \r
1103         void GetScrollPage(SIZE& sizePage) const\r
1104         {\r
1105                 ATLASSERT(m_nMapMode >= MM_MIN && m_nMapMode <= MM_MAX_FIXEDSCALE);\r
1106                 sizePage = m_sizeLogPage;\r
1107         }\r
1108 \r
1109         BEGIN_MSG_MAP(CMapScrollImpl)\r
1110                 MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\r
1111                 MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\r
1112                 MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\r
1113 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\r
1114                 MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\r
1115 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\r
1116                 MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\r
1117                 MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\r
1118                 MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)\r
1119                 MESSAGE_HANDLER(WM_PAINT, OnPaint)\r
1120                 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\r
1121         ALT_MSG_MAP(1)\r
1122                 COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\r
1123                 COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\r
1124                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\r
1125                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\r
1126                 COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\r
1127                 COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\r
1128                 COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\r
1129                 COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\r
1130                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\r
1131                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\r
1132                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\r
1133                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\r
1134         END_MSG_MAP()\r
1135 \r
1136         LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
1137         {\r
1138                 T* pT = static_cast<T*>(this);\r
1139                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
1140                 if(wParam != NULL)\r
1141                 {\r
1142                         CDCHandle dc = (HDC)wParam;\r
1143                         int nMapModeSav = dc.GetMapMode();\r
1144                         dc.SetMapMode(m_nMapMode);\r
1145                         POINT ptViewportOrg = { 0, 0 };\r
1146                         if(m_nMapMode == MM_TEXT)\r
1147                                 dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);\r
1148                         else\r
1149                                 dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy, &ptViewportOrg);\r
1150                         POINT ptWindowOrg = { 0, 0 };\r
1151                         dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top, &ptWindowOrg);\r
1152 \r
1153                         pT->DoPaint(dc);\r
1154 \r
1155                         dc.SetMapMode(nMapModeSav);\r
1156                         dc.SetViewportOrg(ptViewportOrg);\r
1157                         dc.SetWindowOrg(ptWindowOrg);\r
1158                 }\r
1159                 else\r
1160                 {\r
1161                         CPaintDC dc(pT->m_hWnd);\r
1162                         dc.SetMapMode(m_nMapMode);\r
1163                         if(m_nMapMode == MM_TEXT)\r
1164                                 dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);\r
1165                         else\r
1166                                 dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y + m_sizeAll.cy);\r
1167                         dc.SetWindowOrg(m_rectLogAll.left, m_rectLogAll.top);\r
1168                         pT->DoPaint(dc.m_hDC);\r
1169                 }\r
1170                 return 0;\r
1171         }\r
1172 };\r
1173 \r
1174 #endif // !_WIN32_WCE\r
1175 \r
1176 \r
1177 ///////////////////////////////////////////////////////////////////////////////\r
1178 // CMapScrollWindowImpl - Implements scrolling window with mapping\r
1179 \r
1180 #ifndef _WIN32_WCE\r
1181 \r
1182 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\r
1183 class ATL_NO_VTABLE CMapScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CMapScrollImpl< T >\r
1184 {\r
1185 public:\r
1186         BEGIN_MSG_MAP(CMapScrollWindowImpl)\r
1187                 MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\r
1188                 MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\r
1189                 MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\r
1190 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\r
1191                 MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\r
1192 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\r
1193                 MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\r
1194                 MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\r
1195                 MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)\r
1196                 MESSAGE_HANDLER(WM_PAINT, CMapScrollImpl< T >::OnPaint)\r
1197                 MESSAGE_HANDLER(WM_PRINTCLIENT, CMapScrollImpl< T >::OnPaint)\r
1198         ALT_MSG_MAP(1)\r
1199                 COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\r
1200                 COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\r
1201                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\r
1202                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\r
1203                 COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\r
1204                 COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\r
1205                 COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\r
1206                 COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\r
1207                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\r
1208                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\r
1209                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\r
1210                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\r
1211         END_MSG_MAP()\r
1212 };\r
1213 \r
1214 #endif // !_WIN32_WCE\r
1215 \r
1216 \r
1217 ///////////////////////////////////////////////////////////////////////////////\r
1218 // CFSBWindow - Use as a base instead of CWindow to get flat scroll bar support\r
1219 \r
1220 #if defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\r
1221 \r
1222 template <class TBase = ATL::CWindow>\r
1223 class CFSBWindowT : public TBase, public CFlatScrollBarImpl<CFSBWindowT< TBase > >\r
1224 {\r
1225 public:\r
1226 // Constructors\r
1227         CFSBWindowT(HWND hWnd = NULL) : TBase(hWnd)\r
1228         { }\r
1229 \r
1230         CFSBWindowT< TBase >& operator =(HWND hWnd)\r
1231         {\r
1232                 m_hWnd = hWnd;\r
1233                 return *this;\r
1234         }\r
1235 \r
1236 // CWindow overrides that use flat scroll bar API\r
1237 // (only those methods that are used by scroll window classes)\r
1238         int SetScrollPos(int nBar, int nPos, BOOL bRedraw = TRUE)\r
1239         {\r
1240                 ATLASSERT(::IsWindow(m_hWnd));\r
1241                 return FlatSB_SetScrollPos(nBar, nPos, bRedraw);\r
1242         }\r
1243 \r
1244         BOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo)\r
1245         {\r
1246                 ATLASSERT(::IsWindow(m_hWnd));\r
1247                 return FlatSB_GetScrollInfo(nBar, lpScrollInfo);\r
1248         }\r
1249 \r
1250         BOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE)\r
1251         {\r
1252                 ATLASSERT(::IsWindow(m_hWnd));\r
1253                 return FlatSB_SetScrollInfo(nBar, lpScrollInfo, bRedraw);\r
1254         }\r
1255 };\r
1256 \r
1257 typedef CFSBWindowT<ATL::CWindow>   CFSBWindow;\r
1258 \r
1259 #endif // defined(__ATLCTRLS_H__) && (_WIN32_IE >= 0x0400) && !defined(_WIN32_WCE)\r
1260 \r
1261 \r
1262 ///////////////////////////////////////////////////////////////////////////////\r
1263 // CZoomScrollImpl - Provides zooming and scrolling support to any window\r
1264 \r
1265 #ifndef _WIN32_WCE\r
1266 \r
1267 // The zoom modes that can be set with the SetZoomMode method\r
1268 enum\r
1269 {\r
1270         ZOOMMODE_OFF, \r
1271         ZOOMMODE_IN,   // If left mouse button is clicked or dragged, zoom in on point clicked or rectangle dragged.\r
1272         ZOOMMODE_OUT   // If left mouse button clicked, zoom out on point clicked.\r
1273 };\r
1274 \r
1275 // Notification to parent that zoom scale changed as a result of user mouse action.\r
1276 #define ZSN_ZOOMCHANGED (NM_FIRST - 50) \r
1277 \r
1278 template <class T>\r
1279 class CZoomScrollImpl : public CScrollImpl< T >\r
1280 {\r
1281 public:\r
1282         enum { m_cxyMinZoomRect = 12 };   // min rect size to zoom in on rect.\r
1283 \r
1284 // Data members\r
1285         SIZE m_sizeLogAll;              \r
1286         SIZE m_sizeLogLine;     \r
1287         SIZE m_sizeLogPage;\r
1288         float m_fZoomScale;\r
1289         float m_fZoomScaleMin;\r
1290         float m_fZoomDelta;   // Used in ZOOMMODE_IN and ZOOMMODE_OUT on left-button click.\r
1291         int m_nZoomMode;                \r
1292         RECT m_rcTrack;\r
1293         bool m_bTracking;\r
1294 \r
1295 // Constructor\r
1296         CZoomScrollImpl():\r
1297                         m_fZoomScale(1.0),\r
1298                         m_fZoomScaleMin(0.5),\r
1299                         m_fZoomDelta(0.5),\r
1300                         m_nZoomMode(ZOOMMODE_OFF),\r
1301                         m_bTracking(false)\r
1302         {\r
1303                 m_sizeLogAll.cx = 0;\r
1304                 m_sizeLogAll.cy = 0;\r
1305                 m_sizeLogPage.cx = 0;\r
1306                 m_sizeLogPage.cy = 0;\r
1307                 m_sizeLogLine.cx = 0;\r
1308                 m_sizeLogLine.cy = 0;\r
1309                 ::SetRectEmpty(&m_rcTrack);\r
1310         }\r
1311 \r
1312 // Attributes & Operations\r
1313 \r
1314         // size operations\r
1315         void SetScrollSize(int cxLog, int cyLog, BOOL bRedraw = TRUE, bool bResetOffset = true)\r
1316         {\r
1317                 ATLASSERT(cxLog >= 0 && cyLog >= 0);\r
1318 \r
1319                 // Set up the defaults\r
1320                 if (cxLog == 0 && cyLog == 0)\r
1321                 {\r
1322                         cxLog = 1;\r
1323                         cyLog = 1;\r
1324                 }\r
1325 \r
1326                 m_sizeLogAll.cx = cxLog;\r
1327                 m_sizeLogAll.cy = cyLog;\r
1328                 SIZE sizeAll = { 0 };\r
1329                 sizeAll.cx = (int)((float)m_sizeLogAll.cx * m_fZoomScale);\r
1330                 sizeAll.cy = (int)((float)m_sizeLogAll.cy * m_fZoomScale);\r
1331 \r
1332                 CScrollImpl< T >::SetScrollSize(sizeAll, bRedraw, bResetOffset);\r
1333         }\r
1334 \r
1335         void SetScrollSize(SIZE sizeLog, BOOL bRedraw = TRUE, bool bResetOffset = true)\r
1336         {\r
1337                 SetScrollSize(sizeLog.cx, sizeLog.cy, bRedraw, bResetOffset);\r
1338         }\r
1339 \r
1340         void GetScrollSize(SIZE& sizeLog) const\r
1341         {\r
1342                 sizeLog = m_sizeLogAll;\r
1343         }\r
1344 \r
1345         // line operations\r
1346         void SetScrollLine(int cxLogLine, int cyLogLine)\r
1347         {\r
1348                 ATLASSERT(cxLogLine >= 0 && cyLogLine >= 0);\r
1349 \r
1350                 m_sizeLogLine.cx = cxLogLine;\r
1351                 m_sizeLogLine.cy = cyLogLine;\r
1352 \r
1353                 SIZE sizeLine = { 0 };\r
1354                 sizeLine.cx = (int)((float)m_sizeLogLine.cx * m_fZoomScale);\r
1355                 sizeLine.cy = (int)((float)m_sizeLogLine.cy * m_fZoomScale);\r
1356                 CScrollImpl< T >::SetScrollLine(sizeLine);\r
1357         }\r
1358 \r
1359         void SetScrollLine(SIZE sizeLogLine)\r
1360         {\r
1361                 SetScrollLine(sizeLogLine.cx, sizeLogLine.cy);\r
1362         }\r
1363 \r
1364         void GetScrollLine(SIZE& sizeLogLine) const\r
1365         {\r
1366                 sizeLogLine = m_sizeLogLine;\r
1367         }\r
1368 \r
1369         // page operations\r
1370         void SetScrollPage(int cxLogPage, int cyLogPage)\r
1371         {\r
1372                 ATLASSERT(cxLogPage >= 0 && cyLogPage >= 0);\r
1373 \r
1374                 m_sizeLogPage.cx = cxLogPage;\r
1375                 m_sizeLogPage.cy = cyLogPage;\r
1376 \r
1377                 SIZE sizePage = { 0 };\r
1378                 sizePage.cx = (int)((float)m_sizeLogPage.cx * m_fZoomScale);\r
1379                 sizePage.cy = (int)((float)m_sizeLogPage.cy * m_fZoomScale);\r
1380 \r
1381                 CScrollImpl< T >::SetScrollPage(sizePage);\r
1382         }\r
1383 \r
1384         void SetScrollPage(SIZE sizeLogPage)\r
1385         {\r
1386                 SetScrollPage(sizeLogPage.cx, sizeLogPage.cy);\r
1387         }\r
1388 \r
1389         void GetScrollPage(SIZE& sizeLogPage) const\r
1390         {\r
1391                 sizeLogPage = m_sizeLogPage;\r
1392         }\r
1393 \r
1394         void SetZoomScale(float fZoomScale)\r
1395         {\r
1396                 ATLASSERT(fZoomScale > 0);\r
1397 \r
1398                 if(fZoomScale > 0 && fZoomScale >= m_fZoomScaleMin)\r
1399                         m_fZoomScale = fZoomScale;\r
1400         }\r
1401 \r
1402         float GetZoomScale() const\r
1403         {\r
1404                 return m_fZoomScale;\r
1405         }\r
1406 \r
1407         void SetZoomScaleMin(float fZoomScaleMin)\r
1408         {\r
1409                 m_fZoomScaleMin = fZoomScaleMin;\r
1410         }\r
1411 \r
1412         float GetZoomScaleMin() const\r
1413         {\r
1414                 return m_fZoomScaleMin;\r
1415         }\r
1416 \r
1417         void SetZoomDelta(float fZoomDelta)\r
1418         {\r
1419                 ATLASSERT(fZoomDelta >= 0);\r
1420 \r
1421                 if(fZoomDelta >= 0)\r
1422                         m_fZoomDelta = fZoomDelta;\r
1423         }\r
1424 \r
1425         float GetZoomDelta() const\r
1426         {\r
1427                 return m_fZoomDelta;\r
1428         }\r
1429 \r
1430         void SetZoomMode(int nZoomMode)\r
1431         {\r
1432                 m_nZoomMode = nZoomMode;\r
1433         }\r
1434 \r
1435         int GetZoomMode() const\r
1436         {\r
1437                 return m_nZoomMode;\r
1438         }\r
1439 \r
1440         void Zoom(int x, int y, float fZoomScale)\r
1441         {\r
1442                 if(fZoomScale <= 0)\r
1443                         return;\r
1444 \r
1445                 fZoomScale = max(fZoomScale, m_fZoomScaleMin);\r
1446 \r
1447                 T* pT = static_cast<T*>(this);\r
1448                 POINT pt = { x, y };\r
1449                 if(!pT->PtInDevRect(pt))\r
1450                         return;\r
1451 \r
1452                 pT->ViewDPtoLP(&pt);\r
1453                 pT->Zoom(fZoomScale, false);\r
1454                 pT->CenterOnLogicalPoint(pt);\r
1455         }\r
1456 \r
1457         void Zoom(POINT pt, float fZoomScale)\r
1458         {\r
1459                 T* pT = static_cast<T*>(this);\r
1460                 pT->Zoom(pt.x, pt.y, fZoomScale);\r
1461         }\r
1462 \r
1463         void Zoom(RECT& rc)\r
1464         {\r
1465                 T* pT = static_cast<T*>(this);\r
1466                 RECT rcZoom = rc;\r
1467                 pT->NormalizeRect(rcZoom);\r
1468                 SIZE size = { rcZoom.right - rcZoom.left, rcZoom.bottom - rcZoom.top };\r
1469                 POINT pt = { rcZoom.left + size.cx / 2, rcZoom.top + size.cy / 2 };\r
1470                 if(size.cx < m_cxyMinZoomRect || size.cy < m_cxyMinZoomRect)\r
1471                 {\r
1472                         pT->Zoom(pt, m_fZoomScale + m_fZoomDelta);\r
1473                         return;\r
1474                 }\r
1475 \r
1476                 ATLASSERT(size.cx > 0 && size.cy > 0);\r
1477                 \r
1478                 float fScaleH = (float)(m_sizeClient.cx  + 1) / (float)size.cx;\r
1479                 float fScaleV = (float)(m_sizeClient.cy + 1) / (float)size.cy;\r
1480                 float fZoomScale = min(fScaleH, fScaleV) * m_fZoomScale;\r
1481                 pT->Zoom(pt, fZoomScale);               \r
1482         }\r
1483 \r
1484         void Zoom(float fZoomScale, bool bCenter = true)\r
1485         {\r
1486                 if(fZoomScale <= 0)\r
1487                         return;\r
1488 \r
1489                 fZoomScale = max(fZoomScale, m_fZoomScaleMin);\r
1490 \r
1491 \r
1492                 T* pT = static_cast<T*>(this);\r
1493                 POINT pt = { 0 };\r
1494                 if(bCenter)\r
1495                 {\r
1496                         RECT rc;\r
1497                         ::GetClientRect(pT->m_hWnd, &rc);\r
1498                         pt.x = rc.right / 2;\r
1499                         pt.y = rc.bottom / 2;\r
1500                         pT->ViewDPtoLP(&pt);\r
1501                 }\r
1502 \r
1503                 // Modify the Viewport extent\r
1504                 m_fZoomScale = fZoomScale;\r
1505                 SIZE sizeAll = { 0 };\r
1506                 sizeAll.cx = (int)((float)m_sizeLogAll.cx * fZoomScale);\r
1507                 sizeAll.cy = (int)((float)m_sizeLogAll.cy * fZoomScale);\r
1508                 \r
1509                 // Update scroll bars and window\r
1510                 CScrollImpl< T >::SetScrollSize(sizeAll);\r
1511 \r
1512                 if(bCenter)\r
1513                         pT->CenterOnLogicalPoint(pt);\r
1514         }\r
1515 \r
1516         // Helper functions\r
1517         void PrepareDC(CDCHandle dc)\r
1518         {\r
1519                 ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0);\r
1520                 dc.SetMapMode(MM_ANISOTROPIC);\r
1521                 dc.SetWindowExt(m_sizeLogAll);\r
1522                 dc.SetViewportExt(m_sizeAll);\r
1523                 dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y);\r
1524         }\r
1525 \r
1526         void ViewDPtoLP(LPPOINT lpPoints, int nCount = 1)\r
1527         {\r
1528                 ATLASSERT(lpPoints);\r
1529                 T* pT = static_cast<T*>(this);\r
1530                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
1531 \r
1532                 CWindowDC dc(pT->m_hWnd);\r
1533                 pT->PrepareDC(dc.m_hDC);\r
1534                 dc.DPtoLP(lpPoints, nCount);\r
1535         }\r
1536 \r
1537         void ViewLPtoDP(LPPOINT lpPoints, int nCount = 1)\r
1538         {\r
1539                 ATLASSERT(lpPoints);\r
1540                 T* pT = static_cast<T*>(this);\r
1541                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
1542         \r
1543                 CWindowDC dc(pT->m_hWnd);\r
1544                 pT->PrepareDC(dc.m_hDC);\r
1545                 dc.LPtoDP(lpPoints, nCount);\r
1546         }\r
1547 \r
1548         void ClientToDevice(POINT &pt)\r
1549         {\r
1550                 pt.x += m_ptOffset.x;\r
1551                 pt.y += m_ptOffset.y;\r
1552         }        \r
1553 \r
1554         void DeviceToClient(POINT &pt)\r
1555         {\r
1556                 pt.x -= m_ptOffset.x;\r
1557                 pt.y -= m_ptOffset.y;\r
1558         }\r
1559 \r
1560         void CenterOnPoint(POINT pt)\r
1561         {\r
1562                 T* pT = static_cast<T*>(this);\r
1563                 RECT rect;\r
1564                 pT->GetClientRect(&rect);\r
1565 \r
1566                 int xOfs = pt.x - (rect.right / 2) + m_ptOffset.x;\r
1567                 if(xOfs < 0)\r
1568                 {\r
1569                         xOfs = 0;\r
1570                 }\r
1571                 else \r
1572                 {\r
1573                         int xMax = max((int)(m_sizeAll.cx - rect.right), 0);\r
1574                         if(xOfs > xMax)\r
1575                                 xOfs = xMax;\r
1576                 }\r
1577                 \r
1578                 int yOfs = pt.y - (rect.bottom / 2) + m_ptOffset.y;\r
1579                 if(yOfs < 0)\r
1580                 {\r
1581                         yOfs = 0;\r
1582                 }\r
1583                 else \r
1584                 {\r
1585                         int yMax = max((int)(m_sizeAll.cy - rect.bottom), 0);\r
1586                         if(yOfs > yMax)\r
1587                                 yOfs = yMax;\r
1588                 }\r
1589 \r
1590                 CScrollImpl< T >::SetScrollOffset(xOfs, yOfs);\r
1591         }\r
1592 \r
1593         void CenterOnLogicalPoint(POINT ptLog)\r
1594         {\r
1595                 T* pT = static_cast<T*>(this);\r
1596                 pT->ViewLPtoDP(&ptLog);\r
1597                 pT->DeviceToClient(ptLog);\r
1598                 pT->CenterOnPoint(ptLog);\r
1599         }\r
1600 \r
1601         BOOL PtInDevRect(POINT pt)\r
1602         {\r
1603                 RECT rc = { 0, 0, m_sizeAll.cx, m_sizeAll.cy };\r
1604                 ::OffsetRect(&rc, -m_ptOffset.x, -m_ptOffset.y);\r
1605                 return ::PtInRect(&rc, pt);\r
1606         }\r
1607 \r
1608         void NormalizeRect(RECT& rc)\r
1609         {\r
1610                 if(rc.left > rc.right) \r
1611                 {\r
1612                         int r = rc.right;\r
1613                         rc.right = rc.left;\r
1614                         rc.left = r;\r
1615                 }\r
1616                 if(rc.top > rc.bottom)\r
1617                 {\r
1618                         int b = rc.bottom;\r
1619                         rc.bottom = rc.top;\r
1620                         rc.top = b;\r
1621                 }\r
1622         }\r
1623 \r
1624         void DrawTrackRect()\r
1625         {\r
1626                 T* pT = static_cast<T*>(this);\r
1627                 const SIZE sizeLines = { 2, 2 };\r
1628                 RECT rc = m_rcTrack;\r
1629                 pT->NormalizeRect(rc);\r
1630                 if(!::IsRectEmpty(&rc))\r
1631                 {\r
1632                         ::MapWindowPoints(pT->m_hWnd, NULL, (LPPOINT)&rc, 2);\r
1633                         CWindowDC dc(NULL);\r
1634                         dc.DrawDragRect(&rc, sizeLines, NULL, sizeLines);\r
1635                 }\r
1636         }\r
1637 \r
1638         void NotifyParentZoomChanged()\r
1639         {\r
1640                 T* pT = static_cast<T*>(this);\r
1641                 int nId = pT->GetDlgCtrlID();\r
1642                 NMHDR nmhdr = { pT->m_hWnd, nId, ZSN_ZOOMCHANGED };\r
1643                 ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nId, (LPARAM)&nmhdr);\r
1644         }\r
1645 \r
1646         BEGIN_MSG_MAP(CZoomScrollImpl)\r
1647                 MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)\r
1648                 MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\r
1649                 MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\r
1650                 MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\r
1651 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\r
1652                 MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\r
1653 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\r
1654                 MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\r
1655                 MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\r
1656                 MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)\r
1657                 MESSAGE_HANDLER(WM_PAINT, OnPaint)\r
1658                 MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)\r
1659                 MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)\r
1660                 MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)\r
1661                 MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)\r
1662                 MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)\r
1663         ALT_MSG_MAP(1)\r
1664                 COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\r
1665                 COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\r
1666                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\r
1667                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\r
1668                 COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\r
1669                 COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\r
1670                 COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\r
1671                 COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\r
1672                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\r
1673                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\r
1674                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\r
1675                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\r
1676         END_MSG_MAP()\r
1677 \r
1678         LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
1679         {\r
1680                 T* pT = static_cast<T*>(this);\r
1681                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
1682                 ATLASSERT(m_sizeLogAll.cx >= 0 && m_sizeLogAll.cy >= 0);\r
1683                 ATLASSERT(m_sizeAll.cx >= 0 && m_sizeAll.cy >= 0);\r
1684 \r
1685                 if(wParam != NULL)\r
1686                 {\r
1687                         CDCHandle dc = (HDC)wParam;\r
1688                         int nMapModeSav = dc.GetMapMode();\r
1689                         dc.SetMapMode(MM_ANISOTROPIC);\r
1690                         SIZE szWindowExt = { 0, 0 };\r
1691                         dc.SetWindowExt(m_sizeLogAll, &szWindowExt);\r
1692                         SIZE szViewportExt = { 0, 0 };\r
1693                         dc.SetViewportExt(m_sizeAll, &szViewportExt);\r
1694                         POINT ptViewportOrg = { 0, 0 };\r
1695                         dc.SetViewportOrg(-m_ptOffset.x, -m_ptOffset.y, &ptViewportOrg);\r
1696 \r
1697                         pT->DoPaint(dc);\r
1698 \r
1699                         dc.SetMapMode(nMapModeSav);\r
1700                         dc.SetWindowExt(szWindowExt);\r
1701                         dc.SetViewportExt(szViewportExt);\r
1702                         dc.SetViewportOrg(ptViewportOrg);\r
1703                 }\r
1704                 else\r
1705                 {\r
1706                         CPaintDC dc(pT->m_hWnd);\r
1707                         pT->PrepareDC(dc.m_hDC);\r
1708                         pT->DoPaint(dc.m_hDC);\r
1709                 }\r
1710                 return 0;\r
1711         }\r
1712 \r
1713         LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\r
1714         {\r
1715                 if(m_nZoomMode == ZOOMMODE_IN && !m_bTracking)\r
1716                 {\r
1717                         T* pT = static_cast<T*>(this);\r
1718                         POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\r
1719                         if(pT->PtInDevRect(pt))\r
1720                         {\r
1721                                 pT->SetCapture();\r
1722                                 m_bTracking = true;\r
1723                                 ::SetRect(&m_rcTrack, pt.x, pt.y, pt.x, pt.y);\r
1724                         }       \r
1725                 }\r
1726                 bHandled = FALSE;\r
1727                 return 0;\r
1728         }\r
1729 \r
1730         LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\r
1731         {\r
1732                 if(m_bTracking)\r
1733                 {\r
1734                         T* pT = static_cast<T*>(this);\r
1735                         POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };\r
1736                         if(pT->PtInDevRect(pt))\r
1737                         {\r
1738                                 pT->DrawTrackRect();\r
1739                                 m_rcTrack.right = pt.x;\r
1740                                 m_rcTrack.bottom = pt.y;\r
1741                                 pT->DrawTrackRect();\r
1742                         }\r
1743                 }\r
1744                 bHandled = FALSE;\r
1745                 return 0;\r
1746         }\r
1747 \r
1748         LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)\r
1749         {\r
1750                 ::ReleaseCapture();\r
1751                 if(m_nZoomMode == ZOOMMODE_OUT)\r
1752                 {\r
1753                         T* pT = static_cast<T*>(this);\r
1754                         pT->Zoom(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), m_fZoomScale - m_fZoomDelta);\r
1755                         pT->NotifyParentZoomChanged();\r
1756                 }\r
1757                 bHandled = FALSE;\r
1758                 return 0;\r
1759         }\r
1760 \r
1761         LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)\r
1762         {\r
1763                 if(m_bTracking)\r
1764                 {\r
1765                         m_bTracking = false;\r
1766                         T* pT = static_cast<T*>(this);\r
1767                         pT->DrawTrackRect();\r
1768                         pT->Zoom(m_rcTrack);\r
1769                         pT->NotifyParentZoomChanged();\r
1770                         ::SetRectEmpty(&m_rcTrack);\r
1771                 }\r
1772                 bHandled = FALSE;\r
1773                 return 0;\r
1774         }       \r
1775 \r
1776         LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)\r
1777         {\r
1778                 if(LOWORD(lParam) == HTCLIENT && m_nZoomMode != ZOOMMODE_OFF)\r
1779                 {\r
1780                         T* pT = static_cast<T*>(this);\r
1781                         if((HWND)wParam == pT->m_hWnd)\r
1782                         {\r
1783                                 DWORD dwPos = ::GetMessagePos();\r
1784                                 POINT pt = { GET_X_LPARAM(dwPos), GET_Y_LPARAM(dwPos) };\r
1785                                 pT->ScreenToClient(&pt);\r
1786                                 if(pT->PtInDevRect(pt))\r
1787                                 {\r
1788                                         ::SetCursor(::LoadCursor(NULL, IDC_CROSS));\r
1789                                         return 1;\r
1790                                 }\r
1791                         }\r
1792                 }\r
1793                 bHandled = FALSE;\r
1794                 return 0;\r
1795         }\r
1796 };\r
1797 \r
1798 ///////////////////////////////////////////////////////////////////////////////\r
1799 // CZoomScrollWindowImpl - Implements scrolling window with zooming\r
1800 \r
1801 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\r
1802 class ATL_NO_VTABLE CZoomScrollWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CZoomScrollImpl< T >\r
1803 {\r
1804 public:\r
1805         BEGIN_MSG_MAP(CZoomScrollWindowImpl)\r
1806                 MESSAGE_HANDLER(WM_SETCURSOR, CZoomScrollImpl< T >::OnSetCursor)\r
1807                 MESSAGE_HANDLER(WM_VSCROLL, CScrollImpl< T >::OnVScroll)\r
1808                 MESSAGE_HANDLER(WM_HSCROLL, CScrollImpl< T >::OnHScroll)\r
1809                 MESSAGE_HANDLER(WM_MOUSEWHEEL, CScrollImpl< T >::OnMouseWheel)\r
1810 #if !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\r
1811                 MESSAGE_HANDLER(m_uMsgMouseWheel, CScrollImpl< T >::OnMouseWheel)\r
1812 #endif // !((_WIN32_WINNT >= 0x0400) || (_WIN32_WINDOWS > 0x0400))\r
1813                 MESSAGE_HANDLER(WM_MOUSEHWHEEL, CScrollImpl< T >::OnMouseHWheel)\r
1814                 MESSAGE_HANDLER(WM_SETTINGCHANGE, CScrollImpl< T >::OnSettingChange)\r
1815                 MESSAGE_HANDLER(WM_SIZE, CScrollImpl< T >::OnSize)\r
1816                 MESSAGE_HANDLER(WM_PAINT, CZoomScrollImpl< T >::OnPaint)\r
1817                 MESSAGE_HANDLER(WM_PRINTCLIENT, CZoomScrollImpl< T >::OnPaint)\r
1818                 MESSAGE_HANDLER(WM_LBUTTONDOWN, CZoomScrollImpl< T >::OnLButtonDown)\r
1819                 MESSAGE_HANDLER(WM_MOUSEMOVE, CZoomScrollImpl< T >::OnMouseMove)\r
1820                 MESSAGE_HANDLER(WM_LBUTTONUP, CZoomScrollImpl< T >::OnLButtonUp)\r
1821                 MESSAGE_HANDLER(WM_CAPTURECHANGED, CZoomScrollImpl< T >::OnCaptureChanged)\r
1822         ALT_MSG_MAP(1)\r
1823                 COMMAND_ID_HANDLER(ID_SCROLL_UP, CScrollImpl< T >::OnScrollUp)\r
1824                 COMMAND_ID_HANDLER(ID_SCROLL_DOWN, CScrollImpl< T >::OnScrollDown)\r
1825                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_UP, CScrollImpl< T >::OnScrollPageUp)\r
1826                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_DOWN, CScrollImpl< T >::OnScrollPageDown)\r
1827                 COMMAND_ID_HANDLER(ID_SCROLL_TOP, CScrollImpl< T >::OnScrollTop)\r
1828                 COMMAND_ID_HANDLER(ID_SCROLL_BOTTOM, CScrollImpl< T >::OnScrollBottom)\r
1829                 COMMAND_ID_HANDLER(ID_SCROLL_LEFT, CScrollImpl< T >::OnScrollLeft)\r
1830                 COMMAND_ID_HANDLER(ID_SCROLL_RIGHT, CScrollImpl< T >::OnScrollRight)\r
1831                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_LEFT, CScrollImpl< T >::OnScrollPageLeft)\r
1832                 COMMAND_ID_HANDLER(ID_SCROLL_PAGE_RIGHT, CScrollImpl< T >::OnScrollPageRight)\r
1833                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_LEFT, CScrollImpl< T >::OnScrollAllLeft)\r
1834                 COMMAND_ID_HANDLER(ID_SCROLL_ALL_RIGHT, CScrollImpl< T >::OnScrollAllRight)\r
1835         END_MSG_MAP()\r
1836 };\r
1837 \r
1838 #endif // !_WIN32_WCE\r
1839 \r
1840 \r
1841 ///////////////////////////////////////////////////////////////////////////////\r
1842 // CScrollContainer\r
1843 \r
1844 template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>\r
1845 class ATL_NO_VTABLE CScrollContainerImpl : public CScrollWindowImpl< T, TBase, TWinTraits >\r
1846 {\r
1847 public:\r
1848         DECLARE_WND_CLASS_EX(NULL, 0, -1)\r
1849 \r
1850         typedef CScrollWindowImpl< T, TBase, TWinTraits >   _baseClass;\r
1851 \r
1852 // Data members\r
1853         ATL::CWindow m_wndClient;\r
1854         bool m_bAutoSizeClient;\r
1855         bool m_bDrawEdgeIfEmpty;\r
1856 \r
1857 // Constructor\r
1858         CScrollContainerImpl() : m_bAutoSizeClient(true), m_bDrawEdgeIfEmpty(false)\r
1859         {\r
1860                 // Set CScrollWindowImpl extended style\r
1861                 SetScrollExtendedStyle(SCRL_SCROLLCHILDREN);\r
1862         }\r
1863 \r
1864 // Attributes\r
1865         HWND GetClient() const\r
1866         {\r
1867                 return m_wndClient;\r
1868         }\r
1869 \r
1870         HWND SetClient(HWND hWndClient, bool bClientSizeAsMin = true)\r
1871         {\r
1872                 ATLASSERT(::IsWindow(m_hWnd));\r
1873 \r
1874                 HWND hWndOldClient = m_wndClient;\r
1875                 m_wndClient = hWndClient;\r
1876 \r
1877                 SetRedraw(FALSE);\r
1878                 SetScrollSize(1, 1, FALSE);\r
1879 \r
1880                 if(m_wndClient.m_hWnd != NULL)\r
1881                 {\r
1882                         m_wndClient.SetWindowPos(NULL, 0, 0, 0, 0, SWP_NOZORDER | SWP_NOSIZE);\r
1883 \r
1884                         if(bClientSizeAsMin)\r
1885                         {\r
1886                                 RECT rect = { 0 };\r
1887                                 m_wndClient.GetWindowRect(&rect);\r
1888                                 if((rect.right - rect.left) > 0 && (rect.bottom - rect.top) > 0)\r
1889                                         SetScrollSize(rect.right - rect.left, rect.bottom - rect.top, FALSE);\r
1890                         }\r
1891 \r
1892                         T* pT = static_cast<T*>(this);\r
1893                         pT->UpdateLayout();\r
1894                 }\r
1895 \r
1896                 SetRedraw(TRUE);\r
1897                 RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_FRAME | RDW_UPDATENOW | RDW_ALLCHILDREN);\r
1898 \r
1899                 return hWndOldClient;\r
1900         }\r
1901 \r
1902 // Message map and handlers\r
1903         BEGIN_MSG_MAP(CScrollContainerImpl)\r
1904                 MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)\r
1905                 MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)\r
1906                 MESSAGE_HANDLER(WM_SIZE, OnSize)\r
1907                 CHAIN_MSG_MAP(_baseClass)\r
1908                 FORWARD_NOTIFICATIONS()\r
1909         ALT_MSG_MAP(1)\r
1910                 CHAIN_MSG_MAP_ALT(_baseClass, 1)\r
1911         END_MSG_MAP()\r
1912 \r
1913         LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
1914         {\r
1915                 if(m_wndClient.m_hWnd != NULL)\r
1916                         m_wndClient.SetFocus();\r
1917 \r
1918                 return 0;\r
1919         }\r
1920 \r
1921         LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)\r
1922         {\r
1923                 return 1;   // no background needed\r
1924         }\r
1925 \r
1926         LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)\r
1927         {\r
1928                 BOOL bTmp = TRUE;\r
1929                 LRESULT lRet = _baseClass::OnSize(uMsg, wParam, lParam, bTmp);\r
1930 \r
1931                 T* pT = static_cast<T*>(this);\r
1932                 pT->UpdateLayout();\r
1933 \r
1934                 return lRet;\r
1935         }\r
1936 \r
1937 // Overrides for CScrollWindowImpl\r
1938         void DoPaint(CDCHandle dc)\r
1939         {\r
1940                 if(!m_bAutoSizeClient || m_wndClient.m_hWnd == NULL)\r
1941                 {\r
1942                         T* pT = static_cast<T*>(this);\r
1943                         RECT rect = { 0 };\r
1944                         pT->GetContainerRect(rect);\r
1945 \r
1946                         if(m_bDrawEdgeIfEmpty && m_wndClient.m_hWnd == NULL)\r
1947                                 dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);\r
1948 \r
1949                         dc.FillRect(&rect, COLOR_APPWORKSPACE);\r
1950                 }\r
1951         }\r
1952 \r
1953         void ScrollToView(POINT pt)\r
1954         {\r
1955                 CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(pt);\r
1956         }\r
1957 \r
1958         void ScrollToView(RECT& rect)\r
1959         {\r
1960                 CScrollWindowImpl< T, TBase, TWinTraits >::ScrollToView(rect);\r
1961         }\r
1962 \r
1963         void ScrollToView(HWND hWnd)   // client window coordinates\r
1964         {\r
1965                 T* pT = static_cast<T*>(this);\r
1966                 pT;   // avoid level 4 warning\r
1967                 ATLASSERT(::IsWindow(pT->m_hWnd));\r
1968                 ATLASSERT(m_wndClient.IsWindow());\r
1969 \r
1970                 RECT rect = { 0 };\r
1971                 ::GetWindowRect(hWnd, &rect);\r
1972                 ::MapWindowPoints(NULL, m_wndClient.m_hWnd, (LPPOINT)&rect, 2);\r
1973                 ScrollToView(rect);\r
1974         }\r
1975 \r
1976 // Implementation - overrideable methods\r
1977         void UpdateLayout()\r
1978         {\r
1979                 ATLASSERT(::IsWindow(m_hWnd));\r
1980 \r
1981                 if(m_bAutoSizeClient && m_wndClient.m_hWnd != NULL)\r
1982                 {\r
1983                         T* pT = static_cast<T*>(this);\r
1984                         RECT rect = { 0 };\r
1985                         pT->GetContainerRect(rect);\r
1986 \r
1987                         m_wndClient.SetWindowPos(NULL, &rect, SWP_NOZORDER | SWP_NOMOVE);\r
1988                 }\r
1989                 else\r
1990                 {\r
1991                         Invalidate();\r
1992                 }\r
1993         }\r
1994 \r
1995         void GetContainerRect(RECT& rect)\r
1996         {\r
1997                 GetClientRect(&rect);\r
1998 \r
1999                 if(rect.right < m_sizeAll.cx)\r
2000                         rect.right = m_sizeAll.cx;\r
2001 \r
2002                 if(rect.bottom < m_sizeAll.cy)\r
2003                         rect.bottom = m_sizeAll.cy;\r
2004         }\r
2005 };\r
2006 \r
2007 class CScrollContainer : public CScrollContainerImpl<CScrollContainer>\r
2008 {\r
2009 public:\r
2010         DECLARE_WND_CLASS_EX(_T("WTL_ScrollContainer"), 0, -1)\r
2011 };\r
2012 \r
2013 }; // namespace WTL\r
2014 \r
2015 #endif // __ATLSCRL_H__\r