mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1493 lines
39 KiB
1493 lines
39 KiB
/*
|
|
** CUTILS.C
|
|
**
|
|
** Common utilities for common controls
|
|
**
|
|
*/
|
|
|
|
#include "ctlspriv.h"
|
|
#include <ntverp.h>
|
|
#include "ccverp.h"
|
|
|
|
#ifndef SSW_EX_IGNORESETTINGS
|
|
#define SSW_EX_IGNORESETTINGS 0x00040000 // ignore system settings to turn on/off smooth scroll
|
|
#endif
|
|
|
|
#ifdef WIN31
|
|
#ifdef SM_CXEDGE
|
|
#undef SM_CXEDGE
|
|
#undef SM_CYEDGE
|
|
#undef SM_CXMINSPACING
|
|
#undef SM_CYMINSPACING
|
|
#undef SM_CXSMICON
|
|
#undef SM_CYSMICON
|
|
#undef SM_CYSMCAPTION
|
|
#undef SM_CXSMSIZE
|
|
#undef SM_CYSMSIZE
|
|
#undef SM_CXMENUSIZE
|
|
#undef SM_CYMENUSIZE
|
|
#undef SM_ARRANGE
|
|
#undef SM_USERTYPE
|
|
#undef SM_XWORKAREA
|
|
#undef SM_YWORKAREA
|
|
#undef SM_CXWORKAREA
|
|
#undef SM_CYWORKAREA
|
|
#undef SM_CYCAPTIONICON
|
|
#undef SM_CYSMCAPTIONICON
|
|
#undef SM_CXMINIMIZED
|
|
#undef SM_CYMINIMIZED
|
|
#undef SM_CXMAXTRACK
|
|
#undef SM_CYMAXTRACK
|
|
#undef SM_CXMAXIMIZED
|
|
#undef SM_CYMAXIMIZED
|
|
#undef SM_SHOWSOUNDS
|
|
#undef SM_KEYBOARDPREF
|
|
#undef SM_HIGHCONTRAST
|
|
#undef SM_SCREENREADER
|
|
#undef SM_CURSORSIZE
|
|
#undef SM_CLEANBOOT
|
|
#undef SM_CXDRAG
|
|
#undef SM_CYDRAG
|
|
#undef SM_NETWORK
|
|
#undef SM_CXMENUCHECK
|
|
#undef SM_CYMENUCHECK
|
|
#endif
|
|
#endif
|
|
|
|
|
|
//
|
|
// Globals - REVIEW_32
|
|
//
|
|
|
|
BOOL g_fAnimate;
|
|
BOOL g_fSmoothScroll;
|
|
|
|
int g_cxEdge;
|
|
int g_cyEdge;
|
|
int g_cxBorder;
|
|
int g_cyBorder;
|
|
int g_cxScreen;
|
|
int g_cyScreen;
|
|
int g_cxFrame;
|
|
int g_cyFrame;
|
|
int g_cxVScroll;
|
|
int g_cyHScroll;
|
|
int g_cxIcon, g_cyIcon;
|
|
int g_cxIconSpacing, g_cyIconSpacing;
|
|
int g_cxIconMargin, g_cyIconMargin;
|
|
int g_cyLabelSpace;
|
|
int g_cxLabelMargin;
|
|
int g_cxDoubleClk;
|
|
int g_cyDoubleClk;
|
|
int g_cxScrollbar;
|
|
int g_cyScrollbar;
|
|
int g_fDragFullWindows;
|
|
|
|
COLORREF g_clrWindow;
|
|
COLORREF g_clrWindowText;
|
|
COLORREF g_clrWindowFrame;
|
|
COLORREF g_clrGrayText;
|
|
COLORREF g_clrBtnText;
|
|
COLORREF g_clrBtnFace;
|
|
COLORREF g_clrBtnShadow;
|
|
COLORREF g_clrBtnHighlight;
|
|
COLORREF g_clrHighlight;
|
|
COLORREF g_clrHighlightText;
|
|
COLORREF g_clrInfoText;
|
|
COLORREF g_clrInfoBk;
|
|
|
|
HBRUSH g_hbrGrayText;
|
|
HBRUSH g_hbrWindow;
|
|
HBRUSH g_hbrWindowText;
|
|
HBRUSH g_hbrWindowFrame;
|
|
HBRUSH g_hbrBtnFace;
|
|
HBRUSH g_hbrBtnHighlight;
|
|
HBRUSH g_hbrBtnShadow;
|
|
HBRUSH g_hbrHighlight;
|
|
|
|
|
|
#ifdef WIN31
|
|
|
|
HBRUSH g_hbr3DDkShadow;
|
|
HBRUSH g_hbr3DFace;
|
|
HBRUSH g_hbr3DHilight;
|
|
HBRUSH g_hbr3DLight;
|
|
HBRUSH g_hbr3DShadow;
|
|
HBRUSH g_hbrBtnText;
|
|
HBRUSH g_hbrWhite;
|
|
HBRUSH g_hbrGray;
|
|
HBRUSH g_hbrBlack;
|
|
|
|
int g_oemInfo_Planes;
|
|
int g_oemInfo_BitsPixel;
|
|
int g_oemInfo_BitCount;
|
|
|
|
#endif
|
|
|
|
HFONT g_hfontSystem;
|
|
|
|
#define CCS_ALIGN (CCS_TOP | CCS_NOMOVEY | CCS_BOTTOM)
|
|
|
|
/* Note that the default alignment is CCS_BOTTOM
|
|
*/
|
|
void FAR PASCAL NewSize(HWND hWnd, int nThickness, LONG style, int left, int top, int width, int height)
|
|
{
|
|
RECT rc, rcWindow, rcBorder;
|
|
|
|
/* Resize the window unless the user said not to
|
|
*/
|
|
if (!(style & CCS_NORESIZE))
|
|
{
|
|
/* Calculate the borders around the client area of the status bar
|
|
*/
|
|
GetWindowRect(hWnd, &rcWindow);
|
|
rcWindow.right -= rcWindow.left; // -> dx
|
|
rcWindow.bottom -= rcWindow.top; // -> dy
|
|
|
|
GetClientRect(hWnd, &rc);
|
|
ClientToScreen(hWnd, (LPPOINT)&rc);
|
|
|
|
rcBorder.left = rc.left - rcWindow.left;
|
|
rcBorder.top = rc.top - rcWindow.top ;
|
|
rcBorder.right = rcWindow.right - rc.right - rcBorder.left;
|
|
rcBorder.bottom = rcWindow.bottom - rc.bottom - rcBorder.top ;
|
|
|
|
if (style & CCS_VERT)
|
|
nThickness += rcBorder.left + rcBorder.right;
|
|
else
|
|
nThickness += rcBorder.top + rcBorder.bottom;
|
|
|
|
/* Check whether to align to the parent window
|
|
*/
|
|
if (style & CCS_NOPARENTALIGN)
|
|
{
|
|
/* Check out whether this bar is top aligned or bottom aligned
|
|
*/
|
|
switch (style & CCS_ALIGN)
|
|
{
|
|
case CCS_TOP:
|
|
case CCS_NOMOVEY:
|
|
break;
|
|
|
|
default: // CCS_BOTTOM
|
|
if(style & CCS_VERT)
|
|
left = left + width - nThickness;
|
|
else
|
|
top = top + height - nThickness;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* It is assumed there is a parent by default
|
|
*/
|
|
GetClientRect(GetParent(hWnd), &rc);
|
|
|
|
/* Don't forget to account for the borders
|
|
*/
|
|
if(style & CCS_VERT)
|
|
{
|
|
top = -rcBorder.right;
|
|
height = rc.bottom + rcBorder.top + rcBorder.bottom;
|
|
}
|
|
else
|
|
{
|
|
left = -rcBorder.left;
|
|
width = rc.right + rcBorder.left + rcBorder.right;
|
|
}
|
|
|
|
if ((style & CCS_ALIGN) == CCS_TOP)
|
|
{
|
|
if(style & CCS_VERT)
|
|
left = -rcBorder.left;
|
|
else
|
|
top = -rcBorder.top;
|
|
}
|
|
else if ((style & CCS_ALIGN) != CCS_NOMOVEY)
|
|
{
|
|
if (style & CCS_VERT)
|
|
left = rc.right - nThickness + rcBorder.right;
|
|
else
|
|
top = rc.bottom - nThickness + rcBorder.bottom;
|
|
}
|
|
}
|
|
if (!(style & CCS_NOMOVEY) && !(style & CCS_NODIVIDER))
|
|
{
|
|
if (style & CCS_VERT)
|
|
left += g_cxEdge;
|
|
else
|
|
top += g_cyEdge; // double pixel edge thing
|
|
}
|
|
|
|
if(style & CCS_VERT)
|
|
width = nThickness;
|
|
else
|
|
height = nThickness;
|
|
|
|
SetWindowPos(hWnd, NULL, left, top, width, height, SWP_NOZORDER);
|
|
}
|
|
}
|
|
|
|
|
|
BOOL FAR PASCAL MGetTextExtent(HDC hdc, LPCTSTR lpstr, int cnt, int FAR * pcx, int FAR * pcy)
|
|
{
|
|
BOOL fSuccess;
|
|
SIZE size = {0,0};
|
|
fSuccess=GetTextExtentPoint(hdc, lpstr, cnt, &size);
|
|
if (pcx)
|
|
*pcx=size.cx;
|
|
if (pcy)
|
|
*pcy=size.cy;
|
|
|
|
return fSuccess;
|
|
}
|
|
|
|
|
|
// these are the default colors used to map the dib colors
|
|
// to the current system colors
|
|
|
|
#define RGB_BUTTONTEXT (RGB(000,000,000)) // black
|
|
#define RGB_BUTTONSHADOW (RGB(128,128,128)) // dark grey
|
|
#define RGB_BUTTONFACE (RGB(192,192,192)) // bright grey
|
|
#define RGB_BUTTONHILIGHT (RGB(255,255,255)) // white
|
|
#define RGB_BACKGROUNDSEL (RGB(000,000,255)) // blue
|
|
#define RGB_BACKGROUND (RGB(255,000,255)) // magenta
|
|
#define FlipColor(rgb) (RGB(GetBValue(rgb), GetGValue(rgb), GetRValue(rgb)))
|
|
|
|
#define MAX_COLOR_MAPS 16
|
|
|
|
// BUGBUG: can we just nuke this function and use LoadImage(..., LR_MAP3DCOLORS)???????
|
|
|
|
HBITMAP WINAPI CreateMappedBitmap(HINSTANCE hInstance, int idBitmap,
|
|
UINT wFlags, LPCOLORMAP lpColorMap, int iNumMaps)
|
|
{
|
|
HDC hdc, hdcMem = NULL;
|
|
HANDLE h;
|
|
DWORD FAR *p;
|
|
DWORD FAR *lpTable;
|
|
LPBYTE lpBits;
|
|
HANDLE hRes;
|
|
LPBITMAPINFOHEADER lpBitmapInfo;
|
|
HBITMAP hbm = NULL, hbmOld;
|
|
int numcolors, i;
|
|
int wid, hgt;
|
|
LPBITMAPINFOHEADER lpMungeInfo;
|
|
int offBits;
|
|
DWORD rgbMaskTable[16];
|
|
DWORD rgbBackground;
|
|
static const COLORMAP SysColorMap[] = {
|
|
{RGB_BUTTONTEXT, COLOR_BTNTEXT}, // black
|
|
{RGB_BUTTONSHADOW, COLOR_BTNSHADOW}, // dark grey
|
|
{RGB_BUTTONFACE, COLOR_BTNFACE}, // bright grey
|
|
{RGB_BUTTONHILIGHT, COLOR_BTNHIGHLIGHT},// white
|
|
{RGB_BACKGROUNDSEL, COLOR_HIGHLIGHT}, // blue
|
|
{RGB_BACKGROUND, COLOR_WINDOW} // magenta
|
|
};
|
|
#define NUM_DEFAULT_MAPS (sizeof(SysColorMap)/sizeof(COLORMAP))
|
|
COLORMAP DefaultColorMap[NUM_DEFAULT_MAPS];
|
|
COLORMAP DIBColorMap[MAX_COLOR_MAPS];
|
|
|
|
h = FindResource(hInstance, MAKEINTRESOURCE(idBitmap), RT_BITMAP);
|
|
if (!h)
|
|
return NULL;
|
|
|
|
hRes = LoadResource(hInstance, h);
|
|
|
|
/* Lock the bitmap and get a pointer to the color table. */
|
|
lpBitmapInfo = (LPBITMAPINFOHEADER)LockResource(hRes);
|
|
if (!lpBitmapInfo)
|
|
return NULL;
|
|
|
|
// munge on a copy of the color table instead of the original
|
|
// (prevent possibility of "reload" with messed table
|
|
offBits = (int)lpBitmapInfo->biSize + ((1 << (lpBitmapInfo->biBitCount)) * sizeof(RGBQUAD));
|
|
lpMungeInfo = GlobalAlloc(GPTR, offBits);
|
|
if (!lpMungeInfo)
|
|
goto Exit1;
|
|
hmemcpy(lpMungeInfo, lpBitmapInfo, offBits);
|
|
|
|
/* Get system colors for the default color map */
|
|
if (!lpColorMap) {
|
|
lpColorMap = DefaultColorMap;
|
|
iNumMaps = NUM_DEFAULT_MAPS;
|
|
for (i=0; i < iNumMaps; i++) {
|
|
lpColorMap[i].from = SysColorMap[i].from;
|
|
lpColorMap[i].to = GetSysColor((int)SysColorMap[i].to);
|
|
}
|
|
}
|
|
|
|
/* Transform RGB color map to a BGR DIB format color map */
|
|
if (iNumMaps > MAX_COLOR_MAPS)
|
|
iNumMaps = MAX_COLOR_MAPS;
|
|
for (i=0; i < iNumMaps; i++) {
|
|
DIBColorMap[i].to = FlipColor(lpColorMap[i].to);
|
|
DIBColorMap[i].from = FlipColor(lpColorMap[i].from);
|
|
}
|
|
|
|
// use the table in the munging buffer
|
|
lpTable = p = (DWORD FAR *)(((LPBYTE)lpMungeInfo) + lpMungeInfo->biSize);
|
|
|
|
/* Replace button-face and button-shadow colors with the current values
|
|
*/
|
|
numcolors = 16;
|
|
|
|
// if we are creating a mask, build a color table with white
|
|
// marking the transparent section (where it used to be background)
|
|
// and black marking the opaque section (everything else). this
|
|
// table is used below to build the mask using the original DIB bits.
|
|
if (wFlags & CMB_MASKED) {
|
|
rgbBackground = FlipColor(RGB_BACKGROUND);
|
|
for (i = 0; i < 16; i++) {
|
|
if (p[i] == rgbBackground)
|
|
rgbMaskTable[i] = 0xFFFFFF; // transparent section
|
|
else
|
|
rgbMaskTable[i] = 0x000000; // opaque section
|
|
}
|
|
}
|
|
|
|
while (numcolors-- > 0) {
|
|
for (i = 0; i < iNumMaps; i++) {
|
|
if ((*p & 0x00FFFFFF) == DIBColorMap[i].from) {
|
|
*p = DIBColorMap[i].to;
|
|
break;
|
|
}
|
|
}
|
|
p++;
|
|
}
|
|
|
|
/* First skip over the header structure */
|
|
lpBits = (LPBYTE)(lpBitmapInfo) + offBits;
|
|
|
|
/* Create a color bitmap compatible with the display device */
|
|
i = wid = (int)lpBitmapInfo->biWidth;
|
|
hgt = (int)lpBitmapInfo->biHeight;
|
|
hdc = GetDC(NULL);
|
|
hdcMem = CreateCompatibleDC(hdc);
|
|
if (!hdcMem)
|
|
goto cleanup;
|
|
|
|
// if creating a mask, the bitmap needs to be twice as wide.
|
|
if (wFlags & CMB_MASKED)
|
|
i = wid*2;
|
|
|
|
// discardable bitmaps aren't much use anymore...
|
|
//
|
|
// if (wFlags & CMB_DISCARDABLE)
|
|
// hbm = CreateDiscardableBitmap(hdc, i, hgt);
|
|
// else
|
|
|
|
hbm = CreateCompatibleBitmap(hdc, i, hgt);
|
|
if (hbm) {
|
|
hbmOld = SelectObject(hdcMem, hbm);
|
|
|
|
// set the main image
|
|
StretchDIBits(hdcMem, 0, 0, wid, hgt, 0, 0, wid, hgt, lpBits,
|
|
(LPBITMAPINFO)lpMungeInfo, DIB_RGB_COLORS, SRCCOPY);
|
|
|
|
// if building a mask, replace the DIB's color table with the
|
|
// mask's black/white table and set the bits. in order to
|
|
// complete the masked effect, the actual image needs to be
|
|
// modified so that it has the color black in all sections
|
|
// that are to be transparent.
|
|
if (wFlags & CMB_MASKED) {
|
|
hmemcpy(lpTable, (DWORD FAR *)rgbMaskTable, 16 * sizeof(RGBQUAD));
|
|
StretchDIBits(hdcMem, wid, 0, wid, hgt, 0, 0, wid, hgt, lpBits,
|
|
(LPBITMAPINFO)lpMungeInfo, DIB_RGB_COLORS, SRCCOPY);
|
|
BitBlt(hdcMem, 0, 0, wid, hgt, hdcMem, wid, 0, 0x00220326); // DSna
|
|
}
|
|
SelectObject(hdcMem, hbmOld);
|
|
}
|
|
|
|
cleanup:
|
|
if (hdcMem)
|
|
DeleteObject(hdcMem);
|
|
ReleaseDC(NULL, hdc);
|
|
|
|
GlobalFree(lpMungeInfo);
|
|
|
|
Exit1:
|
|
UnlockResource(hRes);
|
|
FreeResource(hRes);
|
|
|
|
return hbm;
|
|
}
|
|
|
|
// moved from shelldll\dragdrop.c
|
|
|
|
// should caller pass in message that indicates termination
|
|
// (WM_LBUTTONUP, WM_RBUTTONUP)?
|
|
//
|
|
// in:
|
|
// hwnd to do check on
|
|
// x, y in client coordinates
|
|
//
|
|
// returns:
|
|
// TRUE the user began to drag (moved mouse outside double click rect)
|
|
// FALSE mouse came up inside click rect
|
|
//
|
|
// BUGBUG, should support VK_ESCAPE to cancel
|
|
|
|
BOOL FAR PASCAL CheckForDragBegin(HWND hwnd, int x, int y)
|
|
{
|
|
RECT rc;
|
|
MSG32 msg32;
|
|
int dxClickRect, dyClickRect;
|
|
|
|
dxClickRect = GetSystemMetrics(SM_CXDRAG);
|
|
dyClickRect = GetSystemMetrics(SM_CYDRAG);
|
|
#ifdef WINNT
|
|
if (dxClickRect == 0)
|
|
{
|
|
dxClickRect = GetSystemMetrics(SM_CXDOUBLECLK);
|
|
dyClickRect = GetSystemMetrics(SM_CYDOUBLECLK);
|
|
}
|
|
|
|
#endif
|
|
|
|
// See if the user moves a certain number of pixels in any direction
|
|
|
|
SetRect(&rc, x - dxClickRect, y - dyClickRect,
|
|
x + dxClickRect, y + dyClickRect);
|
|
|
|
MapWindowPoints(hwnd, NULL, (LPPOINT)&rc, 2);
|
|
|
|
SetCapture(hwnd);
|
|
do {
|
|
if (PeekMessage32(&msg32, NULL, 0, 0, PM_REMOVE, TRUE))
|
|
{
|
|
// See if the application wants to process the message...
|
|
if (CallMsgFilter32(&msg32, MSGF_COMMCTRL_BEGINDRAG, TRUE) != 0)
|
|
continue;
|
|
|
|
switch (msg32.message) {
|
|
case WM_LBUTTONUP:
|
|
case WM_RBUTTONUP:
|
|
case WM_LBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
ReleaseCapture();
|
|
return FALSE;
|
|
|
|
case WM_MOUSEMOVE:
|
|
if (!PtInRect(&rc, msg32.pt)) {
|
|
ReleaseCapture();
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
TranslateMessage32(&msg32, TRUE);
|
|
DispatchMessage32(&msg32, TRUE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// WM_CANCELMODE messages will unset the capture, in that
|
|
// case I want to exit this loop
|
|
} while (GetCapture() == hwnd);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
/* Regular StrToInt; stops at first non-digit. */
|
|
|
|
int WINAPI StrToInt(LPCTSTR lpSrc) // atoi()
|
|
{
|
|
|
|
#define ISDIGIT(c) ((c) >= TEXT('0') && (c) <= TEXT('9'))
|
|
|
|
int n = 0;
|
|
BOOL bNeg = FALSE;
|
|
|
|
if (*lpSrc == TEXT('-')) {
|
|
bNeg = TRUE;
|
|
lpSrc++;
|
|
}
|
|
|
|
while (ISDIGIT(*lpSrc)) {
|
|
n *= 10;
|
|
n += *lpSrc - TEXT('0');
|
|
lpSrc++;
|
|
}
|
|
return bNeg ? -n : n;
|
|
}
|
|
|
|
#ifdef UNICODE
|
|
|
|
//
|
|
// Wrappers for StrToInt
|
|
//
|
|
|
|
int WINAPI StrToIntA(LPCSTR lpSrc) // atoi()
|
|
{
|
|
LPWSTR lpString;
|
|
INT iResult;
|
|
|
|
lpString = ProduceWFromA (CP_ACP, lpSrc);
|
|
|
|
if (!lpString) {
|
|
return 0;
|
|
}
|
|
|
|
iResult = StrToIntW(lpString);
|
|
|
|
FreeProducedString (lpString);
|
|
|
|
return iResult;
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
//
|
|
// Stub W version when Built ANSI
|
|
//
|
|
|
|
int WINAPI StrToIntW(LPCWSTR lpSrc) // atoi()
|
|
{
|
|
SetLastErrorEx(ERROR_CALL_NOT_IMPLEMENTED, SLE_WARNING);
|
|
return 0;
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#undef StrToLong
|
|
|
|
#ifdef WIN32
|
|
|
|
//
|
|
// No need to Unicode this since it is not
|
|
// exported.
|
|
//
|
|
|
|
LONG WINAPI StrToLong(LPCTSTR lpSrc) // atoi()
|
|
{
|
|
return StrToInt(lpSrc);
|
|
}
|
|
|
|
#else
|
|
|
|
/* Regular StrToLong; stops at first non-digit. */
|
|
|
|
LONG WINAPI StrToLong(LPCSTR lpSrc) // atoi()
|
|
{
|
|
|
|
#define ISDIGIT(c) ((c) >= '0' && (c) <= '9')
|
|
|
|
LONG n = 0;
|
|
BOOL bNeg = FALSE;
|
|
|
|
if (*lpSrc == TEXT('-')) {
|
|
bNeg = TRUE;
|
|
lpSrc++;
|
|
}
|
|
|
|
while (ISDIGIT(*lpSrc)) {
|
|
n *= 10;
|
|
n += *lpSrc - TEXT('0');
|
|
lpSrc++;
|
|
}
|
|
return bNeg ? -n : n;
|
|
|
|
}
|
|
#endif
|
|
|
|
#pragma code_seg(CODESEG_INIT)
|
|
|
|
//
|
|
// From zmouse.h in the Magellan SDK
|
|
//
|
|
|
|
#define MSH_MOUSEWHEEL TEXT("MSWHEEL_ROLLMSG")
|
|
|
|
// Class name for Magellan/Z MSWHEEL window
|
|
// use FindWindow to get hwnd to MSWHEEL
|
|
#define MOUSEZ_CLASSNAME TEXT("MouseZ") // wheel window class
|
|
#define MOUSEZ_TITLE TEXT("Magellan MSWHEEL") // wheel window title
|
|
|
|
#define MSH_WHEELMODULE_CLASS (MOUSEZ_CLASSNAME)
|
|
#define MSH_WHEELMODULE_TITLE (MOUSEZ_TITLE)
|
|
|
|
#define MSH_SCROLL_LINES TEXT("MSH_SCROLL_LINES_MSG")
|
|
|
|
UINT g_msgMSWheel;
|
|
UINT g_ucScrollLines = 3; /* default */
|
|
int gcWheelDelta;
|
|
|
|
void FAR PASCAL InitGlobalMetrics(WPARAM wParam)
|
|
{
|
|
static BOOL fInitMouseWheel;
|
|
static HWND hwndMSWheel;
|
|
static UINT msgMSWheelGetScrollLines;
|
|
|
|
if (!fInitMouseWheel) {
|
|
fInitMouseWheel = TRUE;
|
|
|
|
#if defined(WINNT) && defined(WM_MOUSEWHEEL)
|
|
g_msgMSWheel = WM_MOUSEWHEEL;
|
|
#else
|
|
g_msgMSWheel = RegisterWindowMessage(MSH_MOUSEWHEEL);
|
|
msgMSWheelGetScrollLines = RegisterWindowMessage(MSH_SCROLL_LINES);
|
|
hwndMSWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
|
|
#endif
|
|
}
|
|
|
|
#if defined(WINNT) && defined(WM_MOUSEWHEEL)
|
|
SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &g_ucScrollLines, 0);
|
|
#else
|
|
if (hwndMSWheel && msgMSWheelGetScrollLines) {
|
|
g_ucScrollLines =
|
|
(UINT)SendMessage(hwndMSWheel, msgMSWheelGetScrollLines, 0, 0);
|
|
}
|
|
#endif
|
|
|
|
// bug fix HACK: these are NOT members of USER's NONCLIENTMETRICS struct
|
|
g_cxIcon = GetSystemMetrics(SM_CXICON);
|
|
g_cyIcon = GetSystemMetrics(SM_CYICON);
|
|
|
|
g_cxIconSpacing = GetSystemMetrics( SM_CXICONSPACING );
|
|
g_cyIconSpacing = GetSystemMetrics( SM_CYICONSPACING );
|
|
|
|
if ((wParam == 0) || (wParam == SPI_SETDRAGFULLWINDOWS)) {
|
|
SystemParametersInfo(SPI_GETDRAGFULLWINDOWS, sizeof(g_fDragFullWindows), &g_fDragFullWindows, 0);
|
|
}
|
|
|
|
{
|
|
HKEY hkey;
|
|
|
|
#ifdef NASH
|
|
g_fSmoothScroll = TRUE;
|
|
#else
|
|
g_fSmoothScroll = FALSE;
|
|
#endif
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, TEXT("Control Panel\\Desktop"), 0, MAXIMUM_ALLOWED, &hkey) == ERROR_SUCCESS) {
|
|
DWORD dwSize = sizeof(g_fSmoothScroll);
|
|
RegQueryValueEx(hkey, TEXT("SmoothScroll"), 0, NULL, (LPBYTE)&g_fSmoothScroll, &dwSize);
|
|
RegCloseKey(hkey);
|
|
}
|
|
}
|
|
|
|
// BUGBUG: some of these are also not members of NONCLIENTMETRICS
|
|
if ((wParam == 0) || (wParam == SPI_SETNONCLIENTMETRICS))
|
|
{
|
|
NONCLIENTMETRICS ncm;
|
|
|
|
// REVIEW, make sure all these vars are used somewhere.
|
|
#ifndef WIN31
|
|
g_cxEdge = GetSystemMetrics(SM_CXEDGE);
|
|
g_cyEdge = GetSystemMetrics(SM_CYEDGE);
|
|
#else
|
|
g_cxEdge = 2;
|
|
g_cyEdge = 2;
|
|
#endif
|
|
g_cxBorder = GetSystemMetrics(SM_CXBORDER);
|
|
g_cyBorder = GetSystemMetrics(SM_CYBORDER);
|
|
g_cxScreen = GetSystemMetrics(SM_CXSCREEN);
|
|
g_cyScreen = GetSystemMetrics(SM_CYSCREEN);
|
|
g_cxFrame = GetSystemMetrics(SM_CXFRAME);
|
|
g_cyFrame = GetSystemMetrics(SM_CYFRAME);
|
|
|
|
#ifndef WIN31
|
|
ncm.cbSize = sizeof(ncm);
|
|
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
|
|
|
|
g_cxVScroll = g_cxScrollbar = (int)ncm.iScrollWidth;
|
|
g_cyHScroll = g_cyScrollbar = (int)ncm.iScrollHeight;
|
|
#else
|
|
g_cxVScroll = g_cxScrollbar = GetSystemMetrics(SM_CXVSCROLL);
|
|
g_cyHScroll = g_cyScrollbar = GetSystemMetrics(SM_CYHSCROLL);
|
|
#endif
|
|
|
|
// this is true for 4.0 modules only
|
|
// for 3.x modules user lies and adds one to these values
|
|
// Assert(g_cxVScroll == GetSystemMetrics(SM_CXVSCROLL));
|
|
// Assert(g_cyHScroll == GetSystemMetrics(SM_CYHSCROLL));
|
|
|
|
g_cxIconMargin = g_cxBorder * 8;
|
|
g_cyIconMargin = g_cyEdge;
|
|
g_cyLabelSpace = g_cyIconMargin + (g_cyEdge);
|
|
g_cxLabelMargin = g_cxEdge;
|
|
|
|
g_cxDoubleClk = GetSystemMetrics(SM_CXDOUBLECLK);
|
|
g_cyDoubleClk = GetSystemMetrics(SM_CYDOUBLECLK);
|
|
}
|
|
}
|
|
|
|
void FAR PASCAL InitGlobalColors()
|
|
{
|
|
g_clrWindow = GetSysColor(COLOR_WINDOW);
|
|
g_clrWindowText = GetSysColor(COLOR_WINDOWTEXT);
|
|
g_clrWindowFrame = GetSysColor(COLOR_WINDOWFRAME);
|
|
g_clrGrayText = GetSysColor(COLOR_GRAYTEXT);
|
|
g_clrBtnText = GetSysColor(COLOR_BTNTEXT);
|
|
g_clrBtnFace = GetSysColor(COLOR_BTNFACE);
|
|
g_clrBtnShadow = GetSysColor(COLOR_BTNSHADOW);
|
|
g_clrBtnHighlight = GetSysColor(COLOR_BTNHIGHLIGHT);
|
|
g_clrHighlight = GetSysColor(COLOR_HIGHLIGHT);
|
|
g_clrHighlightText = GetSysColor(COLOR_HIGHLIGHTTEXT);
|
|
#ifndef WIN31
|
|
g_clrInfoText = GetSysColor(COLOR_INFOTEXT);
|
|
g_clrInfoBk = GetSysColor(COLOR_INFOBK);
|
|
|
|
g_hbrGrayText = GetSysColorBrush(COLOR_GRAYTEXT);
|
|
g_hbrWindow = GetSysColorBrush(COLOR_WINDOW);
|
|
g_hbrWindowText = GetSysColorBrush(COLOR_WINDOWTEXT);
|
|
g_hbrWindowFrame = GetSysColorBrush(COLOR_WINDOWFRAME);
|
|
g_hbrBtnFace = GetSysColorBrush(COLOR_BTNFACE);
|
|
g_hbrBtnHighlight = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
|
|
g_hbrBtnShadow = GetSysColorBrush(COLOR_BTNSHADOW);
|
|
g_hbrHighlight = GetSysColorBrush(COLOR_HIGHLIGHT);
|
|
|
|
#else // WIN31
|
|
|
|
if (!g_hbrGrayText)
|
|
{
|
|
g_clrInfoText = RGB(0,0,0);
|
|
g_clrInfoBk = RGB(255,255,255);
|
|
|
|
// Init these brushes if they haven't already been init'ed.
|
|
g_hbrGrayText = CreateSolidBrush(g_clrGrayText);
|
|
g_hbrWindow = CreateSolidBrush(g_clrWindow);
|
|
g_hbrWindowText = CreateSolidBrush(g_clrWindowText);
|
|
g_hbrWindowFrame = CreateSolidBrush(g_clrWindowFrame);
|
|
g_hbrBtnFace = CreateSolidBrush(g_clrBtnFace);
|
|
g_hbrBtnHighlight = CreateSolidBrush(g_clrBtnHighlight);
|
|
g_hbrBtnShadow = CreateSolidBrush(g_clrBtnShadow);
|
|
g_hbrHighlight = CreateSolidBrush(g_clrHighlight);
|
|
g_hbrBtnText = CreateSolidBrush(g_clrBtnText);
|
|
g_hbrWhite = CreateSolidBrush(RGB(255,255,255));
|
|
g_hbrGray = CreateSolidBrush(RGB(127,127,127));
|
|
g_hbrBlack = CreateSolidBrush(RGB(0,0,0));
|
|
|
|
// these system colors don't exist for win31...
|
|
g_hbr3DFace = CreateSolidBrush(g_clrBtnFace);
|
|
g_hbr3DShadow = CreateSolidBrush(g_clrBtnShadow);
|
|
g_hbr3DHilight = CreateSolidBrush(RGB_3DHILIGHT);
|
|
g_hbr3DLight = CreateSolidBrush(RGB_3DLIGHT);
|
|
g_hbr3DDkShadow = CreateSolidBrush(RGB_3DDKSHADOW);
|
|
}
|
|
|
|
// oem info for drawing routines
|
|
{
|
|
// Get the (Planes * BitCount) for the current device
|
|
HDC hdcScreen = GetDC(NULL);
|
|
g_oemInfo_Planes = GetDeviceCaps(hdcScreen, PLANES);
|
|
g_oemInfo_BitsPixel = GetDeviceCaps(hdcScreen, BITSPIXEL);
|
|
g_oemInfo_BitCount = g_oemInfo_Planes * g_oemInfo_BitsPixel;
|
|
ReleaseDC(NULL,hdcScreen);
|
|
}
|
|
|
|
#endif //WIN31
|
|
|
|
g_hfontSystem = GetStockObject(SYSTEM_FONT);
|
|
}
|
|
|
|
#pragma code_seg()
|
|
|
|
void FAR PASCAL RelayToToolTips(HWND hwndToolTips, HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if(hwndToolTips) {
|
|
MSG msg;
|
|
msg.lParam = lParam;
|
|
msg.wParam = wParam;
|
|
msg.message = wMsg;
|
|
msg.hwnd = hWnd;
|
|
SendMessage(hwndToolTips, TTM_RELAYEVENT, 0, (LPARAM)(LPMSG)&msg);
|
|
}
|
|
}
|
|
|
|
#define DT_SEARCHTIMEOUT 1000L // 1 seconds
|
|
int g_iIncrSearchFailed = 0;
|
|
|
|
static LPTSTR s_pszCharBuf = NULL;
|
|
static int s_ichCharBuf = 0;
|
|
static DWORD s_timeLast = 0L;
|
|
#if defined(FE_IME) || !defined(WINNT)
|
|
static BOOL s_fReplaceCompChar = FALSE;
|
|
#endif
|
|
|
|
int FAR PASCAL GetIncrementSearchString(LPTSTR lpsz)
|
|
{
|
|
if (GetMessageTime() - s_timeLast > DT_SEARCHTIMEOUT)
|
|
{
|
|
g_iIncrSearchFailed = 0;
|
|
s_ichCharBuf = 0;
|
|
}
|
|
|
|
if (s_ichCharBuf && lpsz) {
|
|
lstrcpyn(lpsz, s_pszCharBuf, s_ichCharBuf + 1);
|
|
lpsz[s_ichCharBuf] = TEXT('\0');
|
|
}
|
|
return s_ichCharBuf;
|
|
}
|
|
|
|
#if defined(FE_IME) || !defined(WINNT)
|
|
// Now only Korean version is interested in incremental search with composition string.
|
|
BOOL FAR PASCAL IncrementSearchImeCompStr(BOOL fCompStr, LPSTR lpszCompStr, LPSTR FAR *lplpstr)
|
|
{
|
|
static int cbCharBuf = 0;
|
|
BOOL fRestart = FALSE;
|
|
|
|
if (!s_fReplaceCompChar && GetMessageTime() - s_timeLast > DT_SEARCHTIMEOUT)
|
|
{
|
|
g_iIncrSearchFailed = 0;
|
|
s_ichCharBuf = 0;
|
|
}
|
|
|
|
if (s_ichCharBuf == 0)
|
|
{
|
|
fRestart = TRUE;
|
|
s_fReplaceCompChar = FALSE;
|
|
}
|
|
s_timeLast = GetMessageTime();
|
|
|
|
// Is there room for new character plus zero terminator?
|
|
//
|
|
if (!s_fReplaceCompChar && s_ichCharBuf + 2 + 1 > cbCharBuf)
|
|
{
|
|
LPSTR psz = ReAlloc(s_pszCharBuf, cbCharBuf + 16);
|
|
if (!psz)
|
|
return fRestart;
|
|
|
|
cbCharBuf += 16;
|
|
s_pszCharBuf = psz;
|
|
}
|
|
|
|
if (s_fReplaceCompChar)
|
|
{
|
|
if (lpszCompStr[0])
|
|
{
|
|
s_pszCharBuf[s_ichCharBuf-2] = lpszCompStr[0];
|
|
s_pszCharBuf[s_ichCharBuf-1] = lpszCompStr[1];
|
|
s_pszCharBuf[s_ichCharBuf] = 0;
|
|
}
|
|
else
|
|
{
|
|
s_ichCharBuf -= 2;
|
|
s_pszCharBuf[s_ichCharBuf] = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
s_pszCharBuf[s_ichCharBuf++] = lpszCompStr[0];
|
|
s_pszCharBuf[s_ichCharBuf++] = lpszCompStr[1];
|
|
s_pszCharBuf[s_ichCharBuf] = 0;
|
|
}
|
|
|
|
s_fReplaceCompChar = (fCompStr && lpszCompStr[0]);
|
|
|
|
if (s_ichCharBuf == 2 && s_fReplaceCompChar)
|
|
fRestart = TRUE;
|
|
|
|
*lplpstr = s_pszCharBuf;
|
|
|
|
return fRestart;
|
|
|
|
}
|
|
#endif FE_IME
|
|
|
|
#ifdef UNICODE
|
|
/*
|
|
* Thunk for LVM_GETISEARCHSTRINGA
|
|
*
|
|
* This message had to be thunked here because s_ichCharBuf
|
|
* is a static var.
|
|
*/
|
|
int FAR PASCAL GetIncrementSearchStringA(UINT uiCodePage, LPSTR lpsz)
|
|
{
|
|
if (GetMessageTime() - s_timeLast > DT_SEARCHTIMEOUT)
|
|
{
|
|
g_iIncrSearchFailed = 0;
|
|
s_ichCharBuf = 0;
|
|
}
|
|
|
|
if (s_ichCharBuf && lpsz) {
|
|
ConvertWToAN( uiCodePage, lpsz, s_ichCharBuf, s_pszCharBuf, s_ichCharBuf );
|
|
lpsz[s_ichCharBuf] = '\0';
|
|
}
|
|
return s_ichCharBuf;
|
|
}
|
|
#endif
|
|
|
|
|
|
BOOL FAR PASCAL IncrementSearchString(UINT ch, LPTSTR FAR *lplpstr)
|
|
{
|
|
// BUGBUG:: review the use of all these statics. Not a major problem
|
|
// as basically we will not use them if we time out between characters
|
|
// (1/4 second)
|
|
static int cbCharBuf = 0;
|
|
BOOL fRestart = FALSE;
|
|
|
|
if (!ch) {
|
|
s_ichCharBuf =0;
|
|
g_iIncrSearchFailed = 0;
|
|
return FALSE;
|
|
}
|
|
|
|
if (GetMessageTime() - s_timeLast > DT_SEARCHTIMEOUT)
|
|
{
|
|
g_iIncrSearchFailed = 0;
|
|
s_ichCharBuf = 0;
|
|
}
|
|
|
|
if (s_ichCharBuf == 0)
|
|
fRestart = TRUE;
|
|
|
|
s_timeLast = GetMessageTime();
|
|
|
|
// Is there room for new character plus zero terminator?
|
|
//
|
|
if (s_ichCharBuf + 1 + 1 > cbCharBuf)
|
|
{
|
|
LPTSTR psz = ReAlloc(s_pszCharBuf, ((cbCharBuf + 16) * sizeof(TCHAR)));
|
|
if (!psz)
|
|
return fRestart;
|
|
|
|
cbCharBuf += 16;
|
|
s_pszCharBuf = psz;
|
|
}
|
|
|
|
s_pszCharBuf[s_ichCharBuf++] = ch;
|
|
s_pszCharBuf[s_ichCharBuf] = 0;
|
|
|
|
*lplpstr = s_pszCharBuf;
|
|
|
|
return fRestart;
|
|
}
|
|
|
|
|
|
// strips out the accelerators. they CAN be the same buffers.
|
|
void PASCAL StripAccelerators(LPTSTR lpszFrom, LPTSTR lpszTo)
|
|
{
|
|
|
|
BOOL fRet = FALSE;
|
|
|
|
while ( *lpszTo = *lpszFrom ) {
|
|
#if !defined(UNICODE) // && defined(DBCS)
|
|
if (IsDBCSLeadByte(*lpszFrom)) {
|
|
(*((WORD FAR*)lpszTo)) = (*((WORD FAR *)lpszFrom));
|
|
lpszTo += 2;
|
|
lpszFrom += 2;
|
|
continue;
|
|
}
|
|
if ((*lpszFrom == '(') && (*(lpszFrom+1)==CH_PREFIX)){
|
|
int i;
|
|
for(i=0; i<4 && *lpszFrom;i++, lpszFrom++)
|
|
;
|
|
|
|
|
|
if (*lpszFrom == '\0') {
|
|
*lpszTo = 0;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
#endif
|
|
|
|
if (*lpszFrom == TEXT('\t')) {
|
|
*lpszTo = TEXT('\0');
|
|
break;
|
|
}
|
|
|
|
if ( (*lpszFrom++ != CH_PREFIX) || (*lpszFrom == CH_PREFIX) ) {
|
|
lpszTo++;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void ScrollShrinkRect(int x, int y, LPRECT lprc)
|
|
{
|
|
if (lprc) {
|
|
if (x > 0) {
|
|
lprc->left += x;
|
|
} else {
|
|
lprc->right += x;
|
|
}
|
|
|
|
if (y > 0) {
|
|
lprc->top += y;
|
|
} else {
|
|
lprc->bottom += y;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// common control info helpers
|
|
void FAR PASCAL CIInitialize(LPCONTROLINFO lpci, HWND hwnd, LPCREATESTRUCT lpcs)
|
|
{
|
|
InitGlobalMetrics(0);
|
|
lpci->hwnd = hwnd;
|
|
lpci->hwndParent = lpcs->hwndParent;
|
|
lpci->style = lpcs->style;
|
|
lpci->uiCodePage = CP_ACP;
|
|
|
|
lpci->bUnicode = (SendMessage (lpci->hwndParent, WM_NOTIFYFORMAT,
|
|
(WPARAM)lpci->hwnd, NF_QUERY) == NFR_UNICODE);
|
|
|
|
}
|
|
|
|
LRESULT FAR PASCAL CIHandleNotifyFormat(LPCONTROLINFO lpci, LPARAM lParam)
|
|
{
|
|
if (lParam == NF_QUERY) {
|
|
#ifdef UNICODE
|
|
return NFR_UNICODE;
|
|
#else
|
|
return NFR_ANSI;
|
|
#endif
|
|
} else if (lParam == NF_REQUERY) {
|
|
UINT uiResult;
|
|
|
|
uiResult = SendMessage (lpci->hwndParent, WM_NOTIFYFORMAT,
|
|
(WPARAM)lpci->hwnd, NF_QUERY);
|
|
|
|
lpci->bUnicode = (uiResult == NFR_UNICODE);
|
|
|
|
return uiResult;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
#define SUBSCROLLS 50
|
|
#define abs(x) ( ( x > 0 ) ? x : -x)
|
|
|
|
|
|
#define DEFAULT_MAXSCROLLTIME (GetDoubleClickTime()/2)
|
|
#define DEFAULT_MINSCROLL 8;
|
|
int SmoothScrollWindow(PSMOOTHSCROLLINFO psi)
|
|
{
|
|
int dx = psi->dx;
|
|
int dy = psi->dy;
|
|
LPCRECT lprcSrc = psi->lprcSrc;
|
|
LPCRECT lprcClip = psi->lprcClip;
|
|
HRGN hrgnUpdate = psi->hrgnUpdate;
|
|
LPRECT lprcUpdate = psi->lprcUpdate;
|
|
UINT fuScroll = psi->fuScroll;
|
|
int iRet = SIMPLEREGION;
|
|
RECT rcUpdate;
|
|
RECT rcSrc;
|
|
RECT rcClip;
|
|
int xStep;
|
|
int yStep;
|
|
int iSlicesDone = 0;
|
|
int iSlices;
|
|
DWORD dwTimeStart, dwTimeNow;
|
|
HRGN hrgnLocalUpdate;
|
|
UINT cxMinScroll = psi->cxMinScroll;
|
|
UINT cyMinScroll = psi->cyMinScroll;
|
|
UINT uMaxScrollTime = psi->uMaxScrollTime;
|
|
if (!lprcUpdate)
|
|
lprcUpdate = &rcUpdate;
|
|
SetRectEmpty(lprcUpdate);
|
|
|
|
if (psi->cbSize != sizeof(SMOOTHSCROLLINFO))
|
|
return 0;
|
|
|
|
// check the defaults
|
|
if (!(psi->fMask & SSIF_MINSCROLL )
|
|
|| cxMinScroll == SSI_DEFAULT)
|
|
cxMinScroll = DEFAULT_MINSCROLL;
|
|
|
|
if (!(psi->fMask & SSIF_MINSCROLL)
|
|
|| cyMinScroll == SSI_DEFAULT)
|
|
cyMinScroll = DEFAULT_MINSCROLL;
|
|
|
|
if (!(psi->fMask & SSIF_MAXSCROLLTIME)
|
|
|| uMaxScrollTime == SSI_DEFAULT)
|
|
uMaxScrollTime = DEFAULT_MAXSCROLLTIME;
|
|
|
|
if (uMaxScrollTime < SUBSCROLLS)
|
|
uMaxScrollTime = SUBSCROLLS;
|
|
|
|
|
|
if ((!(fuScroll & SSW_EX_IGNORESETTINGS)) &&
|
|
(!g_fSmoothScroll)) {
|
|
fuScroll |= SSW_EX_IMMEDIATE;
|
|
}
|
|
|
|
#ifdef ScrollWindowEx
|
|
#undef ScrollWindowEx
|
|
#endif
|
|
|
|
if (fuScroll & SSW_EX_IMMEDIATE) {
|
|
if (psi->fMask & SSIF_SCROLLPROC &&
|
|
psi->pfnScrollProc) {
|
|
|
|
return (psi->pfnScrollProc(psi->hwnd, dx, dy, lprcSrc, lprcClip, hrgnUpdate,
|
|
lprcUpdate, LOWORD(fuScroll)));
|
|
} else {
|
|
// do the old stuff
|
|
return ScrollWindowEx(psi->hwnd, dx, dy, lprcSrc, lprcClip, hrgnUpdate,
|
|
lprcUpdate, fuScroll & 0xFFFF);
|
|
}
|
|
}
|
|
|
|
// copy input rects locally
|
|
if (lprcSrc) {
|
|
rcSrc = *lprcSrc;
|
|
lprcSrc = &rcSrc;
|
|
}
|
|
if (lprcClip) {
|
|
rcClip = *lprcClip;
|
|
lprcClip = &rcClip;
|
|
}
|
|
|
|
if (!hrgnUpdate)
|
|
hrgnLocalUpdate = CreateRectRgn(0,0,0,0);
|
|
else
|
|
hrgnLocalUpdate = hrgnUpdate;
|
|
|
|
//set up initial vars
|
|
dwTimeStart = GetTickCount();
|
|
|
|
if (fuScroll & SSW_EX_NOTIMELIMIT) {
|
|
xStep = cxMinScroll * (dx < 0 ? -1 : 1);
|
|
yStep = cyMinScroll * (dy < 0 ? -1 : 1);
|
|
} else {
|
|
xStep = dx / SUBSCROLLS;
|
|
yStep = dy / SUBSCROLLS;
|
|
}
|
|
|
|
if (xStep == 0 && dx)
|
|
xStep = dx < 0 ? -1 : 1;
|
|
|
|
if (yStep == 0 && dy)
|
|
yStep = dy < 0 ? -1 : 1;
|
|
|
|
while (dx || dy) {
|
|
int x,y;
|
|
RECT rcTempUpdate;
|
|
|
|
if (fuScroll & SSW_EX_NOTIMELIMIT) {
|
|
x = xStep;
|
|
y = yStep;
|
|
if (abs(x) > abs(dx))
|
|
x = dx;
|
|
|
|
if (abs(y) > abs(dy))
|
|
y = dy;
|
|
|
|
} else {
|
|
dwTimeNow = GetTickCount();
|
|
|
|
iSlices = ((dwTimeNow - dwTimeStart) / (uMaxScrollTime / SUBSCROLLS)) - iSlicesDone;
|
|
if (iSlices < 0)
|
|
iSlices = 0;
|
|
|
|
|
|
do {
|
|
|
|
int iRet = 0;
|
|
|
|
iSlices++;
|
|
if ((iSlicesDone + iSlices) <= SUBSCROLLS) {
|
|
x = xStep * iSlices;
|
|
y = yStep * iSlices;
|
|
|
|
// this could go over if we rounded ?Step up to 1(-1) above
|
|
if (abs(x) > abs(dx))
|
|
x = dx;
|
|
|
|
if (abs(y) > abs(dy))
|
|
y = dy;
|
|
|
|
} else {
|
|
x = dx;
|
|
y = dy;
|
|
}
|
|
|
|
//DebugMsg(DM_TRACE, "SmoothScrollWindowCallback %d", iRet);
|
|
|
|
if (x == dx && y == dy)
|
|
break;
|
|
|
|
if ((((UINT)(abs(x)) >= cxMinScroll) || !x) &&
|
|
(((UINT)(abs(y)) >= cyMinScroll) || !y))
|
|
break;
|
|
|
|
} while (1);
|
|
}
|
|
|
|
if (psi->fMask & SSIF_SCROLLPROC &&
|
|
psi->pfnScrollProc) {
|
|
|
|
if (psi->pfnScrollProc(psi->hwnd, x, y, lprcSrc, lprcClip, hrgnLocalUpdate, &rcTempUpdate, LOWORD(fuScroll)) == ERROR) {
|
|
iRet = ERROR;
|
|
goto Bail;
|
|
}
|
|
} else {
|
|
if (ScrollWindowEx(psi->hwnd, x, y, lprcSrc, lprcClip, hrgnLocalUpdate, &rcTempUpdate, LOWORD(fuScroll)) == ERROR) {
|
|
iRet = ERROR;
|
|
goto Bail;
|
|
}
|
|
// we don't need to do this always because if iSlices >= iSlicesDone, we'll have scrolled blanks
|
|
//if (iSlices < iSlicesDone)
|
|
RedrawWindow(psi->hwnd, NULL, hrgnLocalUpdate, RDW_ERASE | RDW_ERASENOW | RDW_INVALIDATE);
|
|
|
|
UnionRect(lprcUpdate, &rcTempUpdate, lprcUpdate);
|
|
}
|
|
|
|
ScrollShrinkRect(x,y, (LPRECT)lprcSrc);
|
|
ScrollShrinkRect(x,y, (LPRECT)lprcClip);
|
|
|
|
dx -= x;
|
|
dy -= y;
|
|
iSlicesDone += iSlices;
|
|
}
|
|
|
|
Bail:
|
|
|
|
if (fuScroll & SW_SCROLLCHILDREN) {
|
|
RedrawWindow(psi->hwnd, lprcUpdate, NULL, RDW_INVALIDATE);
|
|
}
|
|
|
|
if (hrgnLocalUpdate != hrgnUpdate)
|
|
DeleteObject(hrgnLocalUpdate);
|
|
|
|
return iRet;
|
|
}
|
|
|
|
|
|
|
|
typedef BOOL (WINAPI *PLAYSOUNDFN)(LPCTSTR lpsz, HANDLE hMod, DWORD dwFlags);
|
|
typedef UINT (WINAPI *UINTVOIDFN)();
|
|
|
|
TCHAR const c_szWinMMDll[] = TEXT("winmm.dll");
|
|
char const c_szPlaySound[] = "PlaySound";
|
|
char const c_szwaveOutGetNumDevs[] = "waveOutGetNumDevs";
|
|
TCHAR const c_szSoundAliasRegKey[] = TEXT("AppEvents\\Schemes\\Apps");
|
|
TCHAR const c_szDotCurrent[] = TEXT(".current");
|
|
extern TCHAR const c_szExplorer[];
|
|
|
|
#define CCH_KEYMAX 256
|
|
BOOL g_fNeverPlaySound = FALSE;
|
|
|
|
void CCPlaySound(LPCTSTR lpszName)
|
|
{
|
|
DWORD cbSize = 0;
|
|
TCHAR szKey[CCH_KEYMAX];
|
|
HANDLE hMM;
|
|
|
|
|
|
if (g_fNeverPlaySound)
|
|
return;
|
|
|
|
hMM = GetModuleHandle(c_szWinMMDll);
|
|
if (!hMM)
|
|
hMM = LoadLibrary(c_szWinMMDll);
|
|
|
|
if (!hMM)
|
|
return;
|
|
|
|
// check the registry first
|
|
// if there's nothing registered, we blow off the play,
|
|
// but we don't set the MM_DONTLOAD flag so taht if they register
|
|
// something we will play it
|
|
wsprintf(szKey, TEXT("%s\\%s\\%s\\%s"), c_szSoundAliasRegKey, TEXT(".Default"), lpszName, c_szDotCurrent);
|
|
if ((RegQueryValue(HKEY_CURRENT_USER, szKey, NULL, &cbSize) == ERROR_SUCCESS) &&
|
|
(cbSize > 1)) {
|
|
|
|
PLAYSOUNDFN pfnPlaySound;
|
|
UINTVOIDFN pfnwaveOutGetNumDevs;
|
|
|
|
/// are there any devices?
|
|
pfnwaveOutGetNumDevs = (UINTVOIDFN)GetProcAddress(hMM, c_szwaveOutGetNumDevs);
|
|
pfnPlaySound = (PLAYSOUNDFN)GetProcAddress(hMM, c_szPlaySound);
|
|
if (!pfnPlaySound || !pfnwaveOutGetNumDevs || !pfnwaveOutGetNumDevs()) {
|
|
g_fNeverPlaySound = TRUE;
|
|
return;
|
|
}
|
|
|
|
pfnPlaySound(lpszName, NULL, SND_ALIAS | SND_ASYNC);
|
|
}
|
|
}
|
|
|
|
BOOL CCForwardEraseBackground(HWND hwnd, HDC hdc)
|
|
{
|
|
HWND hwndParent = GetParent(hwnd);
|
|
LRESULT lres = 0;
|
|
|
|
if (hwndParent)
|
|
{
|
|
// Adjust the origin so the parent paints in the right place
|
|
POINT pt = {0,0};
|
|
|
|
MapWindowPoints(hwnd, hwndParent, &pt, 1);
|
|
OffsetWindowOrgEx(hdc, pt.x, pt.y, &pt);
|
|
|
|
lres = SendMessage(hwndParent, WM_ERASEBKGND, (WPARAM) hdc, 0L);
|
|
|
|
SetWindowOrgEx(hdc, pt.x, pt.y, NULL);
|
|
}
|
|
return(lres != 0);
|
|
}
|
|
|
|
HFONT CCGetHotFont(HFONT hFont, HFONT *phFontHot)
|
|
{
|
|
if (!*phFontHot) {
|
|
LOGFONT lf;
|
|
|
|
// create the underline font
|
|
GetObject(hFont, sizeof(lf), &lf);
|
|
#ifndef DONT_UNDERLINE
|
|
lf.lfUnderline = TRUE;
|
|
#endif
|
|
*phFontHot = CreateFontIndirect(&lf);
|
|
}
|
|
return *phFontHot;
|
|
}
|
|
|
|
|
|
/*----------------------------------------------------------
|
|
Purpose: This function provides the commctrl version info. This
|
|
allows the caller to distinguish running NT SUR vs.
|
|
Win95 shell vs. Nashville, etc.
|
|
|
|
This API was not supplied in Win95 or NT SUR, so
|
|
the caller must GetProcAddress it. If this fails,
|
|
the caller is running on Win95 or NT SUR.
|
|
|
|
Returns: NO_ERROR
|
|
ERROR_INVALID_PARAMETER if pinfo is invalid
|
|
|
|
Cond: --
|
|
*/
|
|
STDAPI
|
|
DllGetVersion(
|
|
IN OUT DLLVERSIONINFO * pinfo)
|
|
{
|
|
HRESULT hres = E_INVALIDARG;
|
|
|
|
ASSERT(pinfo);
|
|
|
|
if (pinfo &&
|
|
!IsBadWritePtr(pinfo, sizeof(*pinfo)) &&
|
|
sizeof(*pinfo) == pinfo->cbSize)
|
|
{
|
|
pinfo->dwMajorVersion = (VER_PRODUCTVERSION_DW & 0xFF000000) >> 24;
|
|
pinfo->dwMinorVersion = (VER_PRODUCTVERSION_DW & 0x00FF0000) >> 16;
|
|
pinfo->dwBuildNumber = (VER_PRODUCTVERSION_DW & 0x0000FFFF);
|
|
|
|
#ifdef WINNT
|
|
pinfo->dwPlatformID = DLLVER_PLATFORM_NT;
|
|
#else
|
|
pinfo->dwPlatformID = DLLVER_PLATFORM_WINDOWS;
|
|
#endif
|
|
|
|
hres = NOERROR;
|
|
}
|
|
|
|
return hres;
|
|
}
|
|
|
|
|
|
//
|
|
// Translate the given font to a code page used for thunking text
|
|
//
|
|
UINT GetCodePageForFont (HFONT hFont)
|
|
{
|
|
#ifdef UNICODE
|
|
LOGFONT lf;
|
|
TCHAR szFontName[MAX_PATH];
|
|
CHARSETINFO csi;
|
|
DWORD dwSize, dwType;
|
|
HKEY hKey;
|
|
|
|
|
|
if (!GetObject (hFont, sizeof(lf), &lf)) {
|
|
return CP_ACP;
|
|
}
|
|
|
|
|
|
//
|
|
// Check for font substitutes
|
|
//
|
|
|
|
lstrcpy (szFontName, lf.lfFaceName);
|
|
|
|
if (RegOpenKeyEx (HKEY_LOCAL_MACHINE,
|
|
TEXT("Software\\Microsoft\\Windows NT\\CurrentVersion\\FontSubstitutes"),
|
|
0, KEY_READ, &hKey) == ERROR_SUCCESS) {
|
|
|
|
dwSize = MAX_PATH * sizeof(TCHAR);
|
|
RegQueryValueEx (hKey, lf.lfFaceName, NULL, &dwType,
|
|
(LPBYTE) szFontName, &dwSize);
|
|
|
|
RegCloseKey (hKey);
|
|
}
|
|
|
|
|
|
//
|
|
// This is to fix office for locales that use non 1252 versions
|
|
// of Ms Sans Serif and Ms Serif. These fonts incorrectly identify
|
|
// themselves as having an Ansi charset, so TranslateCharsetInfo will
|
|
// return the wrong value.
|
|
//
|
|
if ((lf.lfCharSet == ANSI_CHARSET) &&
|
|
(!lstrcmpi(L"Helv", szFontName) ||
|
|
!lstrcmpi(L"Ms Sans Serif", szFontName) ||
|
|
!lstrcmpi(L"Ms Serif", szFontName)))
|
|
{
|
|
return CP_ACP;
|
|
}
|
|
|
|
if (!TranslateCharsetInfo((DWORD FAR *) lf.lfCharSet, &csi, TCI_SRCCHARSET)) {
|
|
return CP_ACP;
|
|
}
|
|
|
|
return csi.ciACP;
|
|
#else
|
|
|
|
return CP_ACP;
|
|
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
#ifdef ACTIVE_ACCESSIBILITY
|
|
typedef void (CALLBACK* NOTIFYWINEVENTPROC)(UINT, HWND, LONG, LONG);
|
|
|
|
#define DONOTHING_NOTIFYWINEVENT ((NOTIFYWINEVENTPROC)1)
|
|
|
|
// --------------------------------------------------------------------------
|
|
//
|
|
// MyNotifyWinEvent()
|
|
//
|
|
// This tries to get the proc address of NotifyWinEvent(). If it fails, we
|
|
// remember that and do nothing.
|
|
//
|
|
// NOTE TO NT FOLKS:
|
|
// Don't freak out about this code. It will do nothing on NT, nothing yet
|
|
// that is. Active Accessibility will be ported to NT for Service Pack #1
|
|
// or at worst #2 after NT SUR ships, this code will work magically when
|
|
// that is done/
|
|
//
|
|
// --------------------------------------------------------------------------
|
|
void MyNotifyWinEvent(UINT event, HWND hwnd, LONG idContainer, LONG idChild)
|
|
{
|
|
static NOTIFYWINEVENTPROC s_pfnNotifyWinEvent = NULL;
|
|
|
|
if (!s_pfnNotifyWinEvent)
|
|
{
|
|
HMODULE hmod;
|
|
|
|
if (hmod = GetModuleHandle(TEXT("USER32")))
|
|
s_pfnNotifyWinEvent = (NOTIFYWINEVENTPROC)GetProcAddress(hmod,
|
|
"NotifyWinEvent");
|
|
|
|
if (!s_pfnNotifyWinEvent)
|
|
s_pfnNotifyWinEvent = DONOTHING_NOTIFYWINEVENT;
|
|
}
|
|
|
|
if (s_pfnNotifyWinEvent != DONOTHING_NOTIFYWINEVENT)
|
|
(* s_pfnNotifyWinEvent)(event, hwnd, idContainer, idChild);
|
|
}
|
|
|
|
#endif // ACTIVE_ACCESSIBILITY
|