-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathAUTOSCRL.CPP
219 lines (189 loc) · 7.48 KB
/
AUTOSCRL.CPP
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
// autoscvw.cpp : implementation file
//
//
// CAutoScrollView is derived from CScrollView. It adds the AutoScroll feature
// that is needed in many applications. AutoScrolling means that the window
// begins to scroll as soon as the mouse cursor leaves the client area of the
// current View while the left mouse button is pressed. You can customize the
// button used to autoscroll using the SetAutoButton inline member function.
// SetAutoButton accepts one parameter of type _AutoButton: mbLeft, mbRight or
// mbMiddle. SetAutoButton returns the button type that was active before the
// call.
//
// The amount by which the View is scrolled depends on the distance between the
// the window border and the mouse cursor. The greater the distance, the faster
// the View scrolls.
//
// You can enable or disable the AutoScroll feature by using the
// EnableAutoScrolling() inline member function. It accepts one parameter
// of type BOOL.
//
// By default, autoscrolling is enabled with the left button.
//
// BOOL IsAutoScrolling() tells you whether autoscrolling operations are
// underway.
//
// To give your application's View a chance to properly update the screen while
// autoscrolling, CAutoScrollView calls its OnAutoScroll() virtual member
// function just before and just after scrolling. Override this function in
// your View if you want to take some action whenever autoscrolling occurs.
// By default, OnAutoScroll does nothing.
//
// OnAutoScroll accepts two parameters:
//
// virtual void OnAutoScroll(CPoint point, BOOL bBeforeScroll);
//
// point indicates the current position of the mouse cursor in client device
// coordinates. That is, the ScreenToClient() function has been applied to point
// but no DPtoLP operation has been done.
//
// bBeforeScroll is TRUE when OnAutoScroll is called before scrolling and
// FALSE otherwise.
//
// Most of the time you will not have any opportunity to initialize a
// CAutoScrollView yourself. So, member variables are initialized in the
// constructor directly.
//
// CAutoScrollView automatically adapts to the mapping mode. For example, if
// you have set a metric mapping mode, the nMapFactor will be used to
// reverse y coordinates.
//
// CAutoScrollView also corrects an annoying behavior of
// CScrollView::ScrollToPosition. This member function doesn't check whether
// the scroll limit has already been reached and always tries to scroll. This
// wouldn't be a problem if a call to ScrollWindow was not made systematically.
// This generates flicker. When AutoScrolling, this condition doesn't occur.
//
#include "stdafx.h"
//#include "autoscrl.h"
#ifdef _DEBUG
#undef THIS_FILE
static char BASED_CODE THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAutoScrollView
IMPLEMENT_DYNAMIC(CAutoScrollView, CScrollView)
CAutoScrollView::CAutoScrollView()
{
m_bAutoScroll = TRUE;
m_bIsScrolling = FALSE;
}
BEGIN_MESSAGE_MAP(CAutoScrollView, CScrollView)
//{{AFX_MSG_MAP(CAutoScrollView)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CAutoScrollView drawing
void CAutoScrollView::OnDraw(CDC* /*pDC*/)
{
}
/////////////////////////////////////////////////////////////////////////////
// CAutoScrollView message handlers
void CAutoScrollView::AutoScroll(UINT nRefMessage)
{
MSG msg; // dummmy message structure to process incoming
// messages while autoscrolling.
CPoint ptScrollPos, // Current scroll position - logical units
ptDevScrollPos, // Current scroll position - device units
ptCursorPos; // Current mouse cursor position
CRect rc; // Client area
long dx, dy; // Scrolling increment
SIZE sizeTotal, // CScrollView scroll data
sizePage,
sizeLine;
int nMapMode, // Mapping mode
nMapFactor, // Accounts for mapping mode
xMin, xMax,
yMin, yMax; // Scroll range
if (!m_bAutoScroll)
return;
msg.message = 0; // forces at least one loop.
SetCapture();
GetDeviceScrollSizes(nMapMode, sizeTotal, sizePage, sizeLine);
// We keep track of the scroll range because CScrollView::ScrollToPosition always
// try to scroll even if the scroll limit has been reached. This results in screen
// flickering when ScrollWindow is called.
GetScrollRange(SB_HORZ, &xMin, &xMax);
GetScrollRange(SB_VERT, &yMin, &yMax);
// Process all messages until the relevant mouse button
// has been released. nRefMessage depends on which button
// has been used to trigger autoscrolling.
// while (msg.message != nRefMessage)
BOOL bSawRefMessage = FALSE;
while (!bSawRefMessage)
{
// Process incoming messages until autoscroll button is released
// You cannot peek here because it may process an invalidate
// due to the scrolling.
/*
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
*/
ptScrollPos = GetScrollPosition();
ptDevScrollPos = GetDeviceScrollPosition();
GetCursorPos(&ptCursorPos);
ScreenToClient(&ptCursorPos);
GetClientRect(&rc);
dx = 0L;
dy = 0L;
if ((ptCursorPos.y < 0) && (ptDevScrollPos.y != yMin))
// Cursor is above client area
dy = min(-sizeLine.cy, max(-sizePage.cy, (ptCursorPos.y/10) * sizeLine.cy));
else if ((ptCursorPos.y > rc.bottom) && (ptDevScrollPos.y != yMax))
// Cursor is below client area
dy = max(sizeLine.cy, min(sizePage.cy, ((ptCursorPos.y - rc.bottom)/10) * sizeLine.cy));
// otherwise we can't scroll anyway
if ((ptCursorPos.x < 0) && (ptDevScrollPos.x != xMin))
// Cursor is on the left of the client area
dx = min(-sizeLine.cx, max(-sizePage.cx, (ptCursorPos.x/10) * sizeLine.cx));
else if ((ptCursorPos.x > rc.right) && (ptDevScrollPos.x != xMax))
// Cursor is on the right of the client area
dx = max(sizeLine.cx, min(sizePage.cx, ((ptCursorPos.x - rc.right)/10) * sizeLine.cx));
// otherwise we can't scroll anyway
// if mouse cursor is dragging outside the client area, scrolling occurs
if ((dx != 0) || (dy != 0))
{
// Flip the Y coordinate if we're not in MM_TEXT
nMapFactor = (nMapMode == MM_TEXT) ? 1 : -1;
ptScrollPos.y += (int) dy * nMapFactor / 8;
ptScrollPos.x += (int) dx / 8;
m_bIsScrolling = TRUE;
OnAutoScroll(ptCursorPos, TRUE);
ScrollToPosition(ptScrollPos);
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
// if (msg.message == nRefMessage) break;
if (msg.message == nRefMessage) bSawRefMessage = TRUE;
}
// if (!bSawRefMessage)
OnAutoScroll(ptCursorPos, FALSE);
}
else
{
while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
// if (msg.message == nRefMessage) break;
if (msg.message == nRefMessage) bSawRefMessage = TRUE;
}
m_bIsScrolling = FALSE;
}
}
ReleaseCapture();
m_bIsScrolling = FALSE;
}
void CAutoScrollView::OnLButtonDown(UINT nFlags, CPoint point)
{
CScrollView::OnLButtonDown(nFlags, point);
AutoScroll(WM_LBUTTONUP);
}
void CAutoScrollView::OnAutoScroll(CPoint /*point*/, BOOL /*bBeforeScroll*/)
{
}