1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Clipboard Viewer
4  * FILE:            base/applications/clipbrd/scrollutils.c
5  * PURPOSE:         Scrolling related helper functions.
6  * PROGRAMMERS:     Ricardo Hanke
7  */
8 
9 #include "precomp.h"
10 
11 static int InternalSetScrollInfo(HWND hWnd, int nMin, int nMax, UINT nPage, int nPos, int fnBar)
12 {
13     SCROLLINFO si;
14 
15     ZeroMemory(&si, sizeof(si));
16     si.cbSize = sizeof(si);
17     si.fMask  = SIF_RANGE | SIF_PAGE | SIF_POS | SIF_DISABLENOSCROLL;
18     si.nMin   = nMin;
19     si.nMax   = nMax;
20     si.nPage  = nPage;
21     si.nPos   = nPos;
22 
23     return SetScrollInfo(hWnd, fnBar, &si, TRUE);
24 }
25 
26 void HandleKeyboardScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
27 {
28     switch (wParam)
29     {
30         case VK_UP:
31         {
32             SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEUP, 0), 0);
33             break;
34         }
35 
36         case VK_DOWN:
37         {
38             SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
39             break;
40         }
41 
42         case VK_LEFT:
43         {
44             SendMessage(hWnd, WM_HSCROLL, MAKELONG(SB_LINEUP, 0), 0);
45             break;
46         }
47 
48         case VK_RIGHT:
49         {
50             SendMessage(hWnd, WM_HSCROLL, MAKELONG(SB_LINEDOWN, 0), 0);
51             break;
52         }
53 
54         case VK_PRIOR:
55         {
56             SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_PAGEUP, 0), 0);
57             break;
58         }
59 
60         case VK_NEXT:
61         {
62             SendMessage(hWnd, WM_VSCROLL, MAKELONG(SB_PAGEDOWN, 0), 0);
63             break;
64         }
65 
66         default:
67         {
68             break;
69         }
70     }
71 }
72 
73 void HandleMouseScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state)
74 {
75     SCROLLINFO si;
76     int Delta;
77     int NewPos;
78 
79     si.cbSize = sizeof(si);
80     si.fMask = SIF_PAGE;
81     GetScrollInfo(hWnd, SB_VERT, &si);
82 
83     if (Globals.uLinesToScroll == WHEEL_PAGESCROLL)
84     {
85         NewPos = si.nPage;
86     }
87     else
88     {
89         NewPos = Globals.uLinesToScroll * 5;
90     }
91 
92     if (GET_WHEEL_DELTA_WPARAM(wParam) > 0)
93     {
94         NewPos = state->CurrentY - NewPos;
95     }
96     else
97     {
98         NewPos = state->CurrentY + NewPos;
99     }
100 
101     NewPos = min(state->MaxY, max(0, NewPos));
102 
103     if (NewPos == state->CurrentY)
104     {
105         return;
106     }
107 
108     Delta = NewPos - state->CurrentY;
109 
110     state->CurrentY = NewPos;
111 
112     ScrollWindowEx(hWnd, 0, -Delta, NULL, NULL, NULL, NULL, SW_INVALIDATE);
113 
114     si.cbSize = sizeof(si);
115     si.fMask = SIF_POS;
116     si.nPos = state->CurrentY;
117     SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
118 }
119 
120 void HandleHorizontalScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state)
121 {
122     SCROLLINFO si;
123     int Delta;
124     int NewPos;
125 
126     ZeroMemory(&si, sizeof(si));
127     si.cbSize = sizeof(si);
128     si.fMask = SIF_PAGE | SIF_TRACKPOS;
129     GetScrollInfo(hWnd, SB_HORZ, &si);
130 
131     switch (LOWORD(wParam))
132     {
133         case SB_THUMBPOSITION:
134         case SB_THUMBTRACK:
135         {
136             NewPos = si.nTrackPos;
137             break;
138         }
139 
140         case SB_LINELEFT:
141         {
142             NewPos = state->CurrentX - 5;
143             break;
144         }
145 
146         case SB_LINERIGHT:
147         {
148             NewPos = state->CurrentX + 5;
149             break;
150         }
151 
152         case SB_PAGELEFT:
153         {
154             NewPos = state->CurrentX - si.nPage;
155             break;
156         }
157 
158         case SB_PAGERIGHT:
159         {
160             NewPos = state->CurrentX + si.nPage;
161             break;
162         }
163 
164         default:
165         {
166             NewPos = state->CurrentX;
167             break;
168         }
169     }
170 
171    NewPos = min(state->MaxX, max(0, NewPos));
172 
173    if (NewPos == state->CurrentX)
174    {
175        return;
176    }
177 
178    Delta = NewPos - state->CurrentX;
179 
180    state->CurrentX = NewPos;
181 
182    ScrollWindowEx(hWnd, -Delta, 0, NULL, NULL, NULL, NULL, SW_INVALIDATE);
183 
184    si.cbSize = sizeof(si);
185    si.fMask = SIF_POS;
186    si.nPos = state->CurrentX;
187    SetScrollInfo(hWnd, SB_HORZ, &si, TRUE);
188 }
189 
190 void HandleVerticalScrollEvents(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, LPSCROLLSTATE state)
191 {
192     SCROLLINFO si;
193     int Delta;
194     int NewPos;
195 
196     ZeroMemory(&si, sizeof(si));
197     si.cbSize = sizeof(si);
198     si.fMask = SIF_PAGE | SIF_TRACKPOS;
199     GetScrollInfo(hWnd, SB_VERT, &si);
200 
201     switch (LOWORD(wParam))
202     {
203         case SB_THUMBPOSITION:
204         case SB_THUMBTRACK:
205         {
206             NewPos = si.nTrackPos;
207             break;
208         }
209 
210         case SB_LINEUP:
211         {
212             NewPos = state->CurrentY - 5;
213             break;
214         }
215 
216         case SB_LINEDOWN:
217         {
218             NewPos = state->CurrentY + 5;
219             break;
220         }
221 
222         case SB_PAGEUP:
223         {
224             NewPos = state->CurrentY - si.nPage;
225             break;
226         }
227 
228         case SB_PAGEDOWN:
229         {
230             NewPos = state->CurrentY + si.nPage;
231             break;
232         }
233 
234         default:
235         {
236             NewPos = state->CurrentY;
237             break;
238         }
239    }
240 
241    NewPos = min(state->MaxY, max(0, NewPos));
242 
243    if (NewPos == state->CurrentY)
244    {
245        return;
246    }
247 
248    Delta = NewPos - state->CurrentY;
249 
250    state->CurrentY = NewPos;
251 
252    ScrollWindowEx(hWnd, 0, -Delta, NULL, NULL, NULL, NULL, SW_INVALIDATE);
253 
254    si.cbSize = sizeof(si);
255    si.fMask = SIF_POS;
256    si.nPos = state->CurrentY;
257    SetScrollInfo(hWnd, SB_VERT, &si, TRUE);
258 }
259 
260 void UpdateWindowScrollState(HWND hWnd, HBITMAP hBitmap, LPSCROLLSTATE lpState)
261 {
262     BITMAP bmp;
263     RECT rc;
264 
265     if (!GetObject(hBitmap, sizeof(BITMAP), &bmp))
266     {
267         bmp.bmWidth = 0;
268         bmp.bmHeight = 0;
269     }
270 
271     if (!GetClientRect(hWnd, &rc))
272     {
273         SetRectEmpty(&rc);
274     }
275 
276     lpState->MaxX = max(bmp.bmWidth - rc.right, 0);
277     lpState->CurrentX = min(lpState->CurrentX, lpState->MaxX);
278     InternalSetScrollInfo(hWnd, 0, bmp.bmWidth, rc.right, lpState->CurrentX, SB_HORZ);
279 
280     lpState->MaxY = max(bmp.bmHeight - rc.bottom, 0);
281     lpState->CurrentY = min(lpState->CurrentY, lpState->MaxY);
282     InternalSetScrollInfo(hWnd, 0, bmp.bmHeight, rc.bottom, lpState->CurrentY, SB_VERT);
283 }
284 
285 BOOL ScrollBlt(PAINTSTRUCT ps, HBITMAP hBmp, SCROLLSTATE state)
286 {
287     RECT rect;
288     BOOL ret;
289     HDC hdc;
290     int xpos;
291     int ypos;
292 
293     rect.left = ps.rcPaint.left;
294     rect.top = ps.rcPaint.top;
295     rect.right = (ps.rcPaint.right - ps.rcPaint.left);
296     rect.bottom = (ps.rcPaint.bottom - ps.rcPaint.top);
297 
298     xpos = ps.rcPaint.left + state.CurrentX;
299     ypos = ps.rcPaint.top + state.CurrentY;
300 
301     ret = FALSE;
302 
303     hdc = CreateCompatibleDC(ps.hdc);
304     if (hdc)
305     {
306         if (SelectObject(hdc, hBmp))
307         {
308             ret = BitBlt(ps.hdc, rect.left, rect.top, rect.right, rect.bottom, hdc, xpos, ypos, SRCCOPY);
309         }
310         DeleteDC(hdc);
311     }
312 
313     return ret;
314 }
315