#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; return (RegisterClass(&wc) || (GetLastError() == ERROR_CLASS_ALREADY_EXISTS)); } //---------------------------------------------------------------------------// 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; }