Leaked source code of windows server 2003
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.

741 lines
18 KiB

  1. //----------------------------------------------------------
  2. //
  3. // BUGBUG: make sure this stuff really works with the DWORD
  4. // ranges
  5. //
  6. //----------------------------------------------------------
  7. #include "ctlspriv.h"
  8. #include "tracki.h"
  9. #include "muldiv32.h"
  10. #define THUMBSLOP 2
  11. #define TICKHEIGHT 2
  12. #define ABS(X) (X >= 0) ? X : -X
  13. #define BOUND(x,low,high) max(min(x, high),low)
  14. char aszTrackbarClassName[] = TRACKBAR_CLASS;
  15. LPARAM FAR CALLBACK _loadds TrackBarWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
  16. //
  17. // convert a logical scroll-bar position to a physical pixel position
  18. //
  19. static int NEAR PASCAL TBLogToPhys(PTrackBar tb, DWORD dwPos)
  20. {
  21. if (tb->lLogMax == tb->lLogMin)
  22. return tb->rc.left;
  23. return (WORD)MulDiv32(dwPos - tb->lLogMin, tb->iSizePhys - 1,
  24. tb->lLogMax - tb->lLogMin) + tb->rc.left;
  25. }
  26. static LONG NEAR PASCAL TBPhysToLog(PTrackBar tb, int iPos)
  27. {
  28. if (tb->iSizePhys <= 1)
  29. return tb->lLogMin;
  30. if (iPos <= tb->rc.left)
  31. return tb->lLogMin;
  32. if (iPos >= tb->rc.right)
  33. return tb->lLogMax;
  34. return MulDiv32(iPos - tb->rc.left, tb->lLogMax - tb->lLogMin,
  35. tb->iSizePhys - 1) + tb->lLogMin;
  36. }
  37. /*
  38. Initialize the trackbar code.
  39. */
  40. BOOL FAR PASCAL InitTrackBar(HINSTANCE hInstance)
  41. {
  42. WNDCLASS wc;
  43. if (!GetClassInfo(hInstance, aszTrackbarClassName, &wc)) {
  44. // See if we must register a window class
  45. wc.lpszClassName = aszTrackbarClassName;
  46. wc.lpfnWndProc = TrackBarWndProc;
  47. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  48. wc.hIcon = NULL;
  49. wc.lpszMenuName = NULL;
  50. wc.hbrBackground = (HBRUSH)(NULL);
  51. wc.hInstance = hInstance;
  52. wc.style = CS_GLOBALCLASS | CS_DBLCLKS;
  53. wc.cbClsExtra = 0;
  54. wc.cbWndExtra = EXTRA_TB_BYTES;
  55. if (!RegisterClass(&wc))
  56. return FALSE;
  57. }
  58. return TRUE;
  59. }
  60. static void NEAR PASCAL PatRect(HDC hdc,int x,int y,int dx,int dy)
  61. {
  62. RECT rc;
  63. rc.left = x;
  64. rc.top = y;
  65. rc.right = x + dx;
  66. rc.bottom = y + dy;
  67. ExtTextOut(hdc,0,0,ETO_OPAQUE,&rc,NULL,0,NULL);
  68. }
  69. static void NEAR PASCAL DrawTic(PTrackBar tb, int x, int yTic)
  70. {
  71. SetBkColor(tb->hdc, GetSysColor(COLOR_BTNTEXT));
  72. PatRect(tb->hdc,(x),yTic,1,TICKHEIGHT);
  73. SetBkColor(tb->hdc, GetSysColor(COLOR_BTNHIGHLIGHT));
  74. PatRect(tb->hdc,(x)+1,yTic,1,TICKHEIGHT);
  75. }
  76. /* DrawTics() */
  77. /* There is always a tick at the beginning and end of the bar, but you can */
  78. /* add some more of your own with a TBM_SETTIC message. This draws them. */
  79. /* They are kept in an array whose handle is a window word. The first */
  80. /* element is the number of extra ticks, and then the positions. */
  81. static void NEAR PASCAL DrawTics(PTrackBar tb)
  82. {
  83. PDWORD pTics;
  84. int iPos;
  85. int yTic;
  86. int i;
  87. yTic = tb->rc.bottom + THUMBSLOP + 1;
  88. // !!! Not for MCIWnd
  89. // DrawTic(tb, tb->rc.left, yTic); // first
  90. // DrawTic(tb, tb->rc.right-1, yTic); // last
  91. // those inbetween
  92. pTics = tb->pTics;
  93. if (pTics) {
  94. for (i = 0; i < tb->nTics; ++i) {
  95. iPos = TBLogToPhys(tb,pTics[i]);
  96. DrawTic(tb, iPos, yTic);
  97. }
  98. }
  99. // draw the selection range (triangles)
  100. if ((tb->Flags & TBF_SELECTION) &&
  101. (tb->lSelStart <= tb->lSelEnd) && (tb->lSelEnd >= tb->lLogMin)) {
  102. SetBkColor(tb->hdc, GetSysColor(COLOR_BTNTEXT));
  103. iPos = TBLogToPhys(tb,tb->lSelStart);
  104. for (i=0; i < TICKHEIGHT; i++)
  105. PatRect(tb->hdc,iPos-i,yTic+i,1,TICKHEIGHT-i);
  106. iPos = TBLogToPhys(tb,tb->lSelEnd);
  107. for (i=0; i < TICKHEIGHT; i++)
  108. PatRect(tb->hdc,iPos+i,yTic+i,1,TICKHEIGHT-i);
  109. }
  110. // !!! Not for MCIWnd
  111. // line across the bottom
  112. // SetBkColor(tb->hdc, GetSysColor(COLOR_BTNTEXT));
  113. // PatRect(tb->hdc, tb->rc.left, yTic+TICKHEIGHT,tb->iSizePhys,1);
  114. //
  115. // SetBkColor(tb->hdc, GetSysColor(COLOR_BTNHIGHLIGHT));
  116. // PatRect(tb->hdc, tb->rc.left, yTic+TICKHEIGHT+1,tb->iSizePhys,1);
  117. }
  118. /* This draws the track bar itself */
  119. static void NEAR PASCAL DrawChannel(PTrackBar tb)
  120. {
  121. HBRUSH hbrTemp;
  122. // draw the frame around the window
  123. SetBkColor(tb->hdc, GetSysColor(COLOR_WINDOWFRAME));
  124. PatRect(tb->hdc, tb->rc.left, tb->rc.top, tb->iSizePhys, 1);
  125. PatRect(tb->hdc, tb->rc.left, tb->rc.bottom-2, tb->iSizePhys, 1);
  126. PatRect(tb->hdc, tb->rc.left, tb->rc.top, 1, tb->rc.bottom-tb->rc.top-1);
  127. PatRect(tb->hdc, tb->rc.right-1, tb->rc.top, 1, tb->rc.bottom-tb->rc.top-1);
  128. SetBkColor(tb->hdc, GetSysColor(COLOR_BTNHIGHLIGHT));
  129. PatRect(tb->hdc, tb->rc.left, tb->rc.bottom-1, tb->iSizePhys, 1);
  130. SetBkColor(tb->hdc, GetSysColor(COLOR_BTNSHADOW));
  131. PatRect(tb->hdc, tb->rc.left+1, tb->rc.top + 1, tb->iSizePhys-2,1);
  132. // draw the background in dither gray
  133. hbrTemp = SelectObject(tb->hdc, hbrDither);
  134. if (hbrTemp) {
  135. PatBlt(tb->hdc, tb->rc.left+1, tb->rc.top + 2,
  136. tb->iSizePhys-2, tb->rc.bottom-tb->rc.top-4, PATCOPY);
  137. SelectObject(tb->hdc, hbrTemp);
  138. }
  139. // now highlight the selection range
  140. if ((tb->Flags & TBF_SELECTION) &&
  141. (tb->lSelStart <= tb->lSelEnd) && (tb->lSelEnd > tb->lLogMin)) {
  142. int iStart, iEnd;
  143. iStart = TBLogToPhys(tb,tb->lSelStart);
  144. iEnd = TBLogToPhys(tb,tb->lSelEnd);
  145. SetBkColor(tb->hdc, GetSysColor(COLOR_BTNTEXT));
  146. PatRect(tb->hdc, iStart,tb->rc.top+1,1,tb->rc.bottom-tb->rc.top-2);
  147. PatRect(tb->hdc, iEnd, tb->rc.top+1,1,tb->rc.bottom-tb->rc.top-2);
  148. if (iStart + 2 <= iEnd) {
  149. SetBkColor(tb->hdc, GetSysColor(COLOR_BTNHIGHLIGHT));
  150. PatRect(tb->hdc, iStart+1, tb->rc.top+1, iEnd-iStart-1, tb->rc.bottom-tb->rc.top-3);
  151. }
  152. }
  153. }
  154. static void NEAR PASCAL MoveThumb(PTrackBar tb, LONG lPos)
  155. {
  156. InvalidateRect(tb->hwnd, &tb->Thumb, TRUE);
  157. tb->lLogPos = BOUND(lPos,tb->lLogMin,tb->lLogMax);
  158. tb->Thumb.left = TBLogToPhys(tb, tb->lLogPos) - tb->wThumbWidth/2;
  159. tb->Thumb.right = tb->Thumb.left + tb->wThumbWidth;
  160. tb->Thumb.top = tb->rc.top - THUMBSLOP;
  161. tb->Thumb.bottom = tb->rc.bottom + THUMBSLOP;
  162. InvalidateRect(tb->hwnd, &tb->Thumb, TRUE);
  163. UpdateWindow(tb->hwnd);
  164. }
  165. static void NEAR PASCAL DrawThumb(PTrackBar tb)
  166. {
  167. HBITMAP hbmT;
  168. HDC hdcT;
  169. int x;
  170. hdcT = CreateCompatibleDC(tb->hdc);
  171. if( (tb->Cmd == TB_THUMBTRACK) || !IsWindowEnabled(tb->hwnd) )
  172. x = tb->wThumbWidth;
  173. else
  174. x = 0;
  175. hbmT = SelectObject(hdcT, hbmThumb);
  176. if (hbmT) {
  177. BitBlt(tb->hdc,tb->Thumb.left, tb->rc.top-THUMBSLOP,
  178. tb->wThumbWidth, tb->wThumbHeight, hdcT, x + 2*tb->wThumbWidth, 0, SRCAND);
  179. BitBlt(tb->hdc,tb->Thumb.left, tb->rc.top-THUMBSLOP,
  180. tb->wThumbWidth, tb->wThumbHeight, hdcT, x, 0, SRCPAINT);
  181. }
  182. SelectObject(hdcT, hbmT);
  183. DeleteDC(hdcT);
  184. }
  185. /* SetTBCaretPos() */
  186. /* Make the caret flash in the middle of the thumb when it has the focus */
  187. static void NEAR PASCAL SetTBCaretPos(PTrackBar tb)
  188. {
  189. // We only get the caret if we have the focus.
  190. if (tb->hwnd == GetFocus())
  191. SetCaretPos(tb->Thumb.left + tb->wThumbWidth / 2,
  192. tb->Thumb.top + THUMBSLOP);
  193. }
  194. static void NEAR PASCAL DoAutoTics(PTrackBar tb)
  195. {
  196. LONG NEAR *pl;
  197. LONG l;
  198. if (!(GetWindowLong(tb->hwnd, GWL_STYLE) & TBS_AUTOTICKS))
  199. return;
  200. tb->nTics = (int)(tb->lLogMax - tb->lLogMin - 1);
  201. // If our length is zero, we'll blow!
  202. if (tb->nTics <= 0) {
  203. tb ->nTics = 0;
  204. return;
  205. }
  206. if (tb->pTics)
  207. LocalFree((HANDLE)tb->pTics);
  208. tb->pTics = (DWORD NEAR *)LocalAlloc(LPTR, sizeof(DWORD) * tb->nTics);
  209. if (!tb->pTics) {
  210. tb->nTics = 0;
  211. return;
  212. }
  213. for (pl = (LONG NEAR *)tb->pTics, l = tb->lLogMin + 1; l < tb->lLogMax; l++)
  214. *pl++ = l;
  215. }
  216. LPARAM FAR CALLBACK _loadds TrackBarWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  217. {
  218. PTrackBar tb;
  219. PAINTSTRUCT ps;
  220. BITMAP bm;
  221. HANDLE h;
  222. HDC hdc;
  223. HBRUSH hbr;
  224. RECT rc;
  225. tb = TrackBarLock(hwnd);
  226. switch (message) {
  227. case WM_CREATE:
  228. if (!CreateDitherBrush(FALSE))
  229. return -1;
  230. // Get us our window structure.
  231. TrackBarCreate(hwnd);
  232. tb = TrackBarLock(hwnd);
  233. tb->hwnd = hwnd;
  234. tb->Cmd = (WORD)-1;
  235. /* load the 2 thumb bitmaps (pressed and released) */
  236. CreateThumb(FALSE);
  237. GetObject(hbmThumb, sizeof(bm), &bm);
  238. // bitmap has up and down thumb and up&down masks
  239. tb->wThumbWidth = (WORD)(bm.bmWidth/4);
  240. tb->wThumbHeight = (WORD)bm.bmHeight;
  241. // all lLog fields are zero inited by
  242. // the LocalAlloc();
  243. // fall through to WM_SIZE
  244. case WM_SIZE:
  245. GetClientRect(hwnd, &tb->rc);
  246. tb->rc.bottom = tb->rc.top + tb->wThumbHeight - THUMBSLOP;
  247. tb->rc.top += THUMBSLOP;
  248. tb->rc.left += tb->wThumbWidth/2;
  249. tb->rc.right -= tb->wThumbWidth/2;
  250. // Figure out how much room we have to move the thumb in
  251. //!!! -2
  252. tb->iSizePhys = tb->rc.right - tb->rc.left;
  253. // Elevator isn't there if there's no room.
  254. if (tb->iSizePhys == 0) {
  255. // Lost our thumb.
  256. tb->Flags |= TBF_NOTHUMB;
  257. tb->iSizePhys = 1;
  258. } else {
  259. // Ah. We have a thumb.
  260. tb->Flags &= ~TBF_NOTHUMB;
  261. }
  262. InvalidateRect(hwnd, NULL, TRUE);
  263. MoveThumb(tb, tb->lLogPos);
  264. break;
  265. case WM_DESTROY:
  266. TrackBarDestroy(hwnd);
  267. FreeDitherBrush();
  268. DestroyThumb();
  269. break;
  270. case WM_SETFOCUS:
  271. // We gots the focus. We need a caret.
  272. CreateCaret(hwnd, (HBITMAP)1,
  273. 3, tb->wThumbHeight - 2 * THUMBSLOP);
  274. SetTBCaretPos(tb);
  275. ShowCaret(hwnd);
  276. break;
  277. case WM_KILLFOCUS:
  278. DestroyCaret();
  279. break;
  280. case WM_ERASEBKGND:
  281. hdc = (HDC) wParam;
  282. hbr = (HBRUSH)(WORD)SendMessage(GetParent(hwnd),
  283. WM_CTLCOLOR, (WORD) hdc,
  284. MAKELONG(hwnd, CTLCOLOR_STATIC));
  285. if (hbr) {
  286. GetClientRect(hwnd, &rc);
  287. FillRect(hdc, &rc, hbr);
  288. return(FALSE);
  289. }
  290. return(TRUE);
  291. break;
  292. case WM_ENABLE:
  293. InvalidateRect(hwnd, NULL, FALSE);
  294. break;
  295. case WM_PAINT:
  296. if (wParam == NULL)
  297. tb->hdc = BeginPaint(hwnd, &ps);
  298. else
  299. tb->hdc = (HDC)wParam;
  300. // Update the dither brush if necessary.
  301. CheckSysColors();
  302. DrawTics(tb);
  303. DrawThumb(tb);
  304. ExcludeClipRect(tb->hdc, tb->Thumb.left, tb->Thumb.top,
  305. tb->Thumb.right, tb->Thumb.bottom);
  306. DrawChannel(tb);
  307. SetTBCaretPos(tb);
  308. if (wParam == NULL)
  309. EndPaint(hwnd, &ps);
  310. tb->hdc = NULL;
  311. break;
  312. case WM_GETDLGCODE:
  313. return DLGC_WANTARROWS;
  314. break;
  315. case WM_LBUTTONDOWN:
  316. /* Give ourselves focus */
  317. // !!! MCIWnd wants to keep focus
  318. // SetFocus(hwnd);
  319. TBTrackInit(tb, lParam);
  320. break;
  321. case WM_LBUTTONUP:
  322. // We're through doing whatever we were doing with the
  323. // button down.
  324. TBTrackEnd(tb, lParam);
  325. break;
  326. case WM_TIMER:
  327. // The only way we get a timer message is if we're
  328. // autotracking.
  329. lParam = GetMessagePos();
  330. ScreenToClient(tb->hwnd, (LPPOINT)&lParam);
  331. // fall through to WM_MOUSEMOVE
  332. case WM_MOUSEMOVE:
  333. // We only care that the mouse is moving if we're
  334. // tracking the bloody thing.
  335. if (tb->Cmd != (WORD)-1) {
  336. if (GetCapture() != tb->hwnd) {
  337. TBTrackEnd(tb, lParam);
  338. return 0L;
  339. }
  340. TBTrack(tb, lParam);
  341. }
  342. return 0L;
  343. case WM_KEYUP:
  344. // If key was any of the keyboard accelerators, send end
  345. // track message when user up clicks on keyboard
  346. switch (wParam) {
  347. case VK_HOME:
  348. case VK_END:
  349. case VK_PRIOR:
  350. case VK_NEXT:
  351. case VK_LEFT:
  352. case VK_UP:
  353. case VK_RIGHT:
  354. case VK_DOWN:
  355. DoTrack(tb, TB_ENDTRACK, 0);
  356. break;
  357. default:
  358. break;
  359. }
  360. break;
  361. case WM_KEYDOWN:
  362. switch (wParam) {
  363. case VK_HOME:
  364. wParam = TB_TOP;
  365. goto KeyTrack;
  366. case VK_END:
  367. wParam = TB_BOTTOM;
  368. goto KeyTrack;
  369. case VK_PRIOR:
  370. wParam = TB_PAGEUP;
  371. goto KeyTrack;
  372. case VK_NEXT:
  373. wParam = TB_PAGEDOWN;
  374. goto KeyTrack;
  375. case VK_LEFT:
  376. case VK_UP:
  377. wParam = TB_LINEUP;
  378. goto KeyTrack;
  379. case VK_RIGHT:
  380. case VK_DOWN:
  381. wParam = TB_LINEDOWN;
  382. KeyTrack:
  383. DoTrack(tb, wParam, 0);
  384. break;
  385. default:
  386. break;
  387. }
  388. break;
  389. case TBM_GETPOS:
  390. return tb->lLogPos;
  391. case TBM_GETSELSTART:
  392. return tb->lSelStart;
  393. case TBM_GETSELEND:
  394. return tb->lSelEnd;
  395. case TBM_GETRANGEMIN:
  396. return tb->lLogMin;
  397. case TBM_GETRANGEMAX:
  398. return tb->lLogMax;
  399. case TBM_GETPTICS:
  400. return (LONG)(LPVOID)tb->pTics;
  401. case TBM_CLEARSEL:
  402. tb->Flags &= ~TBF_SELECTION;
  403. tb->lSelStart = -1;
  404. tb->lSelEnd = -1;
  405. goto RedrawTB;
  406. case TBM_CLEARTICS:
  407. if (tb->pTics)
  408. LocalFree((HLOCAL)tb->pTics);
  409. tb->nTics = 0;
  410. tb->pTics = NULL;
  411. goto RedrawTB;
  412. case TBM_GETTIC:
  413. if (tb->pTics == NULL || (int)wParam >= tb->nTics)
  414. return -1L;
  415. return tb->pTics[wParam];
  416. case TBM_GETTICPOS:
  417. if (tb->pTics == NULL || (int)wParam >= tb->nTics)
  418. return -1L;
  419. return TBLogToPhys(tb,tb->pTics[wParam]);
  420. case TBM_GETNUMTICS:
  421. return tb->nTics;
  422. case TBM_SETTIC:
  423. /* not a valid position */
  424. if (lParam < 0)
  425. break;
  426. if (tb->pTics)
  427. h = LocalReAlloc((HLOCAL)tb->pTics,
  428. sizeof(DWORD) * (WORD)(tb->nTics + 1),
  429. LMEM_MOVEABLE | LMEM_ZEROINIT);
  430. else
  431. h = LocalAlloc(LPTR, sizeof(DWORD));
  432. if (h)
  433. tb->pTics = (PDWORD)h;
  434. else
  435. return (LONG)FALSE;
  436. tb->pTics[tb->nTics++] = (DWORD)lParam;
  437. InvalidateRect(hwnd, NULL, TRUE);
  438. return (LONG)TRUE;
  439. break;
  440. case TBM_SETPOS:
  441. /* Only redraw if it will physically move */
  442. if (wParam && TBLogToPhys(tb, lParam) !=
  443. TBLogToPhys(tb, tb->lLogPos))
  444. MoveThumb(tb, lParam);
  445. else
  446. tb->lLogPos = BOUND(lParam,tb->lLogMin,tb->lLogMax);
  447. break;
  448. case TBM_SETSEL:
  449. tb->Flags |= TBF_SELECTION;
  450. tb->lSelStart = LOWORD(lParam);
  451. tb->lSelEnd = HIWORD(lParam);
  452. if (tb->lSelEnd < tb->lSelStart)
  453. tb->lSelEnd = tb->lSelStart;
  454. goto RedrawTB;
  455. case TBM_SETSELSTART:
  456. tb->Flags |= TBF_SELECTION;
  457. tb->lSelStart = lParam;
  458. if (tb->lSelEnd < tb->lSelStart || tb->lSelEnd == -1)
  459. tb->lSelEnd = tb->lSelStart;
  460. goto RedrawTB;
  461. case TBM_SETSELEND:
  462. tb->Flags |= TBF_SELECTION;
  463. tb->lSelEnd = lParam;
  464. if (tb->lSelStart > tb->lSelEnd || tb->lSelStart == -1)
  465. tb->lSelStart = tb->lSelEnd;
  466. goto RedrawTB;
  467. case TBM_SETRANGE:
  468. tb->lLogMin = LOWORD(lParam);
  469. tb->lLogMax = HIWORD(lParam);
  470. DoAutoTics(tb);
  471. goto RedrawTB;
  472. case TBM_SETRANGEMIN:
  473. tb->lLogMin = (DWORD)lParam;
  474. goto RedrawTB;
  475. case TBM_SETRANGEMAX:
  476. tb->lLogMax = (DWORD)lParam;
  477. RedrawTB:
  478. tb->lLogPos = BOUND(tb->lLogPos, tb->lLogMin,tb->lLogMax);
  479. /* Only redraw if flag says so */
  480. if (wParam) {
  481. InvalidateRect(hwnd, NULL, TRUE);
  482. MoveThumb(tb, tb->lLogPos);
  483. }
  484. break;
  485. }
  486. return DefWindowProc(hwnd, message, wParam, lParam);
  487. }
  488. /* DoTrack() */
  489. static void NEAR PASCAL DoTrack(PTrackBar tb, int cmd, DWORD dwPos)
  490. {
  491. // note: we only send back a WORD worth of the position.
  492. SendMessage(GetParent(tb->hwnd), WM_HSCROLL, cmd,
  493. MAKELONG(LOWORD(dwPos), tb->hwnd));
  494. }
  495. /* WTrackType() */
  496. static WORD NEAR PASCAL WTrackType(PTrackBar tb, LONG lParam)
  497. {
  498. POINT pt;
  499. #ifdef WIN32
  500. LONG2POINT(lParam, pt);
  501. #else
  502. pt = MAKEPOINT(lParam);
  503. #endif
  504. if (tb->Flags & TBF_NOTHUMB) // If no thumb, just leave.
  505. return 0;
  506. if (PtInRect(&tb->Thumb, pt))
  507. return TB_THUMBTRACK;
  508. if (!PtInRect(&tb->rc, pt))
  509. return 0;
  510. if (pt.x >= tb->Thumb.left)
  511. return TB_PAGEDOWN;
  512. else
  513. return TB_PAGEUP;
  514. }
  515. /* TBTrackInit() */
  516. static void NEAR PASCAL TBTrackInit(PTrackBar tb, LONG lParam)
  517. {
  518. WORD wCmd;
  519. if (tb->Flags & TBF_NOTHUMB) // No thumb: just leave.
  520. return;
  521. wCmd = WTrackType(tb, lParam);
  522. if (!wCmd)
  523. return;
  524. HideCaret(tb->hwnd);
  525. SetCapture(tb->hwnd);
  526. tb->Cmd = wCmd;
  527. tb->dwDragPos = (DWORD)-1;
  528. // Set up for auto-track (if needed).
  529. if (wCmd != TB_THUMBTRACK) {
  530. // Set our timer up
  531. tb->Timer = (UINT)SetTimer(tb->hwnd, TIMER_ID, REPEATTIME, NULL);
  532. }
  533. TBTrack(tb, lParam);
  534. }
  535. /* EndTrack() */
  536. static void near PASCAL TBTrackEnd(PTrackBar tb, long lParam)
  537. {
  538. lParam = lParam; // Just reference this variable
  539. // If we lose mouse capture we need to call this
  540. // if (GetCapture() != tb->hwnd)
  541. // return;
  542. // Let the mouse go.
  543. ReleaseCapture();
  544. // Decide how we're ending this thing.
  545. if (tb->Cmd == TB_THUMBTRACK)
  546. DoTrack(tb, TB_THUMBPOSITION, tb->dwDragPos);
  547. if (tb->Timer)
  548. KillTimer(tb->hwnd, TIMER_ID);
  549. tb->Timer = 0;
  550. // Always send TB_ENDTRACK message.
  551. DoTrack(tb, TB_ENDTRACK, 0);
  552. // Give the caret back.
  553. ShowCaret(tb->hwnd);
  554. // Nothing going on.
  555. tb->Cmd = (WORD)-1;
  556. MoveThumb(tb, tb->lLogPos);
  557. }
  558. static void NEAR PASCAL TBTrack(PTrackBar tb, LONG lParam)
  559. {
  560. DWORD dwPos;
  561. // See if we're tracking the thumb
  562. if (tb->Cmd == TB_THUMBTRACK) {
  563. dwPos = TBPhysToLog(tb, LOWORD(lParam));
  564. // Tentative position changed -- notify the guy.
  565. if (dwPos != tb->dwDragPos) {
  566. tb->dwDragPos = dwPos;
  567. MoveThumb(tb, dwPos);
  568. DoTrack(tb, TB_THUMBTRACK, dwPos);
  569. }
  570. }
  571. else {
  572. if (tb->Cmd != WTrackType(tb, lParam))
  573. return;
  574. DoTrack(tb, tb->Cmd, 0);
  575. }
  576. }