branch update for HEAD-2003021201
[reactos.git] / lib / user32 / controls / scrollbar.c
1 /* $Id$
2  *
3  * COPYRIGHT:        See COPYING in the top level directory
4  * PROJECT:          ReactOS kernel
5  * PURPOSE:          Windows
6  * FILE:             subsys/win32k/ntuser/window.c
7  * PROGRAMER:        Casper S. Hornstrup (chorns@users.sourceforge.net)
8  * REVISION HISTORY:
9  *       06-06-2001  CSH  Created
10  */
11 /* INCLUDES ******************************************************************/
12
13 /* INCLUDES ******************************************************************/
14
15 #include <windows.h>
16 #include <user32.h>
17 #include <debug.h>
18
19 /* GLOBAL VARIABLES **********************************************************/
20 /*
21 static HBITMAP hUpArrow;
22 static HBITMAP hDnArrow;
23 static HBITMAP hLfArrow;
24 static HBITMAP hRgArrow;
25 static HBITMAP hUpArrowD;
26 static HBITMAP hDnArrowD;
27 static HBITMAP hLfArrowD;
28 static HBITMAP hRgArrowD;
29 static HBITMAP hUpArrowI;
30 static HBITMAP hDnArrowI;
31 static HBITMAP hLfArrowI;
32 static HBITMAP hRgArrowI;
33 */
34 #define TOP_ARROW(flags,pressed) \
35    (((flags)&ESB_DISABLE_UP) ? hUpArrowI : ((pressed) ? hUpArrowD:hUpArrow))
36 #define BOTTOM_ARROW(flags,pressed) \
37    (((flags)&ESB_DISABLE_DOWN) ? hDnArrowI : ((pressed) ? hDnArrowD:hDnArrow))
38 #define LEFT_ARROW(flags,pressed) \
39    (((flags)&ESB_DISABLE_LEFT) ? hLfArrowI : ((pressed) ? hLfArrowD:hLfArrow))
40 #define RIGHT_ARROW(flags,pressed) \
41    (((flags)&ESB_DISABLE_RIGHT) ? hRgArrowI : ((pressed) ? hRgArrowD:hRgArrow))
42
43 #define SCROLL_ARROW_THUMB_OVERLAP 0     /* Overlap between arrows and thumb */
44 #define SCROLL_MIN_THUMB 6               /* Minimum size of the thumb in pixels */
45 #define SCROLL_FIRST_DELAY   200         /* Delay (in ms) before first repetition when holding the button down */
46 #define SCROLL_REPEAT_DELAY  50          /* Delay (in ms) between scroll repetitions */
47 #define SCROLL_TIMER   0                 /* Scroll timer id */
48
49  /* What to do after SCROLL_SetScrollInfo() */
50 #define SA_SSI_HIDE             0x0001
51 #define SA_SSI_SHOW             0x0002
52 #define SA_SSI_REFRESH          0x0004
53 #define SA_SSI_REPAINT_ARROWS   0x0008
54
55   /* Scroll-bar hit testing */
56 enum SCROLL_HITTEST
57 {
58   SCROLL_NOWHERE,               /* Outside the scroll bar */
59   SCROLL_TOP_ARROW,             /* Top or left arrow */
60   SCROLL_TOP_RECT,              /* Rectangle between the top arrow and the thumb */
61   SCROLL_THUMB,                 /* Thumb rectangle */
62   SCROLL_BOTTOM_RECT,           /* Rectangle between the thumb and the bottom arrow */
63   SCROLL_BOTTOM_ARROW           /* Bottom or right arrow */
64 };
65
66 static BOOL SCROLL_MovingThumb = FALSE; /* Is the moving thumb being displayed? */
67
68 /* Thumb-tracking info */
69 static HWND SCROLL_TrackingWin = 0;
70 static INT SCROLL_TrackingBar = 0;
71 static INT SCROLL_TrackingPos = 0;
72 /* static INT  SCROLL_TrackingVal = 0; */
73 static enum SCROLL_HITTEST SCROLL_trackHitTest; /* Hit test code of the last button-down event */
74 static BOOL SCROLL_trackVertical;
75
76 /* FUNCTIONS *****************************************************************/
77
78 HBRUSH DefWndControlColor (HDC hDC, UINT ctlType);
79 HPEN STDCALL GetSysColorPen (int nIndex);
80
81
82
83 WINBOOL STDCALL
84 GetScrollBarInfo (HWND hwnd, LONG idObject, PSCROLLBARINFO psbi)
85 {
86   int ret = NtUserGetScrollBarInfo (hwnd, idObject, psbi);
87
88   return ret;
89 }
90
91 /* Ported from WINE20020904 */
92 /* Draw the scroll bar interior (everything except the arrows). */
93 static void
94 SCROLL_DrawInterior (HWND hwnd, HDC hdc, INT nBar, INT arrowSize, PSCROLLBARINFO psbi)
95 {
96   INT thumbSize = psbi->xyThumbBottom - psbi->xyThumbTop;
97   HPEN hSavePen;
98   HBRUSH hSaveBrush, hBrush;
99   BOOLEAN top_selected = FALSE, bottom_selected = FALSE;
100 DbgPrint("[SCROLL_DrawInterior:%d]\n", nBar);
101   if(psbi->rgstate[2] & STATE_SYSTEM_PRESSED)
102   {
103     top_selected = TRUE;
104   }
105   if(psbi->rgstate[4] & STATE_SYSTEM_PRESSED)
106   {
107     bottom_selected = TRUE;
108   }
109
110   /* Only scrollbar controls send WM_CTLCOLORSCROLLBAR.
111    * The window-owned scrollbars need to call DefWndControlColor
112    * to correctly setup default scrollbar colors
113    */
114   if (nBar == SB_CTL)
115     {
116       hBrush = (HBRUSH) NtUserSendMessage (GetParent (hwnd), WM_CTLCOLORSCROLLBAR,
117                                            (WPARAM) hdc, (LPARAM) hwnd);
118     }
119   else
120     {
121 /*      hBrush = NtUserGetControlColor (hdc, CTLCOLOR_SCROLLBAR); FIXME */ /* DefWndControlColor */
122       hBrush = GetSysColorBrush(COLOR_SCROLLBAR);
123     }
124
125   hSavePen = SelectObject (hdc, GetSysColorPen (COLOR_WINDOWFRAME));
126   hSaveBrush = SelectObject (hdc, hBrush);
127
128   /* Calculate the scroll rectangle */
129   if (nBar == SB_VERT)
130     {
131       psbi->rcScrollBar.top += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
132       psbi->rcScrollBar.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
133     }
134   else if (nBar == SB_HORZ)
135     {
136       psbi->rcScrollBar.left += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
137       psbi->rcScrollBar.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
138     }
139
140   /* Draw the scroll rectangles and thumb */
141   if (!psbi->dxyLineButton)             /* No thumb to draw */
142     {
143       PatBlt (hdc,
144               psbi->rcScrollBar.left,
145               psbi->rcScrollBar.top,
146               psbi->rcScrollBar.right - psbi->rcScrollBar.left,
147               psbi->rcScrollBar.bottom - psbi->rcScrollBar.top,
148               PATCOPY);
149
150       /* cleanup and return */
151       SelectObject (hdc, hSavePen);
152       SelectObject (hdc, hSaveBrush);
153       return;
154     }
155
156   if (nBar == SB_VERT)
157     {
158       PatBlt (hdc,
159               psbi->rcScrollBar.left,
160               psbi->rcScrollBar.top,
161               psbi->rcScrollBar.right - psbi->rcScrollBar.left,
162               psbi->dxyLineButton - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
163               top_selected ? 0x0f0000 : PATCOPY);
164       psbi->rcScrollBar.top += psbi->dxyLineButton - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
165       PatBlt (hdc,
166               psbi->rcScrollBar.left,
167               psbi->rcScrollBar.top + thumbSize,
168               psbi->rcScrollBar.right - psbi->rcScrollBar.left,
169               psbi->rcScrollBar.bottom - psbi->rcScrollBar.top - thumbSize,
170               bottom_selected ? 0x0f0000 : PATCOPY);
171       psbi->rcScrollBar.bottom = psbi->rcScrollBar.top + thumbSize;
172     }
173   else if (nBar == SB_HORZ)
174     {
175       PatBlt (hdc,
176               psbi->rcScrollBar.left,
177               psbi->rcScrollBar.top,
178               psbi->dxyLineButton - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
179               psbi->rcScrollBar.bottom - psbi->rcScrollBar.top,
180               top_selected ? 0x0f0000 : PATCOPY);
181       psbi->rcScrollBar.left += psbi->dxyLineButton - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
182       PatBlt (hdc,
183               psbi->rcScrollBar.left + thumbSize,
184               psbi->rcScrollBar.top,
185               psbi->rcScrollBar.right - psbi->rcScrollBar.left - thumbSize,
186               psbi->rcScrollBar.bottom - psbi->rcScrollBar.top,
187               bottom_selected ? 0x0f0000 : PATCOPY);
188       psbi->rcScrollBar.right = psbi->rcScrollBar.left + thumbSize;
189     }
190
191   /* Draw the thumb */
192   DrawEdge (hdc, &psbi->rcScrollBar, EDGE_RAISED, BF_RECT | BF_MIDDLE);
193
194   /* cleanup */
195   SelectObject (hdc, hSavePen);
196   SelectObject (hdc, hSaveBrush);
197 }
198
199 /* Ported from WINE20020904 */
200 static void
201 SCROLL_DrawMovingThumb (HDC hdc, RECT * rect, int nBar, int arrowSize, int thumbSize, PSCROLLBARINFO psbi)
202 {
203   INT pos = SCROLL_TrackingPos;
204   INT max_size;
205
206   if (nBar == SB_VERT)
207     max_size = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top;
208   else if (nBar == SB_HORZ)
209     max_size = psbi->rcScrollBar.right - psbi->rcScrollBar.left;
210
211   max_size -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP) + thumbSize;
212
213   if (pos < (arrowSize - SCROLL_ARROW_THUMB_OVERLAP))
214     pos = (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
215   else if (pos > max_size)
216     pos = max_size;
217
218   SCROLL_DrawInterior (SCROLL_TrackingWin, hdc, SCROLL_TrackingBar, arrowSize, psbi);
219
220   SCROLL_MovingThumb = !SCROLL_MovingThumb;
221 }
222
223 /* Ported from WINE20020904 */
224 /* Draw the scroll bar arrows. */
225 static void
226 SCROLL_DrawArrows (HDC hdc, PSCROLLBARINFO info,
227                    RECT * rect, INT arrowSize, int nBar,
228                    BOOL top_pressed, BOOL bottom_pressed)
229 {
230   RECT r;
231   int scrollDirFlag1, scrollDirFlag2;
232
233   if (nBar == SB_VERT)
234   {
235     scrollDirFlag1 = DFCS_SCROLLUP;
236     scrollDirFlag2 = DFCS_SCROLLDOWN;
237   }
238   else if (nBar == SB_HORZ)
239   {
240     scrollDirFlag1 = DFCS_SCROLLLEFT;
241     scrollDirFlag2 = DFCS_SCROLLRIGHT;
242   }
243
244   r = *rect;
245   if (nBar == SB_VERT)
246     r.bottom = r.top + arrowSize;
247   else if (nBar == SB_HORZ)
248     r.right = r.left + arrowSize;
249
250   DrawFrameControl (hdc, &r, DFC_SCROLL,
251                     scrollDirFlag1 | (top_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0)
252                     /* | (info.flags&ESB_DISABLE_LTUP ? DFCS_INACTIVE : 0) */
253     );
254   r = *rect;
255   if (nBar == SB_VERT)
256     r.top = r.bottom - arrowSize;
257   else if (nBar == SB_HORZ)
258     r.left = r.right - arrowSize;
259   DrawFrameControl (hdc, &r, DFC_SCROLL,
260                     scrollDirFlag2 | (bottom_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0)
261                     /* | (info.flags&ESB_DISABLE_RTDN ? DFCS_INACTIVE : 0) */
262     );
263 }
264
265 /* Ported from WINE20020904 */
266 /* Redraw the whole scrollbar. */
267 void
268 SCROLL_DrawScrollBar (HWND hwnd, HDC hdc, INT nBar,
269                       BOOL arrows, BOOL interior)
270 {
271   INT arrowSize = 0;
272   INT thumbSize;
273   SCROLLBARINFO info;
274   BOOL Save_SCROLL_MovingThumb = SCROLL_MovingThumb;
275
276   info.cbSize = sizeof(SCROLLBARINFO);
277   GetScrollBarInfo (hwnd, nBar, &info);
278
279   thumbSize = info.xyThumbBottom - info.xyThumbTop;
280
281   if (nBar == SB_HORZ)
282   {
283     arrowSize = GetSystemMetrics(SM_CYHSCROLL);
284   } else
285   if (nBar == SB_VERT)
286   {
287     arrowSize = GetSystemMetrics(SM_CXVSCROLL);
288   }
289
290   if (IsRectEmpty (&(info.rcScrollBar))) goto END;
291
292   if (Save_SCROLL_MovingThumb && (SCROLL_TrackingWin == hwnd) && (SCROLL_TrackingBar == nBar))
293   {
294     SCROLL_DrawMovingThumb (hdc, &(info.rcScrollBar), nBar, arrowSize, thumbSize, &info);
295   }
296
297   /* Draw the arrows */
298   if (arrows && arrowSize)
299   {
300     if (SCROLL_trackVertical == TRUE /* && GetCapture () == hwnd */)
301     {
302       SCROLL_DrawArrows (hdc, &info, &(info.rcScrollBar), arrowSize, nBar,
303                          (SCROLL_trackHitTest == SCROLL_TOP_ARROW),
304                          (SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW));
305     }
306     else
307     {
308       SCROLL_DrawArrows (hdc, &info, &(info.rcScrollBar), arrowSize, nBar, FALSE, FALSE);
309     }
310   }
311
312   if (interior)
313   {
314     SCROLL_DrawInterior (hwnd, hdc, nBar, arrowSize, &info);
315   }
316
317   if (Save_SCROLL_MovingThumb &&
318       (SCROLL_TrackingWin == hwnd) && (SCROLL_TrackingBar == nBar))
319     SCROLL_DrawMovingThumb (hdc, &info.rcScrollBar, nBar, arrowSize, thumbSize, &info);
320   /* if scroll bar has focus, reposition the caret */
321
322 /*  if (hwnd == GetFocus () && (nBar == SB_CTL))
323     {
324       if (nBar == SB_HORZ)
325         {
326           SetCaretPos (info.dxyLineButton + 1, info.rcScrollBar.top + 1);
327         }
328       else if (nBAR == SB_VERT)
329         {
330           SetCaretPos (info.rcScrollBar.top + 1, info.dxyLineButton + 1);
331         }
332     } */
333 END:;
334 /*    WIN_ReleaseWndPtr(wndPtr); */
335 }
336
337 WINBOOL STDCALL
338 GetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
339 {
340   UNIMPLEMENTED;
341   return FALSE;
342 }
343
344 int STDCALL
345 GetScrollPos (HWND hWnd, int nBar)
346 {
347   UNIMPLEMENTED;
348   return 0;
349 }
350
351 WINBOOL STDCALL
352 GetScrollRange (HWND hWnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos)
353 {
354   UNIMPLEMENTED;
355   return FALSE;
356 }
357
358 int STDCALL
359 SetScrollInfo (HWND hwnd, int fnBar, LPCSCROLLINFO lpsi, WINBOOL fRedraw)
360 {
361   UNIMPLEMENTED;
362   return 0;
363 }
364
365 int STDCALL
366 SetScrollPos (HWND hWnd, int nBar, int nPos, WINBOOL bRedraw)
367 {
368   UNIMPLEMENTED;
369   return 0;
370 }
371
372 WINBOOL STDCALL
373 SetScrollRange (HWND hWnd,
374                 int nBar, int nMinPos, int nMaxPos, WINBOOL bRedraw)
375 {
376   UNIMPLEMENTED;
377   return FALSE;
378 }
379
380 /* Ported from WINE20020904 */
381 WINBOOL STDCALL
382 ShowScrollBar (HWND hWnd, int wBar, WINBOOL bShow)
383 {
384   NtUserShowScrollBar (hWnd, wBar, bShow);
385   return TRUE;
386 }