gdi32/tests: Mark tests failing randomly on Windows as flaky.
[wine.git] / dlls / user32 / scroll.c
blob788b5091698e18152aaa42c08582ffcf5f9a1975
1 /*
2 * Scrollbar control
4 * Copyright 1993 Martin Ayotte
5 * Copyright 1994, 1996 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include "user_private.h"
23 #include "controls.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(scroll);
29 /* Overlap between arrows and thumb */
30 #define SCROLL_ARROW_THUMB_OVERLAP 0
33 /***********************************************************************
34 * SCROLL_DrawArrows
36 * Draw the scroll bar arrows.
38 static void SCROLL_DrawArrows( HDC hdc, UINT flags,
39 RECT *rect, INT arrowSize, BOOL vertical,
40 BOOL top_pressed, BOOL bottom_pressed )
42 RECT r;
44 r = *rect;
45 if( vertical )
46 r.bottom = r.top + arrowSize;
47 else
48 r.right = r.left + arrowSize;
50 DrawFrameControl( hdc, &r, DFC_SCROLL,
51 (vertical ? DFCS_SCROLLUP : DFCS_SCROLLLEFT)
52 | (top_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
53 | (flags & ESB_DISABLE_LTUP ? DFCS_INACTIVE : 0 ) );
55 r = *rect;
56 if( vertical )
57 r.top = r.bottom-arrowSize;
58 else
59 r.left = r.right-arrowSize;
61 DrawFrameControl( hdc, &r, DFC_SCROLL,
62 (vertical ? DFCS_SCROLLDOWN : DFCS_SCROLLRIGHT)
63 | (bottom_pressed ? (DFCS_PUSHED | DFCS_FLAT) : 0 )
64 | (flags & ESB_DISABLE_RTDN ? DFCS_INACTIVE : 0) );
67 /***********************************************************************
68 * SCROLL_DrawInterior
70 * Draw the scroll bar interior (everything except the arrows).
72 static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, INT nBar,
73 RECT *rect, INT arrowSize,
74 INT thumbSize, INT thumbPos, BOOL vertical,
75 BOOL top_selected, BOOL bottom_selected )
77 RECT r;
78 HPEN hSavePen;
79 HBRUSH hSaveBrush,hBrush;
81 if (nBar == SB_CTL)
83 hBrush = (HBRUSH)SendMessageW( GetParent(hwnd), WM_CTLCOLORSCROLLBAR,
84 (WPARAM)hdc,(LPARAM)hwnd);
86 else
88 COLORREF bk = GetSysColor( COLOR_3DHILIGHT );
89 SetTextColor( hdc, GetSysColor( COLOR_3DFACE ));
90 SetBkColor( hdc, bk );
92 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT
93 * we better use 0x55aa bitmap brush to make scrollbar's background
94 * look different from the window background.
96 if (bk == GetSysColor( COLOR_WINDOW ))
97 hBrush = SYSCOLOR_Get55AABrush();
98 else
100 hBrush = GetSysColorBrush( COLOR_SCROLLBAR );
101 UnrealizeObject( hBrush );
105 hSavePen = SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
106 hSaveBrush = SelectObject( hdc, hBrush );
108 /* Calculate the scroll rectangle */
110 r = *rect;
111 if (vertical)
113 r.top += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
114 r.bottom -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
116 else
118 r.left += arrowSize - SCROLL_ARROW_THUMB_OVERLAP;
119 r.right -= (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
122 /* Draw the scroll bar frame */
124 /* Draw the scroll rectangles and thumb */
126 if (!thumbPos) /* No thumb to draw */
128 PatBlt( hdc, r.left, r.top, r.right - r.left, r.bottom - r.top, PATCOPY );
130 /* cleanup and return */
131 SelectObject( hdc, hSavePen );
132 SelectObject( hdc, hSaveBrush );
133 return;
136 if (vertical)
138 PatBlt( hdc, r.left, r.top, r.right - r.left,
139 thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
140 top_selected ? 0x0f0000 : PATCOPY );
141 r.top += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
142 PatBlt( hdc, r.left, r.top + thumbSize, r.right - r.left,
143 r.bottom - r.top - thumbSize,
144 bottom_selected ? 0x0f0000 : PATCOPY );
145 r.bottom = r.top + thumbSize;
147 else /* horizontal */
149 PatBlt( hdc, r.left, r.top,
150 thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP),
151 r.bottom - r.top, top_selected ? 0x0f0000 : PATCOPY );
152 r.left += thumbPos - (arrowSize - SCROLL_ARROW_THUMB_OVERLAP);
153 PatBlt( hdc, r.left + thumbSize, r.top, r.right - r.left - thumbSize,
154 r.bottom - r.top, bottom_selected ? 0x0f0000 : PATCOPY );
155 r.right = r.left + thumbSize;
158 /* Draw the thumb */
160 SelectObject( hdc, GetSysColorBrush(COLOR_BTNFACE) );
161 Rectangle( hdc, r.left+1, r.top+1, r.right-1, r.bottom-1 );
162 DrawEdge( hdc, &r, EDGE_RAISED, BF_RECT );
164 /* cleanup */
165 SelectObject( hdc, hSavePen );
166 SelectObject( hdc, hSaveBrush );
169 void WINAPI USER_ScrollBarDraw( HWND hwnd, HDC hdc, INT nBar, enum SCROLL_HITTEST hit_test,
170 const struct SCROLL_TRACKING_INFO *tracking_info, BOOL arrows,
171 BOOL interior, RECT *rect, UINT enable_flags, INT arrowSize,
172 INT thumbPos, INT thumbSize, BOOL vertical )
174 if (nBar == SB_CTL)
176 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
178 if (style & SBS_SIZEGRIP)
180 RECT rc = *rect;
182 FillRect( hdc, &rc, GetSysColorBrush( COLOR_BTNFACE ) );
183 rc.left = max( rc.left, rc.right - GetSystemMetrics( SM_CXVSCROLL ) - 1 );
184 rc.top = max( rc.top, rc.bottom - GetSystemMetrics( SM_CYHSCROLL ) - 1 );
185 DrawFrameControl( hdc, &rc, DFC_SCROLL, DFCS_SCROLLSIZEGRIP );
186 return;
189 if (style & SBS_SIZEBOX)
191 FillRect( hdc, rect, GetSysColorBrush( COLOR_BTNFACE ) );
192 return;
196 /* Draw the arrows */
197 if (arrows && arrowSize)
199 if (vertical == tracking_info->vertical && GetCapture() == hwnd)
200 SCROLL_DrawArrows( hdc, enable_flags, rect, arrowSize, vertical,
201 hit_test == tracking_info->hit_test && hit_test == SCROLL_TOP_ARROW,
202 hit_test == tracking_info->hit_test && hit_test == SCROLL_BOTTOM_ARROW );
203 else
204 SCROLL_DrawArrows( hdc, enable_flags, rect, arrowSize, vertical, FALSE, FALSE );
207 if (interior)
209 if (vertical == tracking_info->vertical && GetCapture() == hwnd)
211 SCROLL_DrawInterior( hwnd, hdc, nBar, rect, arrowSize, thumbSize, thumbPos, vertical,
212 hit_test == tracking_info->hit_test && hit_test == SCROLL_TOP_RECT,
213 hit_test == tracking_info->hit_test && hit_test == SCROLL_BOTTOM_RECT );
215 else
217 SCROLL_DrawInterior( hwnd, hdc, nBar, rect, arrowSize, thumbSize, thumbPos,
218 vertical, FALSE, FALSE );
222 /* if scroll bar has focus, reposition the caret */
223 if(hwnd==GetFocus() && (nBar==SB_CTL))
225 if (!vertical)
227 SetCaretPos(thumbPos + 1, rect->top + 1);
229 else
231 SetCaretPos(rect->top + 1, thumbPos + 1);
236 LRESULT WINAPI USER_ScrollBarProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, BOOL unicode )
238 switch(message)
240 case WM_KEYDOWN:
241 case WM_KEYUP:
242 case WM_ENABLE:
243 case WM_LBUTTONDBLCLK:
244 case WM_LBUTTONDOWN:
245 case WM_LBUTTONUP:
246 case WM_NCMOUSEMOVE:
247 case WM_NCMOUSELEAVE:
248 case WM_MOUSEMOVE:
249 case WM_MOUSELEAVE:
250 case WM_SYSTIMER:
251 case WM_SETFOCUS:
252 case WM_KILLFOCUS:
253 case WM_CREATE:
254 case WM_ERASEBKGND:
255 case WM_GETDLGCODE:
256 case WM_PAINT:
257 case SBM_SETRANGEREDRAW:
258 case SBM_SETRANGE:
259 case SBM_GETSCROLLINFO:
260 case SBM_GETSCROLLBARINFO:
261 case SBM_SETSCROLLINFO:
262 case WM_SETCURSOR:
263 case SBM_SETPOS:
264 case SBM_GETPOS:
265 case SBM_GETRANGE:
266 case SBM_ENABLE_ARROWS:
267 case 0x00e5:
268 case 0x00e7:
269 case 0x00e8:
270 case 0x00ec:
271 case 0x00ed:
272 case 0x00ee:
273 case 0x00ef:
274 return NtUserMessageCall( hwnd, message, wParam, lParam, 0, NtUserScrollBarWndProc, !unicode );
276 default:
277 if (message >= WM_USER)
278 WARN("unknown msg %04x wp=%04Ix lp=%08Ix\n",
279 message, wParam, lParam );
280 if (unicode)
281 return DefWindowProcW( hwnd, message, wParam, lParam );
282 else
283 return DefWindowProcA( hwnd, message, wParam, lParam );
285 return 0;
288 /***********************************************************************
289 * ScrollBarWndProc_common
291 LRESULT ScrollBarWndProc_common( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam, BOOL unicode )
293 return user_api->pScrollBarWndProc( hwnd, msg, wParam, lParam, unicode );
297 /*************************************************************************
298 * GetScrollInfo (USER32.@)
300 * GetScrollInfo can be used to retrieve the position, upper bound,
301 * lower bound, and page size of a scrollbar control.
303 * PARAMS
304 * hwnd [I] Handle of window with scrollbar(s)
305 * nBar [I] One of SB_HORZ, SB_VERT, or SB_CTL
306 * info [IO] fMask specifies which values to retrieve
308 * RETURNS
309 * TRUE if SCROLLINFO is filled
310 * ( if nBar is SB_CTL, GetScrollInfo returns TRUE even if nothing
311 * is filled)
313 BOOL WINAPI DECLSPEC_HOTPATCH GetScrollInfo(HWND hwnd, INT nBar, LPSCROLLINFO info)
315 TRACE("hwnd=%p nBar=%d info=%p\n", hwnd, nBar, info);
317 /* Refer SB_CTL requests to the window */
318 if (nBar == SB_CTL)
320 SendMessageW(hwnd, SBM_GETSCROLLINFO, 0, (LPARAM)info);
321 return TRUE;
323 return NtUserGetScrollInfo( hwnd, nBar, info );
327 /*************************************************************************
328 * SetScrollPos (USER32.@)
330 * Sets the current position of the scroll thumb.
332 * PARAMS
333 * hwnd [I] Handle of window with scrollbar(s)
334 * nBar [I] One of SB_HORZ, SB_VERT, or SB_CTL
335 * nPos [I] New value
336 * bRedraw [I] Should scrollbar be redrawn afterwards?
338 * RETURNS
339 * Success: Scrollbar position
340 * Failure: 0
342 * REMARKS
343 * Note the ambiguity when 0 is returned. Use GetLastError
344 * to make sure there was an error (and to know which one).
346 int WINAPI DECLSPEC_HOTPATCH SetScrollPos( HWND hwnd, int bar, int pos, BOOL redraw )
348 SCROLLINFO info;
350 info.cbSize = sizeof(info);
351 info.nPos = pos;
352 info.fMask = SIF_POS | SIF_RETURNPREV;
353 return NtUserSetScrollInfo( hwnd, bar, &info, redraw );
357 /*************************************************************************
358 * GetScrollPos (USER32.@)
360 * Gets the current position of the scroll thumb.
362 * PARAMS
363 * hwnd [I] Handle of window with scrollbar(s)
364 * nBar [I] One of SB_HORZ, SB_VERT, or SB_CTL
366 * RETURNS
367 * Success: Current position
368 * Failure: 0
370 * REMARKS
371 * There is ambiguity when 0 is returned. Use GetLastError
372 * to make sure there was an error (and to know which one).
374 int WINAPI DECLSPEC_HOTPATCH GetScrollPos( HWND hwnd, int bar )
376 SCROLLINFO info;
378 TRACE( "hwnd=%p bar=%d\n", hwnd, bar );
380 /* Refer SB_CTL requests to the window */
381 if (bar == SB_CTL)
382 return SendMessageW( hwnd, SBM_GETPOS, 0, 0 );
384 info.cbSize = sizeof(info);
385 info.fMask = SIF_POS;
386 return GetScrollInfo( hwnd, bar, &info ) ? info.nPos : 0;
390 /*************************************************************************
391 * SetScrollRange (USER32.@)
392 * The SetScrollRange function sets the minimum and maximum scroll box positions
393 * If nMinPos and nMaxPos is the same value, the scroll bar will hide
395 * Sets the range of the scroll bar.
397 * PARAMS
398 * hwnd [I] Handle of window with scrollbar(s)
399 * nBar [I] One of SB_HORZ, SB_VERT, or SB_CTL
400 * minVal [I] New minimum value
401 * maxVal [I] New Maximum value
402 * bRedraw [I] Should scrollbar be redrawn afterwards?
404 * RETURNS
405 * Success: TRUE
406 * Failure: FALSE
408 BOOL WINAPI DECLSPEC_HOTPATCH SetScrollRange(HWND hwnd, INT nBar, INT minVal, INT maxVal, BOOL bRedraw)
410 SCROLLINFO info;
412 TRACE("hwnd=%p nBar=%d min=%d max=%d, bRedraw=%d\n", hwnd, nBar, minVal, maxVal, bRedraw);
414 info.cbSize = sizeof(info);
415 info.fMask = SIF_RANGE;
416 info.nMin = minVal;
417 info.nMax = maxVal;
418 NtUserSetScrollInfo( hwnd, nBar, &info, bRedraw );
419 return TRUE;
423 /*************************************************************************
424 * GetScrollRange (USER32.@)
426 * Gets the range of the scroll bar.
428 * PARAMS
429 * hwnd [I] Handle of window with scrollbar(s)
430 * nBar [I] One of SB_HORZ, SB_VERT, or SB_CTL
431 * lpMin [O] Where to store minimum value
432 * lpMax [O] Where to store maximum value
434 * RETURNS
435 * TRUE if values is filled
437 BOOL WINAPI DECLSPEC_HOTPATCH GetScrollRange( HWND hwnd, int bar, int *min, int *max )
439 SCROLLINFO info;
441 TRACE( "hwnd=%p nBar=%d lpMin=%p lpMax=%p\n", hwnd, bar, min, max );
443 /* Refer SB_CTL requests to the window */
444 if (bar == SB_CTL)
446 SendMessageW( hwnd, SBM_GETRANGE, (WPARAM)min, (LPARAM)max );
447 return TRUE;
450 info.cbSize = sizeof(info);
451 info.fMask = SIF_RANGE;
452 info.nMin = info.nMax = 0;
453 GetScrollInfo( hwnd, bar, &info );
454 if (min) *min = info.nMin;
455 if (max) *max = info.nMax;
456 return TRUE;