branch update for HEAD-2003050101
[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 #include <windows.h>
14 #include <user32.h>
15 #include <debug.h>
16
17 /* GLOBAL VARIABLES **********************************************************/
18 /*
19 static HBITMAP hUpArrow;
20 static HBITMAP hDnArrow;
21 static HBITMAP hLfArrow;
22 static HBITMAP hRgArrow;
23 static HBITMAP hUpArrowD;
24 static HBITMAP hDnArrowD;
25 static HBITMAP hLfArrowD;
26 static HBITMAP hRgArrowD;
27 static HBITMAP hUpArrowI;
28 static HBITMAP hDnArrowI;
29 static HBITMAP hLfArrowI;
30 static HBITMAP hRgArrowI;
31 */
32 #define TOP_ARROW(flags,pressed) \
33    (((flags)&ESB_DISABLE_UP) ? hUpArrowI : ((pressed) ? hUpArrowD:hUpArrow))
34 #define BOTTOM_ARROW(flags,pressed) \
35    (((flags)&ESB_DISABLE_DOWN) ? hDnArrowI : ((pressed) ? hDnArrowD:hDnArrow))
36 #define LEFT_ARROW(flags,pressed) \
37    (((flags)&ESB_DISABLE_LEFT) ? hLfArrowI : ((pressed) ? hLfArrowD:hLfArrow))
38 #define RIGHT_ARROW(flags,pressed) \
39    (((flags)&ESB_DISABLE_RIGHT) ? hRgArrowI : ((pressed) ? hRgArrowD:hRgArrow))
40
41 #define SCROLL_ARROW_THUMB_OVERLAP 0     /* Overlap between arrows and thumb */
42 #define SCROLL_MIN_THUMB 6               /* Minimum size of the thumb in pixels */
43 #define SCROLL_FIRST_DELAY   200         /* Delay (in ms) before first repetition when holding the button down */
44 #define SCROLL_REPEAT_DELAY  50          /* Delay (in ms) between scroll repetitions */
45 #define SCROLL_TIMER   0                 /* Scroll timer id */
46
47  /* What to do after SCROLL_SetScrollInfo() */
48 #define SA_SSI_HIDE             0x0001
49 #define SA_SSI_SHOW             0x0002
50 #define SA_SSI_REFRESH          0x0004
51 #define SA_SSI_REPAINT_ARROWS   0x0008
52
53   /* Scroll-bar hit testing */
54 enum SCROLL_HITTEST
55 {
56   SCROLL_NOWHERE,               /* Outside the scroll bar */
57   SCROLL_TOP_ARROW,             /* Top or left arrow */
58   SCROLL_TOP_RECT,              /* Rectangle between the top arrow and the thumb */
59   SCROLL_THUMB,                 /* Thumb rectangle */
60   SCROLL_BOTTOM_RECT,           /* Rectangle between the thumb and the bottom arrow */
61   SCROLL_BOTTOM_ARROW           /* Bottom or right arrow */
62 };
63
64 static BOOL SCROLL_MovingThumb = FALSE; /* Is the moving thumb being displayed? */
65
66 /* Thumb-tracking info */
67 static HWND SCROLL_TrackingWin = 0;
68 static INT SCROLL_TrackingBar = 0;
69 static INT SCROLL_TrackingPos = 0;
70 /* static INT  SCROLL_TrackingVal = 0; */
71 static enum SCROLL_HITTEST SCROLL_trackHitTest; /* Hit test code of the last button-down event */
72 static BOOL SCROLL_trackVertical;
73
74 /* FUNCTIONS
75 *****************************************************************/
76
77 HBRUSH DefWndControlColor (HDC hDC, UINT ctlType);
78 HPEN STDCALL GetSysColorPen (int nIndex);
79
80
81
82 WINBOOL STDCALL
83 GetScrollBarInfo (HWND hwnd, LONG idObject, PSCROLLBARINFO psbi)
84 {
85   int ret = NtUserGetScrollBarInfo (hwnd, idObject, psbi);
86
87   return ret;
88 }
89
90 /* Ported from WINE20020904 */
91 /* Draw the scroll bar interior (everything except the arrows). */
92 static void
93 SCROLL_DrawInterior (HWND hwnd, HDC hdc, INT nBar, BOOL vertical, INT
94 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, (WPARAM) hdc, (LPARAM) hwnd);
117   }
118   else
119   {
120 /*    hBrush = NtUserGetControlColor (hdc, CTLCOLOR_SCROLLBAR); FIXME
121 */ /* 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 (vertical)
130   {
131     psbi->rcScrollBar.top += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
132     psbi->rcScrollBar.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
133   }
134   else
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 (vertical)
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
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, BOOL vertical, int arrowSize, int thumbSize, PSCROLLBARINFO psbi)
202 {
203   INT pos = SCROLL_TrackingPos;
204   INT max_size;
205
206   if ( vertical )
207     max_size = psbi->rcScrollBar.bottom - psbi->rcScrollBar.top;
208   else
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, vertical, 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, BOOL vertical,
228            BOOL top_pressed, BOOL bottom_pressed)
229 {
230   RECT r1, r2;
231   int scrollDirFlag1, scrollDirFlag2;
232
233   r1 = r2 = *rect;
234   if (vertical)
235   {
236     scrollDirFlag1 = DFCS_SCROLLUP;
237     scrollDirFlag2 = DFCS_SCROLLDOWN;
238     r1.bottom = r1.top + arrowSize;
239     r2.top = r2.bottom - arrowSize;
240   }
241   else
242   {
243     scrollDirFlag1 = DFCS_SCROLLLEFT;
244     scrollDirFlag2 = DFCS_SCROLLRIGHT;
245     r1.right = r1.left + arrowSize;
246     r2.left = r2.right - arrowSize;
247   }
248
249   DrawFrameControl (hdc, &r1, DFC_SCROLL,
250             scrollDirFlag1 | (top_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0)
251             /* | (info.flags&ESB_DISABLE_LTUP ? DFCS_INACTIVE : 0) */
252     );
253   DrawFrameControl (hdc, &r2, DFC_SCROLL,
254             scrollDirFlag2 | (bottom_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0)
255             /* | (info.flags&ESB_DISABLE_RTDN ? DFCS_INACTIVE : 0) */
256     );
257 }
258
259 /* Ported from WINE20020904 */
260 /* Redraw the whole scrollbar. */
261 void
262 SCROLL_DrawScrollBar (HWND hwnd, HDC hdc, INT nBar,
263                       BOOL arrows, BOOL interior)
264 {
265   INT arrowSize = 0;
266   INT thumbSize;
267   SCROLLBARINFO info;
268   BOOL Save_SCROLL_MovingThumb = SCROLL_MovingThumb;
269   BOOL vertical;
270
271   info.cbSize = sizeof(SCROLLBARINFO);
272   GetScrollBarInfo (hwnd, nBar, &info);
273
274   thumbSize = info.xyThumbBottom - info.xyThumbTop;
275
276   switch ( nBar )
277   {
278   case SB_HORZ:
279     vertical = FALSE;
280     break;
281   case SB_VERT:
282     vertical = TRUE;
283     break;
284   case SB_CTL:
285     vertical = (GetWindowLong(hwnd,GWL_STYLE)&SBS_VERT) != 0;
286     break;
287 #ifdef DBG
288   default:
289     DASSERT(!"SCROLL_DrawScrollBar() called with invalid nBar");
290     break;
291 #endif /* DBG */
292   }
293
294   if (vertical)
295     arrowSize = GetSystemMetrics(SM_CXVSCROLL);
296   else
297     arrowSize = GetSystemMetrics(SM_CYHSCROLL);
298
299   if (IsRectEmpty (&(info.rcScrollBar))) goto END;
300
301   if (Save_SCROLL_MovingThumb && (SCROLL_TrackingWin == hwnd) && (SCROLL_TrackingBar == nBar))
302   {
303     SCROLL_DrawMovingThumb (hdc, &(info.rcScrollBar), vertical, arrowSize, thumbSize, &info);
304   }
305
306   /* Draw the arrows */
307   if (arrows && arrowSize)
308   {
309     if (SCROLL_trackVertical == TRUE /* && GetCapture () == hwnd */)
310     {
311       SCROLL_DrawArrows (hdc, &info, &(info.rcScrollBar), arrowSize, vertical,
312                          (SCROLL_trackHitTest == SCROLL_TOP_ARROW),
313                          (SCROLL_trackHitTest == SCROLL_BOTTOM_ARROW));
314     }
315     else
316     {
317       SCROLL_DrawArrows (hdc, &info, &(info.rcScrollBar), arrowSize, vertical, FALSE, FALSE);
318     }
319   }
320
321   if (interior)
322   {
323     SCROLL_DrawInterior (hwnd, hdc, nBar, vertical, arrowSize, &info);
324   }
325
326   if (Save_SCROLL_MovingThumb &&
327       (SCROLL_TrackingWin == hwnd) && (SCROLL_TrackingBar == nBar))
328     SCROLL_DrawMovingThumb (hdc, &info.rcScrollBar, vertical, arrowSize, thumbSize, &info);
329   /* if scroll bar has focus, reposition the caret */
330
331 /*  if (hwnd == GetFocus () && (nBar == SB_CTL))
332     {
333       if (nBar == SB_HORZ)
334       {
335         SetCaretPos (info.dxyLineButton + 1, info.rcScrollBar.top + 1);
336       }
337       else if (nBAR == SB_VERT)
338       {
339         SetCaretPos (info.rcScrollBar.top + 1, info.dxyLineButton + 1);
340       }
341     } */
342 END:;
343 /*    WIN_ReleaseWndPtr(wndPtr); */
344 }
345
346 WINBOOL STDCALL
347 GetScrollInfo (HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
348 {
349   UNIMPLEMENTED;
350   return FALSE;
351 }
352
353 int STDCALL
354 GetScrollPos (HWND hWnd, int nBar)
355 {
356   UNIMPLEMENTED;
357   return 0;
358 }
359
360 WINBOOL STDCALL
361 GetScrollRange (HWND hWnd, int nBar, LPINT lpMinPos, LPINT lpMaxPos)
362 {
363   UNIMPLEMENTED;
364   return FALSE;
365 }
366
367 int STDCALL
368 SetScrollInfo (HWND hwnd, int fnBar, LPCSCROLLINFO lpsi, WINBOOL fRedraw)
369 {
370   UNIMPLEMENTED;
371   return 0;
372 }
373
374 int STDCALL
375 SetScrollPos (HWND hWnd, int nBar, int nPos, WINBOOL bRedraw)
376 {
377   UNIMPLEMENTED;
378   return 0;
379 }
380
381 WINBOOL STDCALL
382 SetScrollRange (HWND hWnd,
383                 int nBar, int nMinPos, int nMaxPos, WINBOOL bRedraw)
384 {
385   UNIMPLEMENTED;
386   return FALSE;
387 }
388
389 /* Ported from WINE20020904 */
390 WINBOOL STDCALL
391 ShowScrollBar (HWND hWnd, int wBar, WINBOOL bShow)
392 {
393   NtUserShowScrollBar (hWnd, wBar, bShow);
394   return TRUE;
395 }