532 lines
13 KiB
C
532 lines
13 KiB
C
#include "ctlspriv.h"
|
|
#pragma hdrstop
|
|
#include "usrctl32.h"
|
|
|
|
//---------------------------------------------------------------------------//
|
|
#define TIMERID 1
|
|
|
|
#define RDRMODE_VERT 0x00000001
|
|
#define RDRMODE_HORZ 0x00000002
|
|
#define RDRMODE_DIAG 0x00000004
|
|
|
|
#define RDRCODE_START 1
|
|
#define RDRCODE_SCROLL 2
|
|
#define RDRCODE_END 3
|
|
|
|
//
|
|
// Instance data pointer access functions
|
|
//
|
|
#define ReaderMode_GetPtr(hwnd) \
|
|
(PREADERINFO)GetWindowPtr(hwnd, 0)
|
|
|
|
#define ReaderMode_SetPtr(hwnd, p) \
|
|
(PREADERINFO)SetWindowPtr(hwnd, 0, p)
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
typedef LONG (CALLBACK* READERMODEPROC)(LPARAM lParam, int nCode, int dx, int dy);
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
typedef struct tagREADERMODE
|
|
{
|
|
UINT cbSize;
|
|
DWORD dwFlags;
|
|
READERMODEPROC pfnReaderModeProc;
|
|
LPARAM lParam;
|
|
} READERMODE, *PREADERMODE;
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
typedef struct tagREADERINFO
|
|
{
|
|
READERMODE;
|
|
READERMODE rm;
|
|
int dx;
|
|
int dy;
|
|
UINT uCursor;
|
|
HBITMAP hbm;
|
|
UINT dxBmp;
|
|
UINT dyBmp;
|
|
} READERINFO, *PREADERINFO;
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
typedef struct tagREADERWND
|
|
{
|
|
HWND hwnd;
|
|
PREADERINFO prdr;
|
|
} READERWND, *PREADERWND;
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
__inline FReader2Dim(PREADERINFO prdr)
|
|
{
|
|
return ((prdr->dwFlags & (RDRMODE_HORZ | RDRMODE_VERT)) ==
|
|
(RDRMODE_HORZ | RDRMODE_VERT));
|
|
}
|
|
__inline FReaderVert(PREADERINFO prdr)
|
|
{
|
|
return (prdr->dwFlags & RDRMODE_VERT);
|
|
}
|
|
__inline FReaderHorz(PREADERINFO prdr)
|
|
{
|
|
return (prdr->dwFlags & RDRMODE_HORZ);
|
|
}
|
|
__inline FReaderDiag(PREADERINFO prdr)
|
|
{
|
|
return (prdr->dwFlags & RDRMODE_DIAG);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
void ReaderMode_SetCursor(PREADERINFO prdr, UINT uCursor)
|
|
{
|
|
if (prdr->uCursor != uCursor)
|
|
{
|
|
SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(uCursor)));
|
|
prdr->uCursor = uCursor;
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// ReaderMode_MouseMove
|
|
//
|
|
// Calculate dx and dy based on the flags passed in. Provide visual
|
|
// feedback for the reader mode by setting the correct cursor.
|
|
//
|
|
void ReaderMode_MouseMove(HWND hwnd, PREADERINFO prdr, LPARAM lParam)
|
|
{
|
|
int dx = 0, dy = 0;
|
|
RECT rc;
|
|
UINT uCursor;
|
|
POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
|
|
|
GetWindowRect(hwnd, &rc);
|
|
|
|
ClientToScreen(hwnd, &pt);
|
|
|
|
if (FReaderVert(prdr))
|
|
{
|
|
if (pt.y < rc.top)
|
|
{
|
|
dy = pt.y - rc.top;
|
|
}
|
|
else if (pt.y > rc.bottom)
|
|
{
|
|
dy = pt.y - rc.bottom;
|
|
}
|
|
}
|
|
|
|
if (FReaderHorz(prdr))
|
|
{
|
|
if (pt.x < rc.left)
|
|
{
|
|
dx = pt.x - rc.left;
|
|
}
|
|
else if (pt.x > rc.right)
|
|
{
|
|
dx = pt.x - rc.right;
|
|
}
|
|
}
|
|
|
|
if (FReader2Dim(prdr))
|
|
{
|
|
if (dx == 0 && dy == 0)
|
|
{
|
|
ReaderMode_SetCursor(prdr, OCR_RDR2DIM);
|
|
goto Exit;
|
|
}
|
|
|
|
if (!FReaderDiag(prdr))
|
|
{
|
|
if (prdr->dy != 0)
|
|
{
|
|
if (abs(dx) > abs(prdr->dy))
|
|
{
|
|
dy = 0;
|
|
}
|
|
else
|
|
{
|
|
dx = 0;
|
|
}
|
|
}
|
|
else if (prdr->dx != 0)
|
|
{
|
|
if (abs(dy) > abs(prdr->dx))
|
|
{
|
|
dx = 0;
|
|
}
|
|
else
|
|
{
|
|
dy = 0;
|
|
}
|
|
}
|
|
else if (dy != 0)
|
|
{
|
|
dx = 0;
|
|
}
|
|
}
|
|
}
|
|
else if (FReaderVert(prdr) && dy == 0)
|
|
{
|
|
ReaderMode_SetCursor(prdr, OCR_RDRVERT);
|
|
goto Exit;
|
|
}
|
|
else if (FReaderHorz(prdr) && dx == 0)
|
|
{
|
|
ReaderMode_SetCursor(prdr, OCR_RDRHORZ);
|
|
goto Exit;
|
|
}
|
|
|
|
if (dx == 0)
|
|
{
|
|
uCursor = (dy > 0) ? OCR_RDRSOUTH : OCR_RDRNORTH;
|
|
}
|
|
else if (dx > 0)
|
|
{
|
|
if (dy == 0)
|
|
{
|
|
uCursor = OCR_RDREAST;
|
|
}
|
|
else
|
|
{
|
|
uCursor = (dy > 0) ? OCR_RDRSOUTHEAST : OCR_RDRNORTHEAST;
|
|
}
|
|
}
|
|
else if (dx < 0)
|
|
{
|
|
if (dy == 0)
|
|
{
|
|
uCursor = OCR_RDRWEST;
|
|
}
|
|
else
|
|
{
|
|
uCursor = (dy > 0) ? OCR_RDRSOUTHWEST : OCR_RDRNORTHWEST;
|
|
}
|
|
}
|
|
|
|
ReaderMode_SetCursor(prdr, uCursor);
|
|
|
|
Exit:
|
|
prdr->dx = dx;
|
|
prdr->dy = dy;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
void ReaderMode_Feedback(HWND hwnd, PREADERINFO prdr)
|
|
{
|
|
if (prdr->dx || prdr->dy)
|
|
{
|
|
if (prdr->pfnReaderModeProc(prdr->lParam, RDRCODE_SCROLL, prdr->dx, prdr->dy) == 0)
|
|
{
|
|
DestroyWindow(hwnd);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
LRESULT CALLBACK ReaderMode_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
HDC hdc, hdcMem;
|
|
HPEN hpen, hpenOld;
|
|
HBRUSH hbrOld;
|
|
HRGN hrgn;
|
|
RECT rc;
|
|
POINT pt;
|
|
int nBitmap, cx, cy;
|
|
PREADERINFO prdr;
|
|
LPCREATESTRUCT pcs;
|
|
PREADERMODE prdrm;
|
|
BITMAP bmp;
|
|
|
|
prdr = ReaderMode_GetPtr(hwnd);
|
|
|
|
if (prdr || msg == WM_CREATE)
|
|
{
|
|
switch (msg)
|
|
{
|
|
case WM_TIMER:
|
|
ReaderMode_Feedback(hwnd, prdr);
|
|
return 0;
|
|
|
|
case WM_MOUSEWHEEL:
|
|
case WM_LBUTTONUP:
|
|
case WM_RBUTTONUP:
|
|
case WM_XBUTTONUP:
|
|
case WM_LBUTTONDOWN:
|
|
case WM_RBUTTONDOWN:
|
|
case WM_MBUTTONDOWN:
|
|
case WM_XBUTTONDOWN:
|
|
case WM_KEYDOWN:
|
|
ReleaseCapture();
|
|
return 0;
|
|
|
|
case WM_MOUSEMOVE:
|
|
ReaderMode_MouseMove(hwnd, prdr, lParam);
|
|
return 0;
|
|
|
|
case WM_MBUTTONUP:
|
|
pt.x = GET_X_LPARAM(lParam);
|
|
pt.y = GET_Y_LPARAM(lParam);
|
|
GetClientRect(hwnd, &rc);
|
|
if (!PtInRect(&rc, pt))
|
|
{
|
|
ReleaseCapture();
|
|
}
|
|
return 0;
|
|
|
|
case WM_CAPTURECHANGED:
|
|
DestroyWindow(hwnd);
|
|
return 0;
|
|
|
|
case WM_NCDESTROY:
|
|
KillTimer(hwnd, TIMERID);
|
|
|
|
prdr->pfnReaderModeProc(prdr->lParam, RDRCODE_END, 0, 0);
|
|
|
|
if (prdr->hbm != NULL)
|
|
{
|
|
DeleteObject(prdr->hbm);
|
|
}
|
|
UserLocalFree(prdr);
|
|
return 0;
|
|
|
|
case WM_CREATE:
|
|
prdr = (PREADERINFO)UserLocalAlloc(HEAP_ZERO_MEMORY, sizeof(READERINFO));
|
|
if (prdr == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
pcs = (LPCREATESTRUCT)lParam;
|
|
prdrm = (PREADERMODE)pcs->lpCreateParams;
|
|
CopyMemory(prdr, prdrm, sizeof(READERMODE));
|
|
ReaderMode_SetPtr(hwnd, prdr);
|
|
|
|
if (prdr->pfnReaderModeProc == NULL)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (FReader2Dim(prdr))
|
|
{
|
|
nBitmap = OBM_RDR2DIM;
|
|
}
|
|
else if (FReaderVert(prdr))
|
|
{
|
|
nBitmap = OBM_RDRVERT;
|
|
}
|
|
else if (FReaderHorz(prdr))
|
|
{
|
|
nBitmap = OBM_RDRHORZ;
|
|
}
|
|
else
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
|
|
SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_CLIPSIBLINGS);
|
|
|
|
prdr->hbm = LoadBitmap(NULL, MAKEINTRESOURCE(nBitmap));
|
|
if (prdr->hbm == NULL ||
|
|
GetObject(prdr->hbm, sizeof(BITMAP), &bmp) == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
if (prdr->pfnReaderModeProc(prdr->lParam, RDRCODE_START, 0, 0) == 0)
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
prdr->dxBmp = bmp.bmWidth;
|
|
prdr->dyBmp = bmp.bmHeight;
|
|
|
|
cx = bmp.bmWidth + 1;
|
|
cy = bmp.bmHeight + 1;
|
|
|
|
GetCursorPos(&pt);
|
|
pt.x -= cx/2;
|
|
pt.y -= cy/2;
|
|
|
|
if ((hrgn = CreateEllipticRgn(0, 0, cx, cy)) != NULL)
|
|
{
|
|
SetWindowRgn(hwnd, hrgn, FALSE);
|
|
}
|
|
|
|
SetWindowPos(hwnd, HWND_TOPMOST, pt.x, pt.y, cx, cy,
|
|
SWP_SHOWWINDOW | SWP_NOACTIVATE);
|
|
|
|
SetCapture(hwnd);
|
|
SetFocus(hwnd);
|
|
SetTimer(hwnd, TIMERID, 10, NULL);
|
|
return 0;
|
|
|
|
case WM_ERASEBKGND:
|
|
hdc = (HDC)wParam;
|
|
|
|
if ((hdcMem = CreateCompatibleDC(hdc)) == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
SelectObject(hdcMem, prdr->hbm);
|
|
hpen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
|
|
if (hpen)
|
|
{
|
|
hpenOld = (HPEN)SelectObject(hdc, hpen);
|
|
hbrOld = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
|
|
|
|
BitBlt(hdc, 0, 0, prdr->dxBmp, prdr->dyBmp, hdcMem, 0, 0, SRCCOPY);
|
|
Ellipse(hdc, 0, 0, prdr->dxBmp, prdr->dyBmp);
|
|
|
|
SelectObject(hdc, hpenOld);
|
|
SelectObject(hdc, hbrOld);
|
|
|
|
DeleteObject(hpen);
|
|
}
|
|
DeleteObject(hdcMem);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
LONG ReaderMode_InternalProc(LPARAM lParam, int nCode, int dx, int dy)
|
|
{
|
|
DWORD dwDelay;
|
|
UINT uMsg, uCode;
|
|
int n, nAbs;
|
|
|
|
if (nCode != RDRCODE_SCROLL)
|
|
return TRUE;
|
|
|
|
if (dy != 0)
|
|
{
|
|
uCode = SB_LINEUP;
|
|
uMsg = WM_VSCROLL;
|
|
n = dy;
|
|
}
|
|
else
|
|
{
|
|
uCode = SB_LINELEFT;
|
|
uMsg = WM_HSCROLL;
|
|
n = dx;
|
|
}
|
|
|
|
nAbs = abs(n);
|
|
if (nAbs >= 120)
|
|
{
|
|
uCode += 2;
|
|
dwDelay = 0;
|
|
}
|
|
else
|
|
{
|
|
dwDelay = 1000 - (nAbs / 2) * 15;
|
|
}
|
|
|
|
if (n > 0)
|
|
{
|
|
uCode += 1;
|
|
}
|
|
|
|
SendMessage((HWND)lParam, uMsg, MAKELONG(uCode, dwDelay), 0);
|
|
UpdateWindow((HWND)lParam);
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
BOOL InitReaderModeClass(HINSTANCE hinst)
|
|
{
|
|
WNDCLASS wc;
|
|
|
|
wc.lpfnWndProc = ReaderMode_WndProc;
|
|
wc.lpszClassName = WC_READERMODE;
|
|
wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = sizeof(READERINFO);
|
|
wc.hInstance = hinst;
|
|
wc.hIcon = NULL;
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = GetStockObject(WHITE_BRUSH);
|
|
wc.lpszMenuName = NULL;
|
|
|
|
if (!RegisterClass(&wc) && !GetClassInfo(hinst, WC_BUTTON, &wc))
|
|
return FALSE;
|
|
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
//---------------------------------------------------------------------------//
|
|
BOOL ReaderMode_ScrollEnabled(HWND hwnd, BOOL fVert)
|
|
{
|
|
SCROLLBARINFO sbi = {0};
|
|
BOOL fResult = FALSE;
|
|
|
|
sbi.cbSize = sizeof(sbi);
|
|
if ( GetScrollBarInfo(hwnd, fVert ? OBJID_VSCROLL : OBJID_HSCROLL, &sbi) )
|
|
{
|
|
fResult = (sbi.rgstate[0] & (STATE_SYSTEM_UNAVAILABLE|STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)) ? FALSE : TRUE;
|
|
}
|
|
|
|
return fResult;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------//
|
|
//
|
|
// EnterReaderMode - entry point to the ReaderMode control displayed when
|
|
// the user presses the scroll wheel. Renders an eliptical
|
|
// window that traps mouse movements in order to autoscroll
|
|
// the given hwnd.
|
|
//
|
|
BOOL EnterReaderMode(HWND hwnd)
|
|
{
|
|
BOOL fResult = FALSE;
|
|
|
|
if (GetCapture() == NULL)
|
|
{
|
|
READERMODE rdrm;
|
|
|
|
rdrm.cbSize = sizeof(READERMODE);
|
|
rdrm.pfnReaderModeProc = ReaderMode_InternalProc;
|
|
rdrm.lParam = (LPARAM)hwnd;
|
|
rdrm.dwFlags = 0;
|
|
|
|
if (ReaderMode_ScrollEnabled(hwnd, TRUE))
|
|
{
|
|
rdrm.dwFlags |= RDRMODE_VERT;
|
|
}
|
|
|
|
if (ReaderMode_ScrollEnabled(hwnd, FALSE))
|
|
{
|
|
rdrm.dwFlags |= RDRMODE_HORZ;
|
|
}
|
|
|
|
if (rdrm.dwFlags)
|
|
{
|
|
fResult = (CreateWindowEx(0,
|
|
WC_READERMODE,
|
|
NULL,
|
|
0, 0, 0, 0, 0,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
(LPVOID)&rdrm) != NULL);
|
|
}
|
|
}
|
|
|
|
return fResult;
|
|
}
|