Source code of Windows XP (NT5)
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.

531 lines
13 KiB

  1. #include "ctlspriv.h"
  2. #pragma hdrstop
  3. #include "usrctl32.h"
  4. //---------------------------------------------------------------------------//
  5. #define TIMERID 1
  6. #define RDRMODE_VERT 0x00000001
  7. #define RDRMODE_HORZ 0x00000002
  8. #define RDRMODE_DIAG 0x00000004
  9. #define RDRCODE_START 1
  10. #define RDRCODE_SCROLL 2
  11. #define RDRCODE_END 3
  12. //
  13. // Instance data pointer access functions
  14. //
  15. #define ReaderMode_GetPtr(hwnd) \
  16. (PREADERINFO)GetWindowPtr(hwnd, 0)
  17. #define ReaderMode_SetPtr(hwnd, p) \
  18. (PREADERINFO)SetWindowPtr(hwnd, 0, p)
  19. //---------------------------------------------------------------------------//
  20. typedef LONG (CALLBACK* READERMODEPROC)(LPARAM lParam, int nCode, int dx, int dy);
  21. //---------------------------------------------------------------------------//
  22. typedef struct tagREADERMODE
  23. {
  24. UINT cbSize;
  25. DWORD dwFlags;
  26. READERMODEPROC pfnReaderModeProc;
  27. LPARAM lParam;
  28. } READERMODE, *PREADERMODE;
  29. //---------------------------------------------------------------------------//
  30. typedef struct tagREADERINFO
  31. {
  32. READERMODE;
  33. READERMODE rm;
  34. int dx;
  35. int dy;
  36. UINT uCursor;
  37. HBITMAP hbm;
  38. UINT dxBmp;
  39. UINT dyBmp;
  40. } READERINFO, *PREADERINFO;
  41. //---------------------------------------------------------------------------//
  42. typedef struct tagREADERWND
  43. {
  44. HWND hwnd;
  45. PREADERINFO prdr;
  46. } READERWND, *PREADERWND;
  47. //---------------------------------------------------------------------------//
  48. __inline FReader2Dim(PREADERINFO prdr)
  49. {
  50. return ((prdr->dwFlags & (RDRMODE_HORZ | RDRMODE_VERT)) ==
  51. (RDRMODE_HORZ | RDRMODE_VERT));
  52. }
  53. __inline FReaderVert(PREADERINFO prdr)
  54. {
  55. return (prdr->dwFlags & RDRMODE_VERT);
  56. }
  57. __inline FReaderHorz(PREADERINFO prdr)
  58. {
  59. return (prdr->dwFlags & RDRMODE_HORZ);
  60. }
  61. __inline FReaderDiag(PREADERINFO prdr)
  62. {
  63. return (prdr->dwFlags & RDRMODE_DIAG);
  64. }
  65. //---------------------------------------------------------------------------//
  66. void ReaderMode_SetCursor(PREADERINFO prdr, UINT uCursor)
  67. {
  68. if (prdr->uCursor != uCursor)
  69. {
  70. SetCursor(LoadCursor(NULL, MAKEINTRESOURCE(uCursor)));
  71. prdr->uCursor = uCursor;
  72. }
  73. }
  74. //---------------------------------------------------------------------------//
  75. //
  76. // ReaderMode_MouseMove
  77. //
  78. // Calculate dx and dy based on the flags passed in. Provide visual
  79. // feedback for the reader mode by setting the correct cursor.
  80. //
  81. void ReaderMode_MouseMove(HWND hwnd, PREADERINFO prdr, LPARAM lParam)
  82. {
  83. int dx = 0, dy = 0;
  84. RECT rc;
  85. UINT uCursor;
  86. POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
  87. GetWindowRect(hwnd, &rc);
  88. ClientToScreen(hwnd, &pt);
  89. if (FReaderVert(prdr))
  90. {
  91. if (pt.y < rc.top)
  92. {
  93. dy = pt.y - rc.top;
  94. }
  95. else if (pt.y > rc.bottom)
  96. {
  97. dy = pt.y - rc.bottom;
  98. }
  99. }
  100. if (FReaderHorz(prdr))
  101. {
  102. if (pt.x < rc.left)
  103. {
  104. dx = pt.x - rc.left;
  105. }
  106. else if (pt.x > rc.right)
  107. {
  108. dx = pt.x - rc.right;
  109. }
  110. }
  111. if (FReader2Dim(prdr))
  112. {
  113. if (dx == 0 && dy == 0)
  114. {
  115. ReaderMode_SetCursor(prdr, OCR_RDR2DIM);
  116. goto Exit;
  117. }
  118. if (!FReaderDiag(prdr))
  119. {
  120. if (prdr->dy != 0)
  121. {
  122. if (abs(dx) > abs(prdr->dy))
  123. {
  124. dy = 0;
  125. }
  126. else
  127. {
  128. dx = 0;
  129. }
  130. }
  131. else if (prdr->dx != 0)
  132. {
  133. if (abs(dy) > abs(prdr->dx))
  134. {
  135. dx = 0;
  136. }
  137. else
  138. {
  139. dy = 0;
  140. }
  141. }
  142. else if (dy != 0)
  143. {
  144. dx = 0;
  145. }
  146. }
  147. }
  148. else if (FReaderVert(prdr) && dy == 0)
  149. {
  150. ReaderMode_SetCursor(prdr, OCR_RDRVERT);
  151. goto Exit;
  152. }
  153. else if (FReaderHorz(prdr) && dx == 0)
  154. {
  155. ReaderMode_SetCursor(prdr, OCR_RDRHORZ);
  156. goto Exit;
  157. }
  158. if (dx == 0)
  159. {
  160. uCursor = (dy > 0) ? OCR_RDRSOUTH : OCR_RDRNORTH;
  161. }
  162. else if (dx > 0)
  163. {
  164. if (dy == 0)
  165. {
  166. uCursor = OCR_RDREAST;
  167. }
  168. else
  169. {
  170. uCursor = (dy > 0) ? OCR_RDRSOUTHEAST : OCR_RDRNORTHEAST;
  171. }
  172. }
  173. else if (dx < 0)
  174. {
  175. if (dy == 0)
  176. {
  177. uCursor = OCR_RDRWEST;
  178. }
  179. else
  180. {
  181. uCursor = (dy > 0) ? OCR_RDRSOUTHWEST : OCR_RDRNORTHWEST;
  182. }
  183. }
  184. ReaderMode_SetCursor(prdr, uCursor);
  185. Exit:
  186. prdr->dx = dx;
  187. prdr->dy = dy;
  188. }
  189. //---------------------------------------------------------------------------//
  190. void ReaderMode_Feedback(HWND hwnd, PREADERINFO prdr)
  191. {
  192. if (prdr->dx || prdr->dy)
  193. {
  194. if (prdr->pfnReaderModeProc(prdr->lParam, RDRCODE_SCROLL, prdr->dx, prdr->dy) == 0)
  195. {
  196. DestroyWindow(hwnd);
  197. }
  198. }
  199. }
  200. //---------------------------------------------------------------------------//
  201. LRESULT CALLBACK ReaderMode_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  202. {
  203. HDC hdc, hdcMem;
  204. HPEN hpen, hpenOld;
  205. HBRUSH hbrOld;
  206. HRGN hrgn;
  207. RECT rc;
  208. POINT pt;
  209. int nBitmap, cx, cy;
  210. PREADERINFO prdr;
  211. LPCREATESTRUCT pcs;
  212. PREADERMODE prdrm;
  213. BITMAP bmp;
  214. prdr = ReaderMode_GetPtr(hwnd);
  215. if (prdr || msg == WM_CREATE)
  216. {
  217. switch (msg)
  218. {
  219. case WM_TIMER:
  220. ReaderMode_Feedback(hwnd, prdr);
  221. return 0;
  222. case WM_MOUSEWHEEL:
  223. case WM_LBUTTONUP:
  224. case WM_RBUTTONUP:
  225. case WM_XBUTTONUP:
  226. case WM_LBUTTONDOWN:
  227. case WM_RBUTTONDOWN:
  228. case WM_MBUTTONDOWN:
  229. case WM_XBUTTONDOWN:
  230. case WM_KEYDOWN:
  231. ReleaseCapture();
  232. return 0;
  233. case WM_MOUSEMOVE:
  234. ReaderMode_MouseMove(hwnd, prdr, lParam);
  235. return 0;
  236. case WM_MBUTTONUP:
  237. pt.x = GET_X_LPARAM(lParam);
  238. pt.y = GET_Y_LPARAM(lParam);
  239. GetClientRect(hwnd, &rc);
  240. if (!PtInRect(&rc, pt))
  241. {
  242. ReleaseCapture();
  243. }
  244. return 0;
  245. case WM_CAPTURECHANGED:
  246. DestroyWindow(hwnd);
  247. return 0;
  248. case WM_NCDESTROY:
  249. KillTimer(hwnd, TIMERID);
  250. prdr->pfnReaderModeProc(prdr->lParam, RDRCODE_END, 0, 0);
  251. if (prdr->hbm != NULL)
  252. {
  253. DeleteObject(prdr->hbm);
  254. }
  255. UserLocalFree(prdr);
  256. return 0;
  257. case WM_CREATE:
  258. prdr = (PREADERINFO)UserLocalAlloc(HEAP_ZERO_MEMORY, sizeof(READERINFO));
  259. if (prdr == NULL)
  260. {
  261. return -1;
  262. }
  263. pcs = (LPCREATESTRUCT)lParam;
  264. prdrm = (PREADERMODE)pcs->lpCreateParams;
  265. CopyMemory(prdr, prdrm, sizeof(READERMODE));
  266. ReaderMode_SetPtr(hwnd, prdr);
  267. if (prdr->pfnReaderModeProc == NULL)
  268. {
  269. return -1;
  270. }
  271. if (FReader2Dim(prdr))
  272. {
  273. nBitmap = OBM_RDR2DIM;
  274. }
  275. else if (FReaderVert(prdr))
  276. {
  277. nBitmap = OBM_RDRVERT;
  278. }
  279. else if (FReaderHorz(prdr))
  280. {
  281. nBitmap = OBM_RDRHORZ;
  282. }
  283. else
  284. {
  285. return -1;
  286. }
  287. SetWindowLong(hwnd, GWL_EXSTYLE, WS_EX_TOOLWINDOW);
  288. SetWindowLong(hwnd, GWL_STYLE, WS_POPUP | WS_CLIPSIBLINGS);
  289. prdr->hbm = LoadBitmap(NULL, MAKEINTRESOURCE(nBitmap));
  290. if (prdr->hbm == NULL ||
  291. GetObject(prdr->hbm, sizeof(BITMAP), &bmp) == 0)
  292. {
  293. return -1;
  294. }
  295. if (prdr->pfnReaderModeProc(prdr->lParam, RDRCODE_START, 0, 0) == 0)
  296. {
  297. return -1;
  298. }
  299. prdr->dxBmp = bmp.bmWidth;
  300. prdr->dyBmp = bmp.bmHeight;
  301. cx = bmp.bmWidth + 1;
  302. cy = bmp.bmHeight + 1;
  303. GetCursorPos(&pt);
  304. pt.x -= cx/2;
  305. pt.y -= cy/2;
  306. if ((hrgn = CreateEllipticRgn(0, 0, cx, cy)) != NULL)
  307. {
  308. SetWindowRgn(hwnd, hrgn, FALSE);
  309. }
  310. SetWindowPos(hwnd, HWND_TOPMOST, pt.x, pt.y, cx, cy,
  311. SWP_SHOWWINDOW | SWP_NOACTIVATE);
  312. SetCapture(hwnd);
  313. SetFocus(hwnd);
  314. SetTimer(hwnd, TIMERID, 10, NULL);
  315. return 0;
  316. case WM_ERASEBKGND:
  317. hdc = (HDC)wParam;
  318. if ((hdcMem = CreateCompatibleDC(hdc)) == NULL)
  319. {
  320. return FALSE;
  321. }
  322. SelectObject(hdcMem, prdr->hbm);
  323. hpen = CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
  324. if (hpen)
  325. {
  326. hpenOld = (HPEN)SelectObject(hdc, hpen);
  327. hbrOld = (HBRUSH)SelectObject(hdc, GetStockObject(NULL_BRUSH));
  328. BitBlt(hdc, 0, 0, prdr->dxBmp, prdr->dyBmp, hdcMem, 0, 0, SRCCOPY);
  329. Ellipse(hdc, 0, 0, prdr->dxBmp, prdr->dyBmp);
  330. SelectObject(hdc, hpenOld);
  331. SelectObject(hdc, hbrOld);
  332. DeleteObject(hpen);
  333. }
  334. DeleteObject(hdcMem);
  335. return TRUE;
  336. }
  337. }
  338. return DefWindowProc(hwnd, msg, wParam, lParam);
  339. }
  340. //---------------------------------------------------------------------------//
  341. LONG ReaderMode_InternalProc(LPARAM lParam, int nCode, int dx, int dy)
  342. {
  343. DWORD dwDelay;
  344. UINT uMsg, uCode;
  345. int n, nAbs;
  346. if (nCode != RDRCODE_SCROLL)
  347. return TRUE;
  348. if (dy != 0)
  349. {
  350. uCode = SB_LINEUP;
  351. uMsg = WM_VSCROLL;
  352. n = dy;
  353. }
  354. else
  355. {
  356. uCode = SB_LINELEFT;
  357. uMsg = WM_HSCROLL;
  358. n = dx;
  359. }
  360. nAbs = abs(n);
  361. if (nAbs >= 120)
  362. {
  363. uCode += 2;
  364. dwDelay = 0;
  365. }
  366. else
  367. {
  368. dwDelay = 1000 - (nAbs / 2) * 15;
  369. }
  370. if (n > 0)
  371. {
  372. uCode += 1;
  373. }
  374. SendMessage((HWND)lParam, uMsg, MAKELONG(uCode, dwDelay), 0);
  375. UpdateWindow((HWND)lParam);
  376. return TRUE;
  377. }
  378. //---------------------------------------------------------------------------//
  379. BOOL InitReaderModeClass(HINSTANCE hinst)
  380. {
  381. WNDCLASS wc;
  382. wc.lpfnWndProc = ReaderMode_WndProc;
  383. wc.lpszClassName = WC_READERMODE;
  384. wc.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  385. wc.cbClsExtra = 0;
  386. wc.cbWndExtra = sizeof(READERINFO);
  387. wc.hInstance = hinst;
  388. wc.hIcon = NULL;
  389. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  390. wc.hbrBackground = GetStockObject(WHITE_BRUSH);
  391. wc.lpszMenuName = NULL;
  392. if (!RegisterClass(&wc) && !GetClassInfo(hinst, WC_BUTTON, &wc))
  393. return FALSE;
  394. return TRUE;
  395. }
  396. //---------------------------------------------------------------------------//
  397. BOOL ReaderMode_ScrollEnabled(HWND hwnd, BOOL fVert)
  398. {
  399. SCROLLBARINFO sbi = {0};
  400. BOOL fResult = FALSE;
  401. sbi.cbSize = sizeof(sbi);
  402. if ( GetScrollBarInfo(hwnd, fVert ? OBJID_VSCROLL : OBJID_HSCROLL, &sbi) )
  403. {
  404. fResult = (sbi.rgstate[0] & (STATE_SYSTEM_UNAVAILABLE|STATE_SYSTEM_INVISIBLE|STATE_SYSTEM_OFFSCREEN)) ? FALSE : TRUE;
  405. }
  406. return fResult;
  407. }
  408. //---------------------------------------------------------------------------//
  409. //
  410. // EnterReaderMode - entry point to the ReaderMode control displayed when
  411. // the user presses the scroll wheel. Renders an eliptical
  412. // window that traps mouse movements in order to autoscroll
  413. // the given hwnd.
  414. //
  415. BOOL EnterReaderMode(HWND hwnd)
  416. {
  417. BOOL fResult = FALSE;
  418. if (GetCapture() == NULL)
  419. {
  420. READERMODE rdrm;
  421. rdrm.cbSize = sizeof(READERMODE);
  422. rdrm.pfnReaderModeProc = ReaderMode_InternalProc;
  423. rdrm.lParam = (LPARAM)hwnd;
  424. rdrm.dwFlags = 0;
  425. if (ReaderMode_ScrollEnabled(hwnd, TRUE))
  426. {
  427. rdrm.dwFlags |= RDRMODE_VERT;
  428. }
  429. if (ReaderMode_ScrollEnabled(hwnd, FALSE))
  430. {
  431. rdrm.dwFlags |= RDRMODE_HORZ;
  432. }
  433. if (rdrm.dwFlags)
  434. {
  435. fResult = (CreateWindowEx(0,
  436. WC_READERMODE,
  437. NULL,
  438. 0, 0, 0, 0, 0,
  439. NULL,
  440. NULL,
  441. NULL,
  442. (LPVOID)&rdrm) != NULL);
  443. }
  444. }
  445. return fResult;
  446. }