From: Jacek Caban jacek@codeweavers.com
--- dlls/user32/scroll.c | 39 --------- dlls/win32u/ntgdi_private.h | 1 - dlls/win32u/scroll.c | 158 +++++++++++++++++++++++++++++++++++ dlls/win32u/win32u_private.h | 1 + 4 files changed, 159 insertions(+), 40 deletions(-)
diff --git a/dlls/user32/scroll.c b/dlls/user32/scroll.c index cc847b48ec6..01f7f3b88ae 100644 --- a/dlls/user32/scroll.c +++ b/dlls/user32/scroll.c @@ -1385,46 +1385,7 @@ LRESULT WINAPI USER_ScrollBarProc( HWND hwnd, UINT message, WPARAM wParam, LPARA break;
case WM_SETFOCUS: - { - /* Create a caret when a ScrollBar get focus */ - RECT rect; - int arrowSize, thumbSize, thumbPos, vertical; - vertical = SCROLL_GetScrollBarRect( hwnd, SB_CTL, &rect, - &arrowSize, &thumbSize, &thumbPos ); - if (!vertical) - { - NtUserCreateCaret( hwnd, (HBITMAP)1, thumbSize - 2, rect.bottom - rect.top - 2 ); - SetCaretPos(thumbPos+1, rect.top+1); - } - else - { - NtUserCreateCaret( hwnd, (HBITMAP)1, rect.right - rect.left - 2, thumbSize - 2); - SetCaretPos(rect.top+1, thumbPos+1); - } - NtUserShowCaret( hwnd ); - } - break; - case WM_KILLFOCUS: - { - RECT rect; - int arrowSize, thumbSize, thumbPos, vertical; - vertical = SCROLL_GetScrollBarRect( hwnd, SB_CTL, &rect,&arrowSize, &thumbSize, &thumbPos ); - if (!vertical){ - rect.left=thumbPos+1; - rect.right=rect.left+thumbSize; - } - else - { - rect.top=thumbPos+1; - rect.bottom=rect.top+thumbSize; - } - NtUserHideCaret( hwnd ); - NtUserInvalidateRect( hwnd, &rect, 0 ); - DestroyCaret(); - } - break; - case WM_CREATE: case WM_ERASEBKGND: case WM_GETDLGCODE: diff --git a/dlls/win32u/ntgdi_private.h b/dlls/win32u/ntgdi_private.h index ac552897769..0397138b109 100644 --- a/dlls/win32u/ntgdi_private.h +++ b/dlls/win32u/ntgdi_private.h @@ -391,7 +391,6 @@ extern void lp_to_dp( DC *dc, POINT *points, INT count ) DECLSPEC_HIDDEN; extern BOOL set_map_mode( DC *dc, int mode ) DECLSPEC_HIDDEN; extern void combine_transform( XFORM *result, const XFORM *xform1, const XFORM *xform2 ) DECLSPEC_HIDDEN; -extern int muldiv( int a, int b, int c ) DECLSPEC_HIDDEN;
/* driver.c */ extern BOOL is_display_device( LPCWSTR name ) DECLSPEC_HIDDEN; diff --git a/dlls/win32u/scroll.c b/dlls/win32u/scroll.c index a15c8bfd36d..14bec1e3b83 100644 --- a/dlls/win32u/scroll.c +++ b/dlls/win32u/scroll.c @@ -32,6 +32,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(scroll);
#define SCROLLBAR_MAGIC 0x5c6011ba
+/* Minimum size of the rectangle between the arrows */ +#define SCROLL_MIN_RECT 4 + +/* Minimum size of the thumb in pixels */ +#define SCROLL_MIN_THUMB 8 + +/* Overlap between arrows and thumb */ +#define SCROLL_ARROW_THUMB_OVERLAP 0 + static struct scroll_info *get_scroll_info_ptr( HWND hwnd, int bar, BOOL alloc ) { struct scroll_info *ret = NULL; @@ -84,6 +93,113 @@ static BOOL show_scroll_bar( HWND hwnd, int bar, BOOL show_horz, BOOL show_vert return FALSE; /* no frame changes */ }
+/*********************************************************************** + * get_scroll_bar_rect + * + * Compute the scroll bar rectangle, in drawing coordinates (i.e. client + * coords for SB_CTL, window coords for SB_VERT and SB_HORZ). + * 'arrow_size' returns the width or height of an arrow (depending on + * the orientation of the scrollbar), 'thumb_size' returns the size of + * the thumb, and 'thumb_pos' returns the position of the thumb + * relative to the left or to the top. + * Return TRUE if the scrollbar is vertical, FALSE if horizontal. + */ +static BOOL get_scroll_bar_rect( HWND hwnd, int bar, RECT *rect, int *arrow_size, + int *thumb_size, int *thumb_pos ) +{ + int pixels, min_thumb_size; + BOOL vertical; + WND *win = get_win_ptr( hwnd ); + + if (!win || win == WND_OTHER_PROCESS || win == WND_DESKTOP) return FALSE; + + switch(bar) + { + case SB_HORZ: + get_window_rects( hwnd, COORDS_WINDOW, NULL, rect, get_thread_dpi() ); + rect->top = rect->bottom; + rect->bottom += get_system_metrics( SM_CYHSCROLL ); + if (win->dwStyle & WS_VSCROLL) rect->right++; + vertical = FALSE; + break; + + case SB_VERT: + get_window_rects( hwnd, COORDS_WINDOW, NULL, rect, get_thread_dpi() ); + if (win->dwExStyle & WS_EX_LEFTSCROLLBAR) + { + rect->right = rect->left; + rect->left -= get_system_metrics( SM_CXVSCROLL ); + } + else + { + rect->left = rect->right; + rect->right += get_system_metrics( SM_CXVSCROLL ); + } + if (win->dwStyle & WS_HSCROLL) rect->bottom++; + vertical = TRUE; + break; + + case SB_CTL: + get_client_rect( hwnd, rect ); + vertical = (win->dwStyle & SBS_VERT) != 0; + break; + + default: + release_win_ptr( win ); + return FALSE; + } + + if (vertical) pixels = rect->bottom - rect->top; + else pixels = rect->right - rect->left; + + if (pixels <= 2 * get_system_metrics( SM_CXVSCROLL ) + SCROLL_MIN_RECT) + { + if (pixels > SCROLL_MIN_RECT) + *arrow_size = (pixels - SCROLL_MIN_RECT) / 2; + else + *arrow_size = 0; + *thumb_pos = *thumb_size = 0; + } + else + { + struct scroll_info *info = get_scroll_info_ptr( hwnd, bar, TRUE ); + if (!info) + { + WARN( "called for missing scroll bar\n" ); + release_win_ptr( win ); + return FALSE; + } + *arrow_size = get_system_metrics( SM_CXVSCROLL ); + pixels -= 2 * (get_system_metrics( SM_CXVSCROLL ) - SCROLL_ARROW_THUMB_OVERLAP); + + if (info->page) + { + *thumb_size = muldiv( pixels,info->page, info->maxVal - info->minVal + 1 ); + min_thumb_size = muldiv( SCROLL_MIN_THUMB, get_dpi_for_window( hwnd ), 96 ); + if (*thumb_size < min_thumb_size) *thumb_size = min_thumb_size; + } + else *thumb_size = get_system_metrics( SM_CXVSCROLL ); + + if ((pixels -= *thumb_size ) < 0 || (info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH) + { + /* Rectangle too small or scrollbar disabled -> no thumb */ + *thumb_pos = *thumb_size = 0; + } + else + { + int max = info->maxVal - max( info->page-1, 0 ); + if (info->minVal >= max) + *thumb_pos = *arrow_size - SCROLL_ARROW_THUMB_OVERLAP; + else + *thumb_pos = *arrow_size - SCROLL_ARROW_THUMB_OVERLAP + + muldiv( pixels, info->curVal - info->minVal, max - info->minVal ); + } + release_scroll_info_ptr( info ); + } + release_win_ptr( win ); + return vertical; +} + static void create_scroll_bar( HWND hwnd, CREATESTRUCTW *create ) { struct scroll_info *info = NULL; @@ -148,6 +264,48 @@ LRESULT scroll_bar_window_proc( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lpara create_scroll_bar( hwnd, (CREATESTRUCTW *)lparam ); return 0;
+ case WM_SETFOCUS: + { + /* Create a caret when a ScrollBar get focus */ + RECT rect; + int arrow_size, thumb_size, thumb_pos, vertical; + vertical = get_scroll_bar_rect( hwnd, SB_CTL, &rect, &arrow_size, + &thumb_size, &thumb_pos ); + if (!vertical) + { + NtUserCreateCaret( hwnd, (HBITMAP)1, thumb_size - 2, rect.bottom - rect.top - 2 ); + set_caret_pos( thumb_pos + 1, rect.top + 1 ); + } + else + { + NtUserCreateCaret( hwnd, (HBITMAP)1, rect.right - rect.left - 2, thumb_size - 2 ); + set_caret_pos( rect.top + 1, thumb_pos + 1 ); + } + NtUserShowCaret( hwnd ); + } + return 0; + + case WM_KILLFOCUS: + { + int arrow_size, thumb_size, thumb_pos, vertical; + RECT rect; + vertical = get_scroll_bar_rect( hwnd, SB_CTL, &rect,&arrow_size, &thumb_size, &thumb_pos ); + if (!vertical) + { + rect.left = thumb_pos + 1; + rect.right = rect.left + thumb_size; + } + else + { + rect.top = thumb_pos + 1; + rect.bottom = rect.top + thumb_size; + } + NtUserHideCaret( hwnd ); + NtUserInvalidateRect( hwnd, &rect, 0 ); + destroy_caret(); + } + return 0; + case WM_ERASEBKGND: return 1;
diff --git a/dlls/win32u/win32u_private.h b/dlls/win32u/win32u_private.h index 684a5e59c5b..49c81ea3bef 100644 --- a/dlls/win32u/win32u_private.h +++ b/dlls/win32u/win32u_private.h @@ -535,6 +535,7 @@ extern NTSTATUS gdi_init(void) DECLSPEC_HIDDEN; extern NTSTATUS callbacks_init( void *args ) DECLSPEC_HIDDEN; extern void winstation_init(void) DECLSPEC_HIDDEN; extern void sysparams_init(void) DECLSPEC_HIDDEN; +extern int muldiv( int a, int b, int c ) DECLSPEC_HIDDEN;
extern HKEY reg_create_key( HKEY root, const WCHAR *name, ULONG name_len, DWORD options, DWORD *disposition ) DECLSPEC_HIDDEN;