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.

235 lines
5.6 KiB

  1. //===========================================================================
  2. // Image dragging API (definitely private)
  3. //===========================================================================
  4. #include <windows.h>
  5. #include <windowsx.h>
  6. #include "autoscrl.h"
  7. #include "common.h"
  8. #include "debug.h"
  9. #if 0
  10. BOOL DAD_SetDragImage(HIMAGELIST him, POINT FAR* pptOffset);
  11. BOOL DAD_DragEnter(HWND hwndTarget);
  12. BOOL DAD_DragEnterEx(HWND hwndTarget, const POINT ptStart);
  13. BOOL DAD_ShowDragImage(BOOL fShow);
  14. BOOL DAD_DragMove(POINT pt);
  15. BOOL DAD_DragLeave(void);
  16. BOOL DAD_SetDragImageFromListView(HWND hwndLV, POINT ptOffset);
  17. #endif
  18. // -------------- auto scroll stuff --------------
  19. BOOL _AddTimeSample(AUTO_SCROLL_DATA *pad, const POINT *ppt, DWORD dwTime)
  20. {
  21. pad->pts[pad->iNextSample] = *ppt;
  22. pad->dwTimes[pad->iNextSample] = dwTime;
  23. pad->iNextSample++;
  24. if (pad->iNextSample == ARRAYSIZE(pad->pts))
  25. pad->bFull = TRUE;
  26. pad->iNextSample = pad->iNextSample % ARRAYSIZE(pad->pts);
  27. return pad->bFull;
  28. }
  29. #ifdef DEBUG
  30. // for debugging, verify we have good averages
  31. DWORD g_time = 0;
  32. int g_distance = 0;
  33. #endif
  34. int _CurrentVelocity(AUTO_SCROLL_DATA *pad)
  35. {
  36. int i, iStart, iNext;
  37. int dx, dy, distance;
  38. DWORD time;
  39. Assert(pad->bFull);
  40. distance = 0;
  41. time = 1; // avoid div by zero
  42. i = iStart = pad->iNextSample % ARRAYSIZE(pad->pts);
  43. do {
  44. iNext = (i + 1) % ARRAYSIZE(pad->pts);
  45. dx = abs(pad->pts[i].x - pad->pts[iNext].x);
  46. dy = abs(pad->pts[i].y - pad->pts[iNext].y);
  47. distance += (dx + dy);
  48. time += abs(pad->dwTimes[i] - pad->dwTimes[iNext]);
  49. i = iNext;
  50. } while (i != iStart);
  51. #ifdef DEBUG
  52. g_time = time;
  53. g_distance = distance;
  54. #endif
  55. // scale this so we don't loose accuracy
  56. return (distance * 1024) / time;
  57. }
  58. // NOTE: this is duplicated in shell32.dll
  59. //
  60. // checks to see if we are at the end position of a scroll bar
  61. // to avoid scrolling when not needed (avoid flashing)
  62. //
  63. // in:
  64. // code SB_VERT or SB_HORZ
  65. // bDown FALSE is up or left
  66. // TRUE is down or right
  67. BOOL CanScroll(HWND hwnd, int code, BOOL bDown)
  68. {
  69. SCROLLINFO si;
  70. si.cbSize = sizeof(SCROLLINFO);
  71. si.fMask = SIF_ALL;
  72. GetScrollInfo(hwnd, code, &si);
  73. if (bDown)
  74. {
  75. if (si.nPage)
  76. si.nMax -= si.nPage - 1;
  77. return si.nPos < si.nMax;
  78. }
  79. else
  80. {
  81. return si.nPos > si.nMin;
  82. }
  83. }
  84. #define DSD_NONE 0x0000
  85. #define DSD_UP 0x0001
  86. #define DSD_DOWN 0x0002
  87. #define DSD_LEFT 0x0004
  88. #define DSD_RIGHT 0x0008
  89. //---------------------------------------------------------------------------
  90. DWORD DAD_DragScrollDirection(HWND hwnd, const POINT *ppt)
  91. {
  92. RECT rcOuter, rc;
  93. DWORD dwDSD = DSD_NONE; // 0
  94. DWORD dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  95. // BUGBUG: do these as globals
  96. #define g_cxVScroll GetSystemMetrics(SM_CXVSCROLL)
  97. #define g_cyHScroll GetSystemMetrics(SM_CYHSCROLL)
  98. #define g_cxSmIcon GetSystemMetrics(SM_CXSMICON)
  99. #define g_cySmIcon GetSystemMetrics(SM_CYSMICON)
  100. #define g_cxIcon GetSystemMetrics(SM_CXICON)
  101. #define g_cyIcon GetSystemMetrics(SM_CXICON)
  102. GetClientRect(hwnd, &rc);
  103. if (dwStyle & WS_HSCROLL)
  104. rc.bottom -= g_cyHScroll;
  105. if (dwStyle & WS_VSCROLL)
  106. rc.right -= g_cxVScroll;
  107. // the explorer forwards us drag/drop things outside of our client area
  108. // so we need to explictly test for that before we do things
  109. //
  110. rcOuter = rc;
  111. InflateRect(&rcOuter, g_cxSmIcon, g_cySmIcon);
  112. InflateRect(&rc, -g_cxIcon, -g_cyIcon);
  113. if (!PtInRect(&rc, *ppt) && PtInRect(&rcOuter, *ppt))
  114. {
  115. // Yep - can we scroll?
  116. if (dwStyle & WS_HSCROLL)
  117. {
  118. if (ppt->x < rc.left)
  119. {
  120. if (CanScroll(hwnd, SB_HORZ, FALSE))
  121. dwDSD |= DSD_LEFT;
  122. }
  123. else if (ppt->x > rc.right)
  124. {
  125. if (CanScroll(hwnd, SB_HORZ, TRUE))
  126. dwDSD |= DSD_RIGHT;
  127. }
  128. }
  129. if (dwStyle & WS_VSCROLL)
  130. {
  131. if (ppt->y < rc.top)
  132. {
  133. if (CanScroll(hwnd, SB_VERT, FALSE))
  134. dwDSD |= DSD_UP;
  135. }
  136. else if (ppt->y > rc.bottom)
  137. {
  138. if (CanScroll(hwnd, SB_VERT, TRUE))
  139. dwDSD |= DSD_DOWN;
  140. }
  141. }
  142. }
  143. return dwDSD;
  144. }
  145. #define SCROLL_FREQUENCY (GetDoubleClickTime()/4) // 1 line scroll every 1/4 second
  146. #define MIN_SCROLL_VELOCITY 20 // scaled mouse velocity
  147. #define DAD_ShowDragImage(f) // BUGBUG
  148. BOOL DAD_AutoScroll(HWND hwnd, AUTO_SCROLL_DATA *pad, const POINT *pptNow)
  149. {
  150. // first time we've been called, init our state
  151. int v;
  152. DWORD dwTimeNow = GetTickCount();
  153. DWORD dwDSD = DAD_DragScrollDirection(hwnd, pptNow);
  154. if (!_AddTimeSample(pad, pptNow, dwTimeNow))
  155. return dwDSD;
  156. v = _CurrentVelocity(pad);
  157. if (v <= MIN_SCROLL_VELOCITY)
  158. {
  159. // Nope, do some scrolling.
  160. if ((dwTimeNow - pad->dwLastScroll) < SCROLL_FREQUENCY)
  161. dwDSD = 0;
  162. if (dwDSD & (DSD_UP | DSD_DOWN | DSD_LEFT | DSD_RIGHT))
  163. DAD_ShowDragImage(FALSE);
  164. if (dwDSD & DSD_UP)
  165. {
  166. FORWARD_WM_VSCROLL(hwnd, NULL, SB_LINEUP, 1, SendMessage);
  167. }
  168. else if (dwDSD & DSD_DOWN)
  169. {
  170. FORWARD_WM_VSCROLL(hwnd, NULL, SB_LINEDOWN, 1, SendMessage);
  171. }
  172. if (dwDSD & DSD_LEFT)
  173. {
  174. FORWARD_WM_HSCROLL(hwnd, NULL, SB_LINEUP, 1, SendMessage);
  175. }
  176. else if (dwDSD & DSD_RIGHT)
  177. {
  178. FORWARD_WM_HSCROLL(hwnd, NULL, SB_LINEDOWN, 1, SendMessage);
  179. }
  180. DAD_ShowDragImage(TRUE);
  181. if (dwDSD)
  182. {
  183. DebugMsg(DM_TRACE, "v=%d", v);
  184. pad->dwLastScroll = dwTimeNow;
  185. }
  186. }
  187. return dwDSD; // bits set if in scroll region
  188. }