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.

359 lines
14 KiB

  1. /* Revision history:
  2. March 92 Ported to 16/32 common code by Laurie Griffiths (LaurieGr)
  3. */
  4. /*--------------------------------------------------------------------------*/
  5. #include <windows.h>
  6. #include <port1632.h>
  7. #include "hack.h"
  8. /*--------------------------------------------------------------------------*/
  9. #define SZCODE char _based(_segname("_CODE"))
  10. #define TIMER_ID 1
  11. #define MS_SCROLLTIME 150
  12. /*--------------------------------------------------------------------------*/
  13. static HWND hwndParent;
  14. static RECT rcUp;
  15. static RECT rcDown;
  16. static SZCODE szArrowClass[] = "cpArrow";
  17. static UINT uScroll; /* gee, thanks for the helpful comment. Laurie. */
  18. static UINT uTimer;
  19. static BOOL fKeyDown;
  20. /*
  21. * fDownButton
  22. *
  23. * TRUE if we are dealing with the 'down arrow'. FALSE if we are dealing
  24. * with the 'up arrow'.
  25. */
  26. typedef enum tagArrowDirection {
  27. enumArrowUp,
  28. enumArrowDown
  29. } ARROWDIRECTION;
  30. static ARROWDIRECTION ArrowType;
  31. /*
  32. * fButton
  33. *
  34. * TRUE if the user pressed the left button down on the arrow window,
  35. * as long as cursor is still over that window and the left button
  36. * remains down.
  37. */
  38. static BOOL fButton;
  39. /*
  40. * fRealButton
  41. *
  42. * TRUE if the user pressed the left button down on the arrow window,
  43. * regardless of whether or not the cursor is still over the window, as
  44. * long as the left button remains down.
  45. */
  46. static BOOL fRealButton;
  47. /*--------------------------------------------------------------------------*/
  48. static void PASCAL NEAR KeyDown(
  49. HWND hwnd,
  50. UINT uKey)
  51. {
  52. DWORD dCoordinates;
  53. if (!fKeyDown && ((uKey == VK_DOWN) || (uKey == VK_UP))) {
  54. fKeyDown = TRUE;
  55. hwndParent = GetParent(hwnd);
  56. GetClientRect(hwnd, &rcUp);
  57. rcUp.bottom = (rcUp.top + rcUp.bottom) / 2 - 1;
  58. rcDown.top = rcUp.bottom + 1;
  59. if (uKey == VK_DOWN)
  60. dCoordinates = MAKELONG(0, rcDown.top);
  61. else
  62. dCoordinates = MAKELONG(0, rcUp.top);
  63. SendMessage(hwnd, WM_LBUTTONDOWN, (WPARAM)0, (LPARAM)dCoordinates);
  64. }
  65. }
  66. /*--------------------------------------------------------------------------*/
  67. static void PASCAL NEAR KeyUp(
  68. HWND hwnd,
  69. UINT uKey)
  70. {
  71. if (fKeyDown && ((uKey == VK_DOWN) || (uKey == VK_UP))) {
  72. fKeyDown = FALSE;
  73. SendMessage(hwnd, WM_LBUTTONUP, (WPARAM)0, (LPARAM)0);
  74. }
  75. }
  76. /*--------------------------------------------------------------------------*/
  77. static void PASCAL NEAR LButtonDown(
  78. HWND hwnd,
  79. int iCoord)
  80. {
  81. if (!fRealButton) {
  82. fButton = TRUE;
  83. fRealButton = TRUE;
  84. SetCapture(hwnd);
  85. hwndParent = GetParent(hwnd);
  86. GetClientRect(hwnd, &rcUp);
  87. CopyRect(&rcDown, &rcUp);
  88. rcUp.bottom = (rcUp.top + rcUp.bottom) / 2 - 1;
  89. rcDown.top = rcUp.bottom + 1;
  90. uScroll = (iCoord >= rcDown.top) ? SB_LINEDOWN : SB_LINEUP;
  91. ArrowType = (uScroll == SB_LINEDOWN) ? enumArrowDown : enumArrowUp;
  92. #if defined(WIN16)
  93. SendMessage(hwndParent, WM_VSCROLL, (WPARAM)uScroll, MAKELPARAM(GetWindowWord(hwnd, GWW_ID), hwnd));
  94. #else
  95. /* The NT version of WM_VSCROLL wants the scroll position.
  96. (Actually the book is vague, maybe it only wants it for
  97. SB_THUMBPOSITION and SB_THUMBTRACK)
  98. However we may be able to fudge it anyway.
  99. So long as the message is sent to a WNDPROC ported from
  100. DOS it will not be looking for the scroll position in
  101. other cases. Neither book (DOS or NT) mentions stuffing
  102. the ID in, but the line above does so.
  103. Fortunately, nobody looks at it!
  104. Whenever it stuffs something into the LOWORD(lParam)
  105. on DOS we use HIWORD(wParam) on NT
  106. */
  107. SendMessage( hwndParent
  108. , WM_VSCROLL
  109. , (WPARAM)uScroll
  110. , (LPARAM)hwnd
  111. );
  112. #endif //WIN16
  113. uTimer = (UINT)SetTimer(hwnd, TIMER_ID, MS_SCROLLTIME, NULL);
  114. if (ArrowType == enumArrowDown)
  115. InvalidateRect(hwnd, &rcDown, TRUE);
  116. else
  117. InvalidateRect(hwnd, &rcUp, TRUE);
  118. }
  119. }
  120. /*--------------------------------------------------------------------------*/
  121. static void PASCAL NEAR MouseMove(
  122. HWND hwnd,
  123. POINT pt)
  124. {
  125. // if they didn't left button down on us originally, ignore it;
  126. if (fRealButton) {
  127. BOOL fGray;
  128. fGray = (((ArrowType == enumArrowDown) && PtInRect(&rcDown, pt)) || ((ArrowType == enumArrowUp) && PtInRect(&rcUp, pt)));
  129. // either not over the arrow window anymore, just came on top of window;
  130. if ((fButton && !fGray) || (!fButton && fGray)) {
  131. fButton = !fButton;
  132. InvalidateRect(hwnd, (ArrowType == enumArrowDown) ? &rcDown : &rcUp, TRUE);
  133. }
  134. }
  135. }
  136. /*--------------------------------------------------------------------------*/
  137. static void PASCAL NEAR LButtonUp(
  138. HWND hwnd)
  139. {
  140. if (fButton) {
  141. ReleaseCapture();
  142. #if defined(WIN16)
  143. SendMessage(hwndParent, WM_VSCROLL, (WPARAM)SB_ENDSCROLL, MAKELPARAM(GetWindowWord(hwnd, GWW_ID), hwnd));
  144. #else
  145. /* See comments about WM_VSCROLL earlier in file */
  146. SendMessage( hwndParent
  147. , WM_VSCROLL
  148. , (WPARAM)SB_ENDSCROLL
  149. , (LPARAM)hwnd
  150. );
  151. #endif //WIN16
  152. fButton = FALSE;
  153. if (ArrowType == enumArrowDown)
  154. InvalidateRect(hwnd, &rcDown, TRUE);
  155. else
  156. InvalidateRect(hwnd, &rcUp, TRUE);
  157. }
  158. fRealButton = FALSE;
  159. if (uTimer) {
  160. KillTimer(hwnd, uTimer);
  161. uTimer = 0;
  162. ReleaseCapture();
  163. }
  164. }
  165. /*--------------------------------------------------------------------------*/
  166. static void PASCAL NEAR Paint(
  167. HWND hwnd)
  168. {
  169. PAINTSTRUCT ps;
  170. BeginPaint(hwnd, &ps);
  171. if (IsWindowVisible(hwnd)) {
  172. RECT rcArrow;
  173. RECT rcHalf;
  174. UINT uMiddle;
  175. HBRUSH hbrOld;
  176. int iLoop;
  177. BOOL fCurrentButtonDown;
  178. HPEN hpenOld;
  179. GetClientRect(hwnd, &rcArrow);
  180. FrameRect(ps.hdc, &rcArrow, (HBRUSH)GetStockObject(BLACK_BRUSH));
  181. InflateRect(&rcArrow, -1, -1);
  182. // Create the barrier between the two buttons...;
  183. uMiddle = rcArrow.top + (rcArrow.bottom - rcArrow.top) / 2 + 1;
  184. hbrOld = (HBRUSH)SelectObject(ps.hdc, (HGDIOBJ)CreateSolidBrush(COLOR_WINDOWFRAME));
  185. PatBlt(ps.hdc, 0, rcArrow.bottom / 2 - 1, rcArrow.right, 2, PATCOPY);
  186. DeleteObject(SelectObject(ps.hdc, (HGDIOBJ)hbrOld));
  187. // Draw the shadows and the face of the button...;
  188. for (iLoop = enumArrowUp; iLoop <= enumArrowDown; iLoop++) {
  189. POINT ptArrow[3];
  190. DWORD dwColor;
  191. fCurrentButtonDown = (fButton && (iLoop == ArrowType));
  192. // get the rectangle for the button half we're dealing with;
  193. rcHalf.top = (iLoop == enumArrowDown) ? uMiddle : rcArrow.top;
  194. rcHalf.bottom = (iLoop == enumArrowDown) ? rcArrow.bottom : uMiddle - 2;
  195. rcHalf.right = rcArrow.right;
  196. rcHalf.left = rcArrow.left;
  197. // draw the highlight lines;
  198. if (fCurrentButtonDown)
  199. dwColor = GetSysColor(COLOR_BTNSHADOW);
  200. else
  201. dwColor = RGB(255, 255, 255);
  202. hpenOld = SelectObject(ps.hdc, (HGDIOBJ)CreatePen(PS_SOLID, 1, dwColor));
  203. MMoveTo(ps.hdc, rcHalf.right - 1, rcHalf.top);
  204. LineTo(ps.hdc, rcHalf.left, rcHalf.top);
  205. LineTo(ps.hdc, rcHalf.left, rcHalf.bottom - 1 + fCurrentButtonDown);
  206. DeleteObject(SelectObject(ps.hdc, (HGDIOBJ)hpenOld));
  207. if (!fCurrentButtonDown) {
  208. // draw the shadow lines;
  209. hpenOld = SelectObject(ps.hdc, (HGDIOBJ)CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW)));
  210. MMoveTo(ps.hdc, rcHalf.right - 1, rcHalf.top);
  211. LineTo(ps.hdc, rcHalf.right - 1, rcHalf.bottom - 1);
  212. LineTo(ps.hdc, rcHalf.left - 1, rcHalf.bottom - 1);
  213. MMoveTo(ps.hdc, rcHalf.right - 2, rcHalf.top + 1);
  214. LineTo(ps.hdc, rcHalf.right - 2, rcHalf.bottom - 2);
  215. LineTo(ps.hdc, rcHalf.left, rcHalf.bottom - 2);
  216. DeleteObject(SelectObject(ps.hdc, hpenOld));
  217. }
  218. // calculate the arrow triangle coordinates;
  219. ptArrow[0].x = rcHalf.left + (rcHalf.right - rcHalf.left) / 2 + fCurrentButtonDown;
  220. ptArrow[0].y = rcHalf.top + 2 + fCurrentButtonDown;
  221. ptArrow[1].y = ptArrow[2].y = rcHalf.bottom - 4 + fCurrentButtonDown;
  222. if (ptArrow[0].y > ptArrow[1].y)
  223. ptArrow[1].y = ptArrow[2].y = ptArrow[0].y;
  224. ptArrow[1].x = ptArrow[0].x - (ptArrow[1].y - ptArrow[0].y);
  225. ptArrow[2].x = ptArrow[0].x + (ptArrow[1].y - ptArrow[0].y);
  226. // flip over if we're drawing bottom button;
  227. if (iLoop == enumArrowDown) {
  228. ptArrow[2].y = ptArrow[0].y;
  229. ptArrow[0].y = ptArrow[1].y;
  230. ptArrow[1].y = ptArrow[2].y;
  231. }
  232. if (IsWindowEnabled(hwnd))
  233. dwColor = GetSysColor(COLOR_BTNTEXT);
  234. else
  235. dwColor = GetSysColor(COLOR_GRAYTEXT);
  236. // draw the triangle;
  237. hbrOld = SelectObject(ps.hdc, (HGDIOBJ)CreateSolidBrush(dwColor));
  238. hpenOld = SelectObject(ps.hdc, CreatePen(PS_SOLID, 1, dwColor));
  239. Polygon(ps.hdc, ptArrow, 3);
  240. DeleteObject(SelectObject(ps.hdc, (HGDIOBJ)hbrOld));
  241. DeleteObject(SelectObject(ps.hdc, (HGDIOBJ)hpenOld));
  242. }
  243. }
  244. EndPaint(hwnd, &ps);
  245. }
  246. /*--------------------------------------------------------------------------*/
  247. LRESULT PASCAL FAR _loadds ArrowControlProc(
  248. HWND hwndArrow,
  249. UINT wMsg,
  250. WPARAM wParam,
  251. LPARAM lParam)
  252. {
  253. switch (wMsg) {
  254. case WM_SETFOCUS:
  255. case WM_KILLFOCUS:
  256. case WM_ENABLE:
  257. case WM_SYSCOLORCHANGE:
  258. InvalidateRect(hwndArrow, NULL, TRUE);
  259. UpdateWindow(hwndArrow);
  260. break;
  261. case WM_GETDLGCODE:
  262. return (LRESULT)DLGC_WANTARROWS; // | DLGC_UNDEFPUSHBUTTON;
  263. case WM_KEYDOWN:
  264. KeyDown(hwndArrow, (UINT)wParam);
  265. break;
  266. case WM_KEYUP:
  267. KeyUp(hwndArrow, (UINT)wParam);
  268. break;
  269. case WM_LBUTTONDOWN:
  270. LButtonDown(hwndArrow, HIWORD(lParam)); // y coord
  271. break;
  272. case WM_MOUSEMOVE:
  273. { POINT pt;
  274. LONG2POINT(lParam,pt);
  275. MouseMove(hwndArrow, pt);
  276. }
  277. break;
  278. case WM_LBUTTONUP:
  279. LButtonUp(hwndArrow);
  280. break;
  281. case WM_TIMER:
  282. if (fButton)
  283. #if defined(WIN16)
  284. SendMessage(hwndParent, WM_VSCROLL, (WPARAM)uScroll, MAKELPARAM(GetWindowWord(hwndArrow, GWW_ID), hwndArrow));
  285. #else
  286. /* See comments about WM_VSCROLL earlier in file */
  287. SendMessage( hwndParent
  288. , WM_VSCROLL
  289. , (WPARAM)uScroll
  290. , (LPARAM)hwndArrow
  291. );
  292. #endif //WIN16
  293. break;
  294. case WM_PAINT:
  295. Paint(hwndArrow);
  296. break;
  297. default:
  298. return DefWindowProc(hwndArrow, wMsg, wParam, lParam);
  299. }
  300. return (LRESULT)0;
  301. }
  302. /*--------------------------------------------------------------------------*/
  303. BOOL PASCAL FAR RegisterArrowClass(
  304. HINSTANCE hInstance)
  305. {
  306. WNDCLASS wcArrow;
  307. wcArrow.lpszClassName = szArrowClass;
  308. wcArrow.hInstance = hInstance;
  309. wcArrow.lpfnWndProc = ArrowControlProc;
  310. wcArrow.hCursor = LoadCursor(NULL, IDC_ARROW);
  311. wcArrow.hIcon = NULL;
  312. wcArrow.lpszMenuName = NULL;
  313. wcArrow.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
  314. wcArrow.style = CS_HREDRAW | CS_VREDRAW;
  315. wcArrow.cbClsExtra = 0;
  316. wcArrow.cbWndExtra = 0;
  317. return RegisterClass((LPWNDCLASS)&wcArrow);
  318. }
  319. /*--------------------------------------------------------------------------*/
  320. void PASCAL FAR UnregisterArrowClass(
  321. HINSTANCE hInstance)
  322. {
  323. UnregisterClass(szArrowClass, hInstance);
  324. }