1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00
wine/controls/scroll.c
Alexandre Julliard 0c126c7c61 Release 960218
Sun Feb 18 16:35:54 1996  Alexandre Julliard  <julliard@lrc.epfl.ch>

	* [controls/desktop.c]
	Look for the wallpaper file in the Windows directory.

	* [controls/menu.c]
	Fixed swapped parameters in SetMenuItemBitmaps().
	Create a separator in MENU_SetItemData() when the string is NULL.

	* [file/dosfs.c]
	DOSFS_FindNext: don't return '.' and '..' in a drive root dir.

	* [files/file.c]
	Added a DOS_FILE structure to store per-file information (not
	really used yet).
	Fixed _lread and _hread to check the size of the buffer before
	calling Unix read() to avoid EFAULT error.

	* [misc/exec.c]
	Return TRUE in WinHelp() for HELP_QUIT to quiet Notepad on exit.

	* [miscemu/instr.c]
	Call DOSMEM_Alarm() in INSTR_ReplaceSelector(). This should fix
 	programs that poll the BIOS counter, provided they reload the
 	selector on every read.

	* [miscemu/int21.c]
	Re-implemented FindFirst/FindNext for FCB calls.

	* [windows/message.c] [windows/winpos.c]
	Merged MSG_GetWindowForEvent() and WINPOS_WindowFromPoint().

	* [windows/nonclient.c] [windows/win.c] [include/windows.h]
	Added a per-window WIN_MANAGED flag; only windows that have a
	dialog frame or a sizing border are managed.

Sat Feb 17 18:25:00 1996  Thomas Sandford <tdgsandf@prds-grn.demon.co.uk>

	* [if1632/Makefile.in]
	Added -g flag to compilation of .c files generated from *32.spec.

	* [if1632/gdi32.spec]
	Numerous additional functions implemented.

	* if1632/user32.spec]
	wsprintfA maps to vsprintf not wsprintf
	Numerous additional functions implemented.

	* [include/gdi.h] [objects/gdiobj.c]
	New #define MAGIC_DONTCARE added. This is used in
	GDI_GetObjPtr to enable getting a pointer to a GDI object of
	unknow type.

	* [win32/gdi32.c]
	New file.

	* [win32/param32.c]
	WIN32_MoveToEx() - handle NULL pointer argument.

	* [win32/user32.c]
	USER32_InvalidateRect - handle passing of a NULL pointer.
	USER32_SetTimer - New function.

	* [files/directory.c]
	Fixed DIR_Init() (off by one in allocation of space for
	environment variables).

	* [files/drive.c]
	Added <sys/types.h> to #includes (prerequisite for <sys/stat.h>
	on FreeBSD).

Fri Feb 16 10:26:56 1996  Andreas Kirschbaum <ank@rbg.informatik.th-darmstadt.de>

	* [controls/menu.c]
	Memory leak plugged.

	* [controls/edit.c]
	Erase space with function ExtTextOut(). This eliminates the use of
 	xmalloc().  Memory leak in EDIT_WriteText plugged.

	* [debugger/db_disasm.c]
	Operand for scas now is di.

	* [files/profile.c]
	PROFILE_GetSection was copying too much data.
	PROFILE_GetSection now returns the correct value. It was returning
 	the number of unused instead of used bytes.

	* [objects/dc.c]
	Corrected two typos in comments.

	* [objects/font.c]
	FONT_MatchFont didn't return if it couldn't find any font.

	* [objects/oembitmap.c]
	Free object only if it has been allocated.

	* [windows/scroll.c]
	Memory leak in ScrollDC plugged.

Tue Feb 13 11:17:00 1996 William Magro  <wmagro@tc.cornell.edu>

	* [controls/edit.c]
	Implemented ES_NOHIDESEL style, shift+click selection,
 	shift+{arrow,home,end,pgup,pgdn} selection.  Optimized
	(de)selection drawing.  Changed selection drawing to use correct
 	system colors instead of inverting.  Fixed deleting or backspacing
 	across a '\r\n' end of line pair.  Selection now anchors
 	correctly. Fixed text leaking and extra garbage problem bug
 	uncovered by change in class style in wine960131.

	* [controls/widgets.c]
	Class flags now match those of Windows.

Mon Feb 12 21:28:19 1996  Martin von Loewis <loewis@informatik.hu-berlin.de>

	* [controls/widgets.c]
	WIDGETS_Init: RELAY32_GetEntryPoint does not take a string anymore.

	* [if1632/Makefile.in][if1632/relay32.c][include/relay32.h]
	comctl32.spec ole32.spec winspool.spec: new files.
	RELAY32_Init: call initialization of new DLLs.
	RELAY32_GetEntryPoint: expects WIN32_builtin* now.
	RELAY32_MakeFakeModule: new function.

	* [if1632/gdi32.spec][if1632/kernel32.spec][if1632/user32.spec]
	Added Win95 functions. Ordinals now differ from both NT and Win95
	HeapCreate, CreateDialogIndirectParamA, CreateDialogIndirectParamW,
	CreateDialogParamA, CreateDialogParamW, DialogBoxIndirectParamA
	DialogBoxIndirectParamW, DialogBoxParamA, DialogBoxParamW:
	new relays.

	* [if1632/shell32.spec]
	shell32.spec: renumbered all functions to take into account ordinals.
	These seem to be identical between NT and Win95.

	* [include/dialog.h][windows/dialog.c]
	xBaseUnit,yBaseUnit,DIALOG_DoDialogBox: made non-static.

	* [include/handle32.h]
	New handle types VRANGE, HEAP, HEAPITEM.

	* [include/pe_image.h][loader/pe_image.c]
	struct w_files: new field builtin.
	PE_FindExportedFunction: support ordinals.
	PE_GetProcAddress: call RELAY32_GetEntryPoint for builtins.
	fixup_imports: support ordinals.
	PE_LoadImage: prefer directories over segments.

	* [include/resource.h][win32/resource.c]
	FindResource32: changed parameter from LPCTSTR to LPCWSTR
		check LANG_NEUTRAL if LANG_ENGLISH fails.
	LoadAcceleratorsW,SizeofResource32,AccessResource32: 
		disabled because it's broken.
	Casted to and from LPWSTR at various places.

	* [include/string32.h][win32/string32.c]
	Changed prototypes to take const arguments where appropriate.

	* [include/struct32.h]
	New structures DLGTEMPLATE32, DLGITEMTEMPLATE32.

	* [tools/build.c]
	BuildSpec32Files: generate Base value into code, generate call to
	RELAY32_MakeFakeModule.
	
	* [win32/heap.c]
	This is still not finished and needs rework.
	HeapAlloc: renamed to SIMPLE_HeapAlloc, implemented HeapAlloc.
	HeapCreate: implemented on top of VirtualAlloc, which does not work yet
	HeapDestroy, HEAP_GrowHeap, HeapFree: new functions.

	* [win32/memory.c]
	Support for VRANGE_OBJECT. This is not yet called from any place,
	and needs more platform specific support
	MEMORY_FindVrange, MEMORY_IsVrangeFree, MEMORY_InsertVrange,
	MEMORY_AllocVrange, MEMORY_ReleaseVrange: new functions.

	* [win32/user32.c]
	WIN32_CreateWindowExA: don't GlobalAlloc for integer class and window
	names, as in dialogs.
	Implemented dialog functions (see user32.spec).

	* [windows/caret.c]
	CARET_Initialize: call RELAY32_GetBuiltinDLL.

Mon Feb 12 18:52:40 1996  Jim Peterson <jspeter@birch.ee.vt.edu>

	* [controls/edit.c]
	Removed commented out #ifdefs for WINELIB.

	* [tools/makehtml.pl]
	Put in error checking when trying to open a file.

	* [libtest/Makefile.in] [libtest/new.c] [libtest/hello4.c]
	Added two new targets: hello4 and new.

	* [include/windows.h]
	Added definition of DEVMODE structure, although it's not yet used.
  	Modified various API functions from CreateDC() to Escape(), in
 	order to make them more compliant with the strict API definitions.

	* [include/wintypes.h]
	Added 'typedef char TCHAR'.  It probably should be defined as
	'short', but then we would have to support such characters.  Also did
	'typedef const TCHAR* LPCTSTR' and 'typedef TCHAR* LPTSTR'.
	Also defined WNDENUMPROC, FONTENUMPROC, GOBJENUMPROC, PROPENUMPROC
	MFENUMPROC, and HGDIOBJ.

Mon Feb  5 16:42:07 1996  Frans van Dorsselaer <dorssel@rulhm1.leidenuniv.nl>

	* [misc/commdlg.c]
	Patched a bug that occurred in the internal COMMDLG module for the
 	FileOpen(), FileSave() and FileSaveAs() functions.  The file-type
 	combobox is now handled correctly.

Fri Feb  2 22:52:58 1996  Roman Dolejsi  <roman@sorry.vse.cz>

	* [resources/sysres_Cz.rc]
	Added support for Czech [Cz] language.

Thu Feb  1 00:35:04 1996  Philippe De Muyter  <phdm@info.ucl.ac.be>

	* [objects/font.c]
	FONT_matchfont : for fixed-spacing fonts, allow 'c' if 'm' fails;
	for variable-spacing fonts : allow '*' if 'p' fails; if asked lfHeight
	is -1, assume 0.
	CreateFontIndirect : if font parameter is NULL, issue an error message.
	CreateFont : null-terminate lfFaceName.
	ParseFontParms : debug code turned off : too verbose.
	InitFontsList : recognize *-c-* fonts as fixed-spacing fonts.

	* [objects/color.c]
	ColorToPhysical : admit 0xff...... COLORREF's as 0x00...... ones.
1996-02-18 18:44:41 +00:00

990 lines
33 KiB
C

/*
* Interface code to SCROLLBAR widget
*
* Copyright Martin Ayotte, 1993
* Copyright Alexandre Julliard, 1994
*
* Small fixes and implemented SB_THUMBPOSITION
* by Peter Broadhurst, 940611
*/
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "windows.h"
#include "syscolor.h"
#include "sysmetrics.h"
#include "scroll.h"
#include "user.h"
#include "graphics.h"
#include "win.h"
#include "stddebug.h"
/* #define DEBUG_SCROLL */
#include "debug.h"
static HBITMAP hUpArrow = 0;
static HBITMAP hDnArrow = 0;
static HBITMAP hLfArrow = 0;
static HBITMAP hRgArrow = 0;
static HBITMAP hUpArrowD = 0;
static HBITMAP hDnArrowD = 0;
static HBITMAP hLfArrowD = 0;
static HBITMAP hRgArrowD = 0;
static HBITMAP hUpArrowI = 0;
static HBITMAP hDnArrowI = 0;
static HBITMAP hLfArrowI = 0;
static HBITMAP hRgArrowI = 0;
#define TOP_ARROW(flags,pressed) \
(((flags)&ESB_DISABLE_UP) ? hUpArrowI : ((pressed) ? hUpArrowD:hUpArrow))
#define BOTTOM_ARROW(flags,pressed) \
(((flags)&ESB_DISABLE_DOWN) ? hDnArrowI : ((pressed) ? hDnArrowD:hDnArrow))
#define LEFT_ARROW(flags,pressed) \
(((flags)&ESB_DISABLE_LEFT) ? hLfArrowI : ((pressed) ? hLfArrowD:hLfArrow))
#define RIGHT_ARROW(flags,pressed) \
(((flags)&ESB_DISABLE_RIGHT) ? hRgArrowI : ((pressed) ? hRgArrowD:hRgArrow))
/* Minimum size of the rectangle between the arrows */
#define SCROLL_MIN_RECT 4
/* Delay (in ms) before first repetition when holding the button down */
#define SCROLL_FIRST_DELAY 200
/* Delay (in ms) between scroll repetitions */
#define SCROLL_REPEAT_DELAY 100
/* Scroll timer id */
#define SCROLL_TIMER 0
/* Scroll-bar hit testing */
enum SCROLL_HITTEST
{
SCROLL_NOWHERE, /* Outside the scroll bar */
SCROLL_TOP_ARROW, /* Top or left arrow */
SCROLL_TOP_RECT, /* Rectangle between the top arrow and the thumb */
SCROLL_THUMB, /* Thumb rectangle */
SCROLL_BOTTOM_RECT, /* Rectangle between the thumb and the bottom arrow */
SCROLL_BOTTOM_ARROW /* Bottom or right arrow */
};
/***********************************************************************
* SCROLL_LoadBitmaps
*/
static void SCROLL_LoadBitmaps(void)
{
hUpArrow = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_UPARROW));
hDnArrow = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_DNARROW));
hLfArrow = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_LFARROW));
hRgArrow = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_RGARROW));
hUpArrowD = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_UPARROWD));
hDnArrowD = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_DNARROWD));
hLfArrowD = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_LFARROWD));
hRgArrowD = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_RGARROWD));
hUpArrowI = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_UPARROWI));
hDnArrowI = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_DNARROWI));
hLfArrowI = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_LFARROWI));
hRgArrowI = LoadBitmap((HINSTANCE)NULL, MAKEINTRESOURCE(OBM_RGARROWI));
}
/***********************************************************************
* SCROLL_GetScrollInfo
*/
static SCROLLINFO *SCROLL_GetScrollInfo( HWND hwnd, int nBar )
{
HANDLE handle;
WND *wndPtr = WIN_FindWndPtr( hwnd );
if (!wndPtr) return NULL;
switch(nBar)
{
case SB_HORZ: handle = wndPtr->hHScroll; break;
case SB_VERT: handle = wndPtr->hVScroll; break;
case SB_CTL: return (SCROLLINFO *)wndPtr->wExtra;
default: return NULL;
}
if (!handle) /* Create the info structure if needed */
{
if ((handle = USER_HEAP_ALLOC( sizeof(SCROLLINFO) )))
{
SCROLLINFO *infoPtr = (SCROLLINFO *) USER_HEAP_LIN_ADDR( handle );
infoPtr->MinVal = infoPtr->CurVal = 0;
infoPtr->MaxVal = 100;
infoPtr->flags = ESB_ENABLE_BOTH;
if (nBar == SB_HORZ) wndPtr->hHScroll = handle;
else wndPtr->hVScroll = handle;
}
if (!hUpArrow) SCROLL_LoadBitmaps();
}
return (SCROLLINFO *) USER_HEAP_LIN_ADDR( handle );
}
/***********************************************************************
* SCROLL_GetScrollBarRect
*
* Compute the scroll bar rectangle, in drawing coordinates (i.e. client
* coords for SB_CTL, window coords for SB_VERT and SB_HORZ).
* 'arrowSize' returns the width or height of an arrow (depending on the
* orientation of the scrollbar), and 'thumbPos' 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 SCROLL_GetScrollBarRect( HWND hwnd, int nBar, RECT *lprect,
WORD *arrowSize, WORD *thumbPos )
{
int pixels;
BOOL vertical;
WND *wndPtr = WIN_FindWndPtr( hwnd );
switch(nBar)
{
case SB_HORZ:
lprect->left = wndPtr->rectClient.left - wndPtr->rectWindow.left - 1;
lprect->top = wndPtr->rectClient.bottom - wndPtr->rectWindow.top;
lprect->right = wndPtr->rectClient.right - wndPtr->rectWindow.left +1;
lprect->bottom = lprect->top + SYSMETRICS_CYHSCROLL + 1;
vertical = FALSE;
break;
case SB_VERT:
lprect->left = wndPtr->rectClient.right - wndPtr->rectWindow.left;
lprect->top = wndPtr->rectClient.top - wndPtr->rectWindow.top - 1;
lprect->right = lprect->left + SYSMETRICS_CXVSCROLL + 1;
lprect->bottom = wndPtr->rectClient.bottom - wndPtr->rectWindow.top +1;
vertical = TRUE;
break;
case SB_CTL:
GetClientRect( hwnd, lprect );
vertical = ((wndPtr->dwStyle & SBS_VERT) != 0);
break;
default:
return FALSE;
}
if (vertical) pixels = lprect->bottom - lprect->top;
else pixels = lprect->right - lprect->left;
if (pixels > 2*SYSMETRICS_CXVSCROLL + SCROLL_MIN_RECT)
{
*arrowSize = SYSMETRICS_CXVSCROLL;
}
else if (pixels > SCROLL_MIN_RECT)
{
*arrowSize = (pixels - SCROLL_MIN_RECT) / 2;
}
else *arrowSize = 0;
if ((pixels -= 3*SYSMETRICS_CXVSCROLL+1) > 0)
{
SCROLLINFO *info = SCROLL_GetScrollInfo( hwnd, nBar );
if ((info->flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
*thumbPos = 0;
else if (info->MinVal == info->MaxVal)
*thumbPos = *arrowSize;
else
*thumbPos = *arrowSize + pixels * (info->CurVal - info->MinVal) /
(info->MaxVal - info->MinVal);
}
else *thumbPos = 0;
return vertical;
}
/***********************************************************************
* SCROLL_GetThumbVal
*
* Compute the current scroll position based on the thumb position in pixels
* from the top of the scroll-bar.
*/
static UINT SCROLL_GetThumbVal( SCROLLINFO *infoPtr, RECT *rect,
BOOL vertical, WORD pos )
{
int pixels = vertical ? rect->bottom-rect->top : rect->right-rect->left;
if ((pixels -= 3*SYSMETRICS_CXVSCROLL+1) <= 0) return infoPtr->MinVal;
pos = MAX( 0, pos - SYSMETRICS_CXVSCROLL );
if (pos > pixels) pos = pixels;
dprintf_scroll(stddeb,"GetThumbVal: pos=%d ret=%d\n", pos,
(infoPtr->MinVal
+ (UINT)(((int)pos * (infoPtr->MaxVal-infoPtr->MinVal) + pixels/2)
/ pixels)) );
return (infoPtr->MinVal
+ (UINT)(((int)pos * (infoPtr->MaxVal-infoPtr->MinVal) + pixels/2)
/ pixels));
}
/***********************************************************************
* SCROLL_HitTest
*
* Scroll-bar hit testing (don't confuse this with WM_NCHITTEST!).
*/
static enum SCROLL_HITTEST SCROLL_HitTest( HWND hwnd, int nBar, POINT pt )
{
WORD arrowSize, thumbPos;
RECT rect;
BOOL vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
&arrowSize, &thumbPos );
if (!PtInRect( &rect, pt )) return SCROLL_NOWHERE;
if (vertical)
{
if (pt.y <= rect.top + arrowSize + 1) return SCROLL_TOP_ARROW;
if (pt.y >= rect.bottom - arrowSize) return SCROLL_BOTTOM_ARROW;
if (!thumbPos) return SCROLL_TOP_RECT;
pt.y -= rect.top;
if (pt.y < (INT)thumbPos) return SCROLL_TOP_RECT;
if (pt.y > thumbPos+SYSMETRICS_CYHSCROLL) return SCROLL_BOTTOM_RECT;
return SCROLL_THUMB;
}
else /* horizontal */
{
if (pt.x <= rect.left + arrowSize) return SCROLL_TOP_ARROW;
if (pt.x >= rect.right - arrowSize) return SCROLL_BOTTOM_ARROW;
if (!thumbPos) return SCROLL_TOP_RECT;
pt.x -= rect.left;
if (pt.x < (INT)thumbPos) return SCROLL_TOP_RECT;
if (pt.x > thumbPos+SYSMETRICS_CXVSCROLL) return SCROLL_BOTTOM_RECT;
return SCROLL_THUMB;
}
}
/***********************************************************************
* SCROLL_DrawArrows
*
* Draw the scroll bar arrows.
*/
static void SCROLL_DrawArrows( HDC hdc, SCROLLINFO *infoPtr, RECT *rect,
WORD arrowSize, BOOL vertical,
BOOL top_pressed, BOOL bottom_pressed )
{
HDC hdcMem = CreateCompatibleDC( hdc );
HBITMAP hbmpPrev = SelectObject( hdcMem, vertical ?
TOP_ARROW(infoPtr->flags, top_pressed)
: LEFT_ARROW(infoPtr->flags, top_pressed));
SetStretchBltMode( hdc, STRETCH_DELETESCANS );
StretchBlt( hdc, rect->left, rect->top,
vertical ? rect->right-rect->left : arrowSize+1,
vertical ? arrowSize+1 : rect->bottom-rect->top,
hdcMem, 0, 0,
SYSMETRICS_CXVSCROLL + 1, SYSMETRICS_CYHSCROLL + 1,
SRCCOPY );
SelectObject( hdcMem, vertical ?
BOTTOM_ARROW( infoPtr->flags, bottom_pressed )
: RIGHT_ARROW( infoPtr->flags, bottom_pressed ) );
if (vertical)
StretchBlt( hdc, rect->left, rect->bottom - arrowSize - 1,
rect->right - rect->left, arrowSize + 1,
hdcMem, 0, 0,
SYSMETRICS_CXVSCROLL + 1, SYSMETRICS_CYHSCROLL + 1,
SRCCOPY );
else
StretchBlt( hdc, rect->right - arrowSize - 1, rect->top,
arrowSize + 1, rect->bottom - rect->top,
hdcMem, 0, 0,
SYSMETRICS_CXVSCROLL + 1, SYSMETRICS_CYHSCROLL + 1,
SRCCOPY );
SelectObject( hdcMem, hbmpPrev );
DeleteDC( hdcMem );
}
/***********************************************************************
* SCROLL_DrawMovingThumb
*
* Draw the moving thumb rectangle.
*/
static void SCROLL_DrawMovingThumb( HDC hdc, RECT *rect, BOOL vertical,
WORD arrowSize, WORD thumbPos )
{
RECT r = *rect;
if (vertical)
{
r.top += thumbPos;
if (r.top < rect->top + arrowSize) r.top = rect->top + arrowSize;
if (r.top + SYSMETRICS_CYHSCROLL >= rect->bottom - arrowSize)
r.top = rect->bottom - arrowSize - SYSMETRICS_CYHSCROLL - 1;
r.bottom = r.top + SYSMETRICS_CYHSCROLL + 1;
}
else
{
r.left += thumbPos;
if (r.left < rect->left + arrowSize) r.left = rect->left + arrowSize;
if (r.left + SYSMETRICS_CXVSCROLL >= rect->right - arrowSize)
r.left = rect->right - arrowSize - SYSMETRICS_CXVSCROLL - 1;
r.right = r.left + SYSMETRICS_CXVSCROLL + 1;
}
InflateRect( &r, -1, -1 );
DrawFocusRect( hdc, &r );
}
/***********************************************************************
* SCROLL_DrawInterior
*
* Draw the scroll bar interior (everything except the arrows).
*/
static void SCROLL_DrawInterior( HWND hwnd, HDC hdc, int nBar, RECT *rect,
WORD arrowSize, WORD thumbPos, WORD flags,
BOOL vertical, BOOL top_selected,
BOOL bottom_selected )
{
RECT r;
/* Select the correct brush and pen */
SelectObject( hdc, sysColorObjects.hpenWindowFrame );
if ((flags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH)
{
/* This ought to be the color of the parent window */
SelectObject( hdc, sysColorObjects.hbrushWindow );
}
else
{
if (nBar == SB_CTL) /* Only scrollbar controls send WM_CTLCOLOR */
{
#ifdef WINELIB32
HBRUSH hbrush = (HBRUSH)SendMessage( GetParent(hwnd),
WM_CTLCOLORSCROLLBAR,
(WPARAM)hdc, (LPARAM)hwnd );
#else
HBRUSH hbrush = SendMessage( GetParent(hwnd), WM_CTLCOLOR, hdc,
MAKELONG(hwnd, CTLCOLOR_SCROLLBAR) );
#endif
SelectObject( hdc, hbrush );
}
else SelectObject( hdc, sysColorObjects.hbrushScrollbar );
}
/* Calculate the scroll rectangle */
r = *rect;
if (vertical)
{
r.top += arrowSize;
r.bottom -= arrowSize;
}
else
{
r.left += arrowSize;
r.right -= arrowSize;
}
/* Draw the scroll bar frame */
MoveTo( hdc, r.left, r.top );
LineTo( hdc, r.right-1, r.top );
LineTo( hdc, r.right-1, r.bottom-1 );
LineTo( hdc, r.left, r.bottom-1 );
LineTo( hdc, r.left, r.top );
/* Draw the scroll rectangles and thumb */
if (!thumbPos) /* No thumb to draw */
{
PatBlt( hdc, r.left+1, r.top+1, r.right - r.left - 2,
r.bottom - r.top - 2, PATCOPY );
return;
}
if (vertical)
{
PatBlt( hdc, r.left + 1, r.top + 1,
r.right - r.left - 2,
thumbPos - arrowSize,
top_selected ? 0x0f0000 : PATCOPY );
r.top += thumbPos - arrowSize;
PatBlt( hdc, r.left + 1, r.top + SYSMETRICS_CYHSCROLL + 1,
r.right - r.left - 2,
r.bottom - r.top - SYSMETRICS_CYHSCROLL - 2,
bottom_selected ? 0x0f0000 : PATCOPY );
r.bottom = r.top + SYSMETRICS_CYHSCROLL + 1;
}
else /* horizontal */
{
PatBlt( hdc, r.left + 1, r.top + 1,
thumbPos - arrowSize,
r.bottom - r.top - 2,
top_selected ? 0x0f0000 : PATCOPY );
r.left += thumbPos - arrowSize;
PatBlt( hdc, r.left + SYSMETRICS_CYHSCROLL + 1, r.top + 1,
r.right - r.left - SYSMETRICS_CYHSCROLL - 2,
r.bottom - r.top - 2,
bottom_selected ? 0x0f0000 : PATCOPY );
r.right = r.left + SYSMETRICS_CXVSCROLL + 1;
}
/* Draw the thumb */
SelectObject( hdc, sysColorObjects.hbrushBtnFace );
Rectangle( hdc, r.left, r.top, r.right, r.bottom );
InflateRect( &r, -1, -1 );
GRAPH_DrawReliefRect( hdc, &r, 1, 2, FALSE );
}
/***********************************************************************
* SCROLL_DrawScrollBar
*
* Redraw the whole scrollbar.
*/
void SCROLL_DrawScrollBar( HWND hwnd, HDC hdc, int nBar )
{
WORD arrowSize, thumbPos;
RECT rect;
BOOL vertical;
WND *wndPtr = WIN_FindWndPtr( hwnd );
SCROLLINFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
if (!wndPtr || !infoPtr ||
((nBar == SB_VERT) && !(wndPtr->dwStyle & WS_VSCROLL)) ||
((nBar == SB_HORZ) && !(wndPtr->dwStyle & WS_HSCROLL))) return;
vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
&arrowSize, &thumbPos );
/* Draw the arrows */
if (arrowSize) SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize,
vertical, FALSE, FALSE );
SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
infoPtr->flags, vertical, FALSE, FALSE );
}
/***********************************************************************
* SCROLL_RefreshScrollBar
*
* Repaint the scroll bar interior after a SetScrollRange() or
* SetScrollPos() call.
*/
static void SCROLL_RefreshScrollBar( HWND hwnd, int nBar )
{
WORD arrowSize, thumbPos;
RECT rect;
BOOL vertical;
HDC hdc;
WND *wndPtr = WIN_FindWndPtr( hwnd );
SCROLLINFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
if (!wndPtr || !infoPtr ||
((nBar == SB_VERT) && !(wndPtr->dwStyle & WS_VSCROLL)) ||
((nBar == SB_HORZ) && !(wndPtr->dwStyle & WS_HSCROLL))) return;
vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
&arrowSize, &thumbPos );
hdc = (nBar == SB_CTL) ? GetDC(hwnd) : GetWindowDC(hwnd);
if (!hdc) return;
SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
infoPtr->flags, vertical, FALSE, FALSE );
ReleaseDC( hwnd, hdc );
}
/***********************************************************************
* SCROLL_HandleKbdEvent
*
* Handle a keyboard event (only for SB_CTL scrollbars).
*/
static void SCROLL_HandleKbdEvent( HWND hwnd, WORD wParam )
{
WND *wndPtr = WIN_FindWndPtr( hwnd );
WORD msg;
switch(wParam)
{
case VK_PRIOR: msg = SB_PAGEUP; break;
case VK_NEXT: msg = SB_PAGEDOWN; break;
case VK_HOME: msg = SB_TOP; break;
case VK_END: msg = SB_BOTTOM; break;
case VK_UP: msg = SB_LINEUP; break;
case VK_DOWN: msg = SB_LINEDOWN; break;
default:
return;
}
#ifdef WINELIB32
SendMessage( GetParent(hwnd),
(wndPtr->dwStyle & SBS_VERT) ? WM_VSCROLL : WM_HSCROLL,
(WPARAM)msg, (LPARAM)hwnd );
#else
SendMessage( GetParent(hwnd),
(wndPtr->dwStyle & SBS_VERT) ? WM_VSCROLL : WM_HSCROLL,
msg, MAKELONG( 0, hwnd ));
#endif
}
/***********************************************************************
* SCROLL_HandleScrollEvent
*
* Handle a mouse or timer event for the scrollbar.
* 'pt' is the location of the mouse event in client (for SB_CTL) or
* windows coordinates.
*/
void SCROLL_HandleScrollEvent( HWND hwnd, int nBar, WORD msg, POINT pt )
{
/* Previous mouse position for timer events */
static POINT prevPt;
/* Hit test code of the last button-down event */
static enum SCROLL_HITTEST trackHitTest;
/* Thumb position when tracking started. */
static UINT trackThumbPos;
/* Position in the scroll-bar of the last button-down event. */
static int lastClickPos;
/* Position in the scroll-bar of the last mouse event. */
static int lastMousePos;
enum SCROLL_HITTEST hittest;
HWND hwndOwner, hwndCtl;
BOOL vertical;
WORD arrowSize, thumbPos;
RECT rect;
HDC hdc;
SCROLLINFO *infoPtr = SCROLL_GetScrollInfo( hwnd, nBar );
if (!infoPtr) return;
if ((trackHitTest == SCROLL_NOWHERE) && (msg != WM_LBUTTONDOWN)) return;
hdc = (nBar == SB_CTL) ? GetDC(hwnd) : GetWindowDC(hwnd);
vertical = SCROLL_GetScrollBarRect( hwnd, nBar, &rect,
&arrowSize, &thumbPos );
hwndOwner = (nBar == SB_CTL) ? GetParent(hwnd) : hwnd;
hwndCtl = (nBar == SB_CTL) ? hwnd : 0;
switch(msg)
{
case WM_LBUTTONDOWN: /* Initialise mouse tracking */
trackHitTest = hittest = SCROLL_HitTest( hwnd, nBar, pt );
lastClickPos = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
lastMousePos = lastClickPos;
trackThumbPos = thumbPos;
prevPt = pt;
SetCapture( hwnd );
if (nBar == SB_CTL) SetFocus( hwnd );
break;
case WM_MOUSEMOVE:
hittest = SCROLL_HitTest( hwnd, nBar, pt );
prevPt = pt;
break;
case WM_LBUTTONUP:
hittest = SCROLL_NOWHERE;
ReleaseCapture();
break;
case WM_SYSTIMER:
pt = prevPt;
hittest = SCROLL_HitTest( hwnd, nBar, pt );
break;
default:
return; /* Should never happen */
}
dprintf_scroll( stddeb, "ScrollBar Event: hwnd="NPFMT" bar=%d msg=%x pt=%ld,%ld hit=%d\n",
hwnd, nBar, msg, (LONG)pt.x, (LONG)pt.y, hittest );
switch(trackHitTest)
{
case SCROLL_NOWHERE: /* No tracking in progress */
break;
case SCROLL_TOP_ARROW:
SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
(hittest == trackHitTest), FALSE );
if (hittest == trackHitTest)
{
if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
{
SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
(FARPROC)0 );
#ifdef WINELIB32
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
(WPARAM)SB_LINEUP, (LPARAM)hwndCtl );
#else
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
SB_LINEUP, MAKELONG( 0, hwndCtl ));
#endif
}
}
else KillSystemTimer( hwnd, SCROLL_TIMER );
break;
case SCROLL_TOP_RECT:
SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
infoPtr->flags, vertical,
(hittest == trackHitTest), FALSE );
if (hittest == trackHitTest)
{
if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
{
SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
(FARPROC)0 );
#ifdef WINELIB32
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
(WPARAM)SB_PAGEUP, (LPARAM)hwndCtl );
#else
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
SB_PAGEUP, MAKELONG( 0, hwndCtl ));
#endif
}
}
else KillSystemTimer( hwnd, SCROLL_TIMER );
break;
case SCROLL_THUMB:
if (msg == WM_LBUTTONDOWN)
SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize,
trackThumbPos + lastMousePos - lastClickPos );
else if (msg == WM_LBUTTONUP)
SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
infoPtr->flags, vertical, FALSE, FALSE );
else /* WM_MOUSEMOVE */
{
UINT pos, val;
if (!PtInRect( &rect, pt )) pos = lastClickPos;
else pos = vertical ? (pt.y - rect.top) : (pt.x - rect.left);
if (pos != lastMousePos)
{
SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize,
trackThumbPos + lastMousePos - lastClickPos );
SCROLL_DrawMovingThumb( hdc, &rect, vertical, arrowSize,
trackThumbPos + pos - lastClickPos );
lastMousePos = pos;
val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
trackThumbPos + lastMousePos - lastClickPos );
#ifdef WINELIB32
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
MAKEWPARAM(SB_THUMBTRACK,val), (LPARAM)hwndCtl );
#else
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
SB_THUMBTRACK, MAKELONG( val, hwndCtl ));
#endif
}
}
break;
case SCROLL_BOTTOM_RECT:
SCROLL_DrawInterior( hwnd, hdc, nBar, &rect, arrowSize, thumbPos,
infoPtr->flags, vertical,
FALSE, (hittest == trackHitTest) );
if (hittest == trackHitTest)
{
if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
{
SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
(FARPROC)0 );
#ifdef WINELIB32
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
(WPARAM)SB_PAGEDOWN, (LPARAM)hwndCtl );
#else
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
SB_PAGEDOWN, MAKELONG( 0, hwndCtl ));
#endif
}
}
else KillSystemTimer( hwnd, SCROLL_TIMER );
break;
case SCROLL_BOTTOM_ARROW:
SCROLL_DrawArrows( hdc, infoPtr, &rect, arrowSize, vertical,
FALSE, (hittest == trackHitTest) );
if (hittest == trackHitTest)
{
if ((msg == WM_LBUTTONDOWN) || (msg == WM_SYSTIMER))
{
SetSystemTimer( hwnd, SCROLL_TIMER, (msg == WM_LBUTTONDOWN) ?
SCROLL_FIRST_DELAY : SCROLL_REPEAT_DELAY,
(FARPROC)0 );
#ifdef WINELIB32
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
(WPARAM)SB_LINEDOWN, (LPARAM)hwndCtl );
#else
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
SB_LINEDOWN, MAKELONG( 0, hwndCtl ));
#endif
}
}
else KillSystemTimer( hwnd, SCROLL_TIMER );
break;
}
if (msg == WM_LBUTTONUP)
{
if (trackHitTest == SCROLL_THUMB)
{
UINT val = SCROLL_GetThumbVal( infoPtr, &rect, vertical,
trackThumbPos + lastMousePos - lastClickPos );
#ifdef WINELIB32
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
MAKEWPARAM(SB_THUMBPOSITION,val), (LPARAM)hwndCtl );
#else
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
SB_THUMBPOSITION, MAKELONG( val, hwndCtl ) );
#endif
}
else
#ifdef WINELIB32
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
(WPARAM)SB_ENDSCROLL, (LPARAM)hwndCtl );
#else
SendMessage( hwndOwner, vertical ? WM_VSCROLL : WM_HSCROLL,
SB_ENDSCROLL, MAKELONG( 0, hwndCtl ) );
#endif
trackHitTest = SCROLL_NOWHERE; /* Terminate tracking */
}
ReleaseDC( hwnd, hdc );
}
/***********************************************************************
* ScrollBarWndProc
*/
LONG ScrollBarWndProc( HWND hwnd, WORD message, WORD wParam, LONG lParam )
{
POINT Pt;
Pt.x = LOWORD(lParam); Pt.y = HIWORD(lParam);
/* ^ Can't use MAKEPOINT macro in WINELIB32 */
switch(message)
{
case WM_CREATE:
{
CREATESTRUCT *lpCreat = (CREATESTRUCT *)PTR_SEG_TO_LIN(lParam);
if (lpCreat->style & SBS_SIZEBOX)
{
fprintf( stdnimp, "Unimplemented style SBS_SIZEBOX.\n" );
return 0; /* FIXME */
}
if (lpCreat->style & SBS_VERT)
{
if (lpCreat->style & SBS_LEFTALIGN)
MoveWindow( hwnd, lpCreat->x, lpCreat->y,
SYSMETRICS_CXVSCROLL+1, lpCreat->cy, FALSE );
else if (lpCreat->style & SBS_RIGHTALIGN)
MoveWindow( hwnd,
lpCreat->x+lpCreat->cx-SYSMETRICS_CXVSCROLL-1,
lpCreat->y,
SYSMETRICS_CXVSCROLL + 1, lpCreat->cy, FALSE );
}
else /* SBS_HORZ */
{
if (lpCreat->style & SBS_TOPALIGN)
MoveWindow( hwnd, lpCreat->x, lpCreat->y,
lpCreat->cx, SYSMETRICS_CYHSCROLL+1, FALSE );
else if (lpCreat->style & SBS_BOTTOMALIGN)
MoveWindow( hwnd,
lpCreat->x,
lpCreat->y+lpCreat->cy-SYSMETRICS_CYHSCROLL-1,
lpCreat->cx, SYSMETRICS_CYHSCROLL+1, FALSE );
}
}
if (!hUpArrow) SCROLL_LoadBitmaps();
dprintf_scroll( stddeb, "ScrollBar creation, hwnd="NPFMT"\n", hwnd );
return 0;
case WM_LBUTTONDOWN:
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
case WM_SYSTIMER:
SCROLL_HandleScrollEvent( hwnd, SB_CTL, message, Pt );
break;
case WM_KEYDOWN:
SCROLL_HandleKbdEvent( hwnd, wParam );
break;
case WM_ERASEBKGND:
break;
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint( hwnd, &ps );
SCROLL_DrawScrollBar( hwnd, hdc, SB_CTL );
EndPaint( hwnd, &ps );
}
break;
default:
return DefWindowProc( hwnd, message, wParam, lParam );
}
return 0;
}
/*************************************************************************
* SetScrollPos (USER.62)
*/
int SetScrollPos( HWND hwnd, int nBar, int nPos, BOOL bRedraw )
{
SCROLLINFO *infoPtr;
INT oldPos;
if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return 0;
dprintf_scroll( stddeb,"SetScrollPos min=%d max=%d pos=%d\n",
infoPtr->MinVal, infoPtr->MaxVal, nPos );
if (nPos < infoPtr->MinVal) nPos = infoPtr->MinVal;
else if (nPos > infoPtr->MaxVal) nPos = infoPtr->MaxVal;
oldPos = infoPtr->CurVal;
infoPtr->CurVal = nPos;
if (bRedraw) SCROLL_RefreshScrollBar( hwnd, nBar );
return oldPos;
}
/*************************************************************************
* GetScrollPos (USER.63)
*/
int GetScrollPos( HWND hwnd, int nBar )
{
SCROLLINFO *infoPtr;
if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return 0;
return infoPtr->CurVal;
}
/*************************************************************************
* SetScrollRange (USER.64)
*/
void SetScrollRange(HWND hwnd, int nBar, int MinVal, int MaxVal, BOOL bRedraw)
{
SCROLLINFO *infoPtr;
if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return;
dprintf_scroll( stddeb,"SetScrollRange hwnd="NPFMT" bar=%d min=%d max=%d\n",
hwnd, nBar, MinVal, MaxVal );
/* Invalid range -> range is set to (0,0) */
if ((MinVal > MaxVal) || ((long)MaxVal - MinVal > 32767L))
MinVal = MaxVal = 0;
if (infoPtr->CurVal < MinVal) infoPtr->CurVal = MinVal;
else if (infoPtr->CurVal > MaxVal) infoPtr->CurVal = MaxVal;
infoPtr->MinVal = MinVal;
infoPtr->MaxVal = MaxVal;
/* Non-client scroll-bar is hidden if min==max */
if (nBar != SB_CTL) ShowScrollBar( hwnd, nBar, (MinVal != MaxVal) );
if (bRedraw) SCROLL_RefreshScrollBar( hwnd, nBar );
}
/*************************************************************************
* GetScrollRange (USER.65)
*/
void GetScrollRange(HWND hwnd, int nBar, LPINT lpMin, LPINT lpMax)
{
SCROLLINFO *infoPtr;
if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return;
if (lpMin) *lpMin = infoPtr->MinVal;
if (lpMax) *lpMax = infoPtr->MaxVal;
}
/*************************************************************************
* ShowScrollBar (USER.267)
*/
void ShowScrollBar( HWND hwnd, WORD wBar, BOOL fShow )
{
WND *wndPtr = WIN_FindWndPtr( hwnd );
if (!wndPtr) return;
dprintf_scroll( stddeb, "ShowScrollBar: hwnd="NPFMT" bar=%d on=%d\n", hwnd, wBar, fShow );
switch(wBar)
{
case SB_CTL:
ShowWindow( hwnd, fShow ? SW_SHOW : SW_HIDE );
return;
case SB_HORZ:
if (fShow)
{
if (wndPtr->dwStyle & WS_HSCROLL) return;
wndPtr->dwStyle |= WS_HSCROLL;
}
else /* hide it */
{
if (!(wndPtr->dwStyle & WS_HSCROLL)) return;
wndPtr->dwStyle &= ~WS_HSCROLL;
}
break;
case SB_VERT:
if (fShow)
{
if (wndPtr->dwStyle & WS_VSCROLL) return;
wndPtr->dwStyle |= WS_VSCROLL;
}
else /* hide it */
{
if (!(wndPtr->dwStyle & WS_VSCROLL)) return;
wndPtr->dwStyle &= ~WS_VSCROLL;
}
break;
case SB_BOTH:
if (fShow)
{
if ((wndPtr->dwStyle & WS_HSCROLL)
&& (wndPtr->dwStyle & WS_VSCROLL)) return;
wndPtr->dwStyle |= WS_HSCROLL | WS_VSCROLL;
}
else /* hide it */
{
if (!(wndPtr->dwStyle & WS_HSCROLL)
&& !(wndPtr->dwStyle & WS_HSCROLL)) return;
wndPtr->dwStyle &= ~(WS_HSCROLL | WS_VSCROLL);
}
break;
default:
return; /* Nothing to do! */
}
SetWindowPos( hwnd, 0, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE
| SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED );
}
/*************************************************************************
* EnableScrollBar (USER.482)
*/
BOOL EnableScrollBar( HWND hwnd, UINT nBar, UINT flags )
{
SCROLLINFO *infoPtr;
HDC hdc;
if (!(infoPtr = SCROLL_GetScrollInfo( hwnd, nBar ))) return FALSE;
dprintf_scroll( stddeb, "EnableScrollBar: "NPFMT" %d %d\n", hwnd, nBar, flags );
flags &= ESB_DISABLE_BOTH;
if (infoPtr->flags == flags) return FALSE;
infoPtr->flags = flags;
/* Redraw the whole scroll bar */
hdc = (nBar == SB_CTL) ? GetDC(hwnd) : GetWindowDC(hwnd);
SCROLL_DrawScrollBar( hwnd, hdc, nBar );
ReleaseDC( hwnd, hdc );
return TRUE;
}