Implemented inter-thread SendMessageCallback.
[wine] / dlls / comctl32 / trackbar.c
1 /*
2  * Trackbar control
3  *
4  * Copyright 1998, 1999 Eric Kohl
5  * Copyright 1998, 1999 Alex Priem
6  * Copyright 2002 Dimitrie O. Paun
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  *
22  * NOTE
23  * 
24  * This code was audited for completeness against the documented features
25  * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
26  * 
27  * Unless otherwise noted, we believe this code to be complete, as per
28  * the specification mentioned above.
29  * If you discover missing features, or bugs, please note them below.
30  * 
31  */
32
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include "winbase.h"
38 #include "commctrl.h"
39 #include "wine/debug.h"
40
41 #include "comctl32.h"
42
43 WINE_DEFAULT_DEBUG_CHANNEL(trackbar);
44
45 typedef struct
46 {
47     HWND hwndSelf;
48     LONG lRangeMin;
49     LONG lRangeMax;
50     LONG lLineSize;
51     LONG lPageSize;
52     LONG lSelMin;
53     LONG lSelMax;
54     LONG lPos;
55     UINT uThumbLen;
56     UINT uNumTics;
57     UINT uTicFreq;
58     HWND hwndNotify;
59     HWND hwndToolTip;
60     HWND hwndBuddyLA;
61     HWND hwndBuddyRB;
62     INT  fLocation;
63     INT  flags;
64     BOOL bUnicode;
65     BOOL bFocussed;
66     RECT rcChannel;
67     RECT rcSelection;
68     RECT rcThumb;
69     LPLONG tics;
70 } TRACKBAR_INFO;
71
72 #define TB_REFRESH_TIMER        1
73 #define TB_REFRESH_DELAY        500
74
75 #define TOOLTIP_OFFSET          2     /* distance from ctrl edge to tooltip */
76
77 /* Used by TRACKBAR_Refresh to find out which parts of the control
78    need to be recalculated */
79
80 #define TB_THUMBPOSCHANGED      1
81 #define TB_THUMBSIZECHANGED     2
82 #define TB_THUMBCHANGED         (TB_THUMBPOSCHANGED | TB_THUMBSIZECHANGED)
83 #define TB_SELECTIONCHANGED     4
84 #define TB_DRAG_MODE            8     /* we're dragging the slider */
85 #define TB_AUTO_PAGE_LEFT       16
86 #define TB_AUTO_PAGE_RIGHT      32
87 #define TB_AUTO_PAGE            (TB_AUTO_PAGE_LEFT | TB_AUTO_PAGE_RIGHT)
88
89 /* helper defines for TRACKBAR_DrawTic */
90 #define TIC_EDGE                0x20
91 #define TIC_SELECTIONMARKMAX    0x80
92 #define TIC_SELECTIONMARKMIN    0x100
93 #define TIC_SELECTIONMARK       (TIC_SELECTIONMARKMAX | TIC_SELECTIONMARKMIN)
94
95 static BOOL TRACKBAR_SendNotify (TRACKBAR_INFO *infoPtr, UINT code);
96
97 static inline int 
98 notify_customdraw(NMCUSTOMDRAW *pnmcd, int stage)
99 {
100     pnmcd->dwDrawStage = stage;
101     return SendMessageW (GetParent(pnmcd->hdr.hwndFrom), WM_NOTIFY, 
102                          pnmcd->hdr.idFrom, (LPARAM)pnmcd);
103 }
104
105 static void TRACKBAR_RecalculateTics (TRACKBAR_INFO *infoPtr)
106 {
107     int i, tic, nrTics;
108
109     if (infoPtr->uTicFreq && infoPtr->lRangeMax >= infoPtr->lRangeMin)
110         nrTics=(infoPtr->lRangeMax - infoPtr->lRangeMin)/infoPtr->uTicFreq;
111     else {
112         nrTics = 0;
113         COMCTL32_Free (infoPtr->tics);
114         infoPtr->tics = NULL;
115         infoPtr->uNumTics = 0;
116         return;
117     }
118
119     if (nrTics != infoPtr->uNumTics) {
120         infoPtr->tics=COMCTL32_ReAlloc (infoPtr->tics,
121                                         (nrTics+1)*sizeof (DWORD));
122         if (!infoPtr->tics) {
123             infoPtr->uNumTics = 0;
124             TRACKBAR_SendNotify(infoPtr, NM_OUTOFMEMORY);
125             return;
126         }
127         infoPtr->uNumTics = nrTics;
128     }
129
130     tic = infoPtr->lRangeMin + infoPtr->uTicFreq;
131     for (i = 0; i < nrTics; i++, tic += infoPtr->uTicFreq)
132         infoPtr->tics[i] = tic;
133 }
134
135 /* converts from physical (mouse) position to logical position
136    (in range of trackbar) */
137
138 static inline LONG
139 TRACKBAR_ConvertPlaceToPosition (TRACKBAR_INFO *infoPtr, int place,
140                                  int vertical)
141 {
142     double range, width, pos;
143
144     range = infoPtr->lRangeMax - infoPtr->lRangeMin;
145     if (vertical) {
146         width = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top;
147         pos = (range*(place - infoPtr->rcChannel.top)) / width;
148     } else {
149         width = infoPtr->rcChannel.right - infoPtr->rcChannel.left;
150         pos = (range*(place - infoPtr->rcChannel.left)) / width;
151     }
152     pos += infoPtr->lRangeMin;
153     if (pos > infoPtr->lRangeMax)
154         pos = infoPtr->lRangeMax;
155     else if (pos < infoPtr->lRangeMin)
156         pos = infoPtr->lRangeMin;
157
158     TRACE("%.2f\n", pos);
159     return (LONG)(pos + 0.5);
160 }
161
162
163 /* return: 0> prev, 0 none, >0 next */
164 static LONG
165 TRACKBAR_GetAutoPageDirection (TRACKBAR_INFO *infoPtr, POINT clickPoint)
166 {
167     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
168     RECT pageRect;
169
170     if (dwStyle & TBS_VERT) {
171         pageRect.top = infoPtr->rcChannel.top;
172         pageRect.bottom = infoPtr->rcChannel.bottom;
173         pageRect.left = infoPtr->rcThumb.left;
174         pageRect.right = infoPtr->rcThumb.right;
175     } else {
176         pageRect.top = infoPtr->rcThumb.top;
177         pageRect.bottom = infoPtr->rcThumb.bottom;
178         pageRect.left = infoPtr->rcChannel.left;
179         pageRect.right = infoPtr->rcChannel.right;
180     }
181
182
183     if (PtInRect(&pageRect, clickPoint))
184     {
185         int clickPlace = (dwStyle & TBS_VERT) ? clickPoint.y : clickPoint.x;
186
187         LONG clickPos = TRACKBAR_ConvertPlaceToPosition(infoPtr, clickPlace,
188                                                         dwStyle & TBS_VERT);
189         return clickPos - infoPtr->lPos;
190     }
191
192     return 0;
193 }
194
195 static void inline
196 TRACKBAR_PageUp (TRACKBAR_INFO *infoPtr)
197 {
198     if (infoPtr->lPos == infoPtr->lRangeMax) return;
199
200     infoPtr->lPos += infoPtr->lPageSize;
201     if (infoPtr->lPos > infoPtr->lRangeMax)
202         infoPtr->lPos = infoPtr->lRangeMax;
203     TRACKBAR_SendNotify (infoPtr, TB_PAGEUP);
204 }
205
206
207 static void inline
208 TRACKBAR_PageDown (TRACKBAR_INFO *infoPtr)
209 {
210     if (infoPtr->lPos == infoPtr->lRangeMin) return;
211
212     infoPtr->lPos -= infoPtr->lPageSize;
213     if (infoPtr->lPos < infoPtr->lRangeMin)
214         infoPtr->lPos = infoPtr->lRangeMin;
215     TRACKBAR_SendNotify (infoPtr, TB_PAGEDOWN);
216 }
217
218 static void
219 TRACKBAR_CalcChannel (TRACKBAR_INFO *infoPtr)
220 {
221     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
222     INT cyChannel, offsetthumb, offsetedge;
223     RECT lpRect, *channel = & infoPtr->rcChannel;
224
225     GetClientRect (infoPtr->hwndSelf, &lpRect);
226
227     offsetthumb = (int)(infoPtr->uThumbLen/4.5);
228     offsetedge  = offsetthumb + 3;
229     cyChannel   = (dwStyle & TBS_ENABLESELRANGE) ? (offsetthumb+1)*3 : 4;
230     if (dwStyle & TBS_VERT) {
231         channel->top    = lpRect.top + offsetedge;
232         channel->bottom = lpRect.bottom - offsetedge;
233         channel->left = lpRect.left + offsetthumb - cyChannel;
234         if (dwStyle & (TBS_BOTH | TBS_LEFT))
235             channel->left += (lpRect.right-lpRect.left-offsetthumb-cyChannel)/2;
236         channel->right = channel->left + cyChannel;
237     } else {
238         channel->left = lpRect.left + offsetedge;
239         channel->right = lpRect.right - offsetedge;
240         channel->top = lpRect.top + offsetedge;
241         if (dwStyle & (TBS_BOTH | TBS_TOP))
242             channel->top += (lpRect.bottom-lpRect.top-offsetedge-cyChannel)/2;
243         channel->bottom   = channel->top + cyChannel;
244     }
245 }
246
247 static void
248 TRACKBAR_CalcThumb (TRACKBAR_INFO *infoPtr, LONG lPos, RECT *thumb)
249 {
250     int range, width, height, thumbdepth, ticOffset = 5 + 2; /* 5 is length of tic, 2 is extra indent */
251     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
252     RECT lpRect;
253
254     range = infoPtr->lRangeMax - infoPtr->lRangeMin;
255     thumbdepth = ((int)(infoPtr->uThumbLen / 4.5)) + 2;
256
257     if (!range) range = 1;
258
259     GetClientRect(infoPtr->hwndSelf, &lpRect);
260     if (dwStyle & TBS_VERT)
261     {
262         height = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top;
263
264         if (dwStyle & (TBS_BOTH | TBS_LEFT))
265             thumb->left = (lpRect.right - lpRect.left - infoPtr->uThumbLen)/2 + ticOffset;
266         else
267             thumb->left = 2;
268         thumb->right = thumb->left + infoPtr->uThumbLen - (ticOffset * 2);
269         thumb->top = infoPtr->rcChannel.top +
270                      (height*(lPos - infoPtr->lRangeMin))/range -
271                      thumbdepth/2;
272         thumb->bottom = thumb->top + thumbdepth;
273     }
274     else
275     {
276         width = infoPtr->rcChannel.right - infoPtr->rcChannel.left;
277
278         thumb->left = infoPtr->rcChannel.left +
279                       (width*(lPos - infoPtr->lRangeMin))/range -
280                       thumbdepth/2;
281         thumb->right = thumb->left + thumbdepth;
282         if (dwStyle & (TBS_BOTH | TBS_TOP))
283             thumb->top = (lpRect.bottom - lpRect.top - infoPtr->uThumbLen)/2;
284         else
285             thumb->top = 2;
286         thumb->bottom = thumb->top + infoPtr->uThumbLen - 20; /* double the bottom padding for the ticks, chosen to resemble native control */
287     }
288 }
289
290 inline static void
291 TRACKBAR_UpdateThumb (TRACKBAR_INFO *infoPtr)
292 {
293     TRACKBAR_CalcThumb(infoPtr, infoPtr->lPos, &infoPtr->rcThumb);
294 }
295
296 static inline void
297 TRACKBAR_InvalidateAll(TRACKBAR_INFO * infoPtr)
298 {
299     InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
300 }
301
302 static void
303 TRACKBAR_InvalidateThumb (TRACKBAR_INFO *infoPtr, LONG thumbPos)
304 {
305     RECT rcThumb;
306
307     TRACKBAR_CalcThumb(infoPtr, thumbPos, &rcThumb);
308     InflateRect(&rcThumb, 1, 1);
309     InvalidateRect(infoPtr->hwndSelf, &rcThumb, FALSE);
310 }
311
312 static inline void
313 TRACKBAR_InvalidateThumbMove (TRACKBAR_INFO *infoPtr, LONG oldPos, LONG newPos)
314 {
315     TRACKBAR_InvalidateThumb (infoPtr, oldPos);
316     if (newPos != oldPos)
317         TRACKBAR_InvalidateThumb (infoPtr, newPos);
318 }
319
320 static BOOL inline
321 TRACKBAR_HasSelection (TRACKBAR_INFO *infoPtr)
322 {
323     return infoPtr->lSelMin != infoPtr->lSelMax;
324 }
325
326 static void
327 TRACKBAR_CalcSelection (TRACKBAR_INFO *infoPtr)
328 {
329     RECT *selection = &infoPtr->rcSelection;
330     int range = infoPtr->lRangeMax - infoPtr->lRangeMin;
331
332     if (range <= 0) {
333         SetRectEmpty (selection);
334     } else {
335         if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_VERT) {
336             int height = infoPtr->rcChannel.right - infoPtr->rcChannel.left;
337             selection->top    = infoPtr->rcChannel.top +
338                 (height*infoPtr->lSelMin)/range;
339             selection->bottom = infoPtr->rcChannel.top +
340                 (height*infoPtr->lSelMax)/range;
341             selection->left   = infoPtr->rcChannel.left + 3;
342             selection->right  = infoPtr->rcChannel.right - 3;
343         } else {
344             int width = infoPtr->rcChannel.right - infoPtr->rcChannel.left;
345             selection->left   = infoPtr->rcChannel.left +
346                 (width*infoPtr->lSelMin)/range;
347             selection->right  = infoPtr->rcChannel.left +
348                 (width*infoPtr->lSelMax)/range;
349             selection->top    = infoPtr->rcChannel.top + 3;
350             selection->bottom = infoPtr->rcChannel.bottom - 3;
351         }
352     }
353
354     TRACE("selection[left=%ld, top=%ld, right=%ld, bottom=%ld]\n",
355            selection->left, selection->top, selection->right, selection->bottom);
356 }
357
358 static BOOL
359 TRACKBAR_AutoPage (TRACKBAR_INFO *infoPtr, POINT clickPoint)
360 {
361     LONG dir = TRACKBAR_GetAutoPageDirection(infoPtr, clickPoint);
362     LONG prevPos = infoPtr->lPos;
363
364     TRACE("x=%ld, y=%ld, dir=%ld\n", clickPoint.x, clickPoint.y, dir);
365
366     if (dir > 0 && (infoPtr->flags & TB_AUTO_PAGE_RIGHT))
367         TRACKBAR_PageUp(infoPtr);
368     else if (dir < 0 && (infoPtr->flags & TB_AUTO_PAGE_LEFT))
369         TRACKBAR_PageDown(infoPtr);
370     else return FALSE;
371
372     infoPtr->flags |= TB_THUMBPOSCHANGED;
373     TRACKBAR_InvalidateThumbMove (infoPtr, prevPos, infoPtr->lPos);
374
375     return TRUE;
376 }
377
378 /* Trackbar drawing code. I like my spaghetti done milanese.  */
379
380 static void
381 TRACKBAR_DrawChannel (TRACKBAR_INFO *infoPtr, HDC hdc, DWORD dwStyle)
382 {
383     RECT rcChannel = infoPtr->rcChannel;
384     int runOver = 5;
385
386     /* make the channel slightly overrun the last tick, to make it look more like the native control, and less "clunky" */
387     if (dwStyle & TBS_VERT) {
388         rcChannel.top -= runOver;
389         rcChannel.bottom += runOver;
390     } else {
391         rcChannel.left -= runOver;
392         rcChannel.right += runOver;
393     }
394
395     DrawEdge (hdc, &rcChannel, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
396     if (dwStyle & TBS_ENABLESELRANGE) {          /* fill the channel */
397         FillRect (hdc, &rcChannel, GetStockObject(WHITE_BRUSH));
398         if (TRACKBAR_HasSelection(infoPtr))
399             FillRect (hdc, &infoPtr->rcSelection, GetSysColorBrush(COLOR_HIGHLIGHT));
400     }
401 }
402
403 static void
404 TRACKBAR_DrawOneTic (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags)
405 {
406     int x, y, ox, oy, range, side, offset = 5, indent = 0, len = 3;
407     RECT rcTics;
408
409     TRACE("\n");
410
411     GetClientRect(infoPtr->hwndSelf, &rcTics);
412     if (flags & TBS_VERT) {
413         rcTics.top    = infoPtr->rcChannel.top;
414         rcTics.bottom = infoPtr->rcChannel.bottom;
415     } else {
416         rcTics.left   = infoPtr->rcChannel.left;
417         rcTics.right  = infoPtr->rcChannel.right;
418         rcTics.bottom -= 10; /* value obtained by guesswork and experimentation */
419     }
420
421     if (flags & (TBS_TOP | TBS_LEFT)) {
422         x = rcTics.left;
423         y = rcTics.top;
424         side = -1;
425     } else {
426         x = rcTics.right;
427         y = rcTics.bottom;
428         side = 1;
429     }
430
431     range = infoPtr->lRangeMax - infoPtr->lRangeMin;
432     if (range == 0)
433       range = 1; /* to avoid division by zero */
434
435     if (flags & TIC_SELECTIONMARK) {
436         indent = (flags & TIC_SELECTIONMARKMIN) ? -1 : 1;
437     } else if (flags & TIC_EDGE) {
438         len++;
439     }
440
441     if (flags & TBS_VERT) {
442         int height = rcTics.bottom - rcTics.top;
443         y = rcTics.top + (height*(ticPos - infoPtr->lRangeMin))/range;
444         x -= (offset + 2) * side;
445         y += indent;
446     } else {
447         int width = rcTics.right - rcTics.left;
448         x = rcTics.left + (width*(ticPos - infoPtr->lRangeMin))/range;
449         x += indent;
450         y -= (offset + 2) * side;
451     }
452
453     ox = x;
454     oy = y;
455     MoveToEx(hdc, x, y, 0);
456     if (flags & TBS_VERT) x += len * side;
457     else y += len * side;
458     LineTo(hdc, x, y);
459             
460     if (flags & TIC_SELECTIONMARK) {
461         if (flags & TBS_VERT) {
462             x -= side;
463         } else {
464             y -= side;
465         }
466         MoveToEx(hdc, x, y, 0);
467         if (flags & TBS_VERT) {
468             y += 2 * indent;
469         } else {
470             x += 2 * indent;
471         }
472         
473         LineTo(hdc, x, y);
474         LineTo(hdc, ox, oy);
475     }
476 }
477
478
479 static inline void
480 TRACKBAR_DrawTic (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags)
481 {
482     if ((flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH))
483         TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags | TBS_LEFT);
484
485     if (!(flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH))
486         TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags);
487 }
488
489 static void
490 TRACKBAR_DrawTics (TRACKBAR_INFO *infoPtr, HDC hdc, DWORD dwStyle)
491 {
492     int i, ticFlags = dwStyle & 0x0f;
493     LOGPEN ticPen = { PS_SOLID, {1, 0}, GetSysColor (COLOR_3DDKSHADOW) };
494     HPEN hOldPen, hTicPen;
495     
496     /* create the pen to draw the tics with */   
497     hTicPen = CreatePenIndirect(&ticPen);
498     hOldPen = hTicPen ? SelectObject(hdc, hTicPen) : 0;
499
500     /* actually draw the tics */
501     for (i=0; i<infoPtr->uNumTics; i++)
502         TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->tics[i], ticFlags);
503
504     TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lRangeMin, ticFlags | TIC_EDGE);
505     TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lRangeMax, ticFlags | TIC_EDGE);
506
507     if ((dwStyle & TBS_ENABLESELRANGE) && TRACKBAR_HasSelection(infoPtr)) {
508         TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lSelMin,
509                           ticFlags | TIC_SELECTIONMARKMIN);
510         TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lSelMax,
511                           ticFlags | TIC_SELECTIONMARKMAX);
512     }
513     
514     /* clean up the pen, if we created one */
515     if (hTicPen) {
516         SelectObject(hdc, hOldPen);
517         DeleteObject(hTicPen);
518     }
519 }
520
521 static void
522 TRACKBAR_DrawThumb(TRACKBAR_INFO *infoPtr, HDC hdc, DWORD dwStyle)
523 {
524     HBRUSH oldbr;
525     HPEN  oldpen;
526     RECT thumb = infoPtr->rcThumb;
527     int BlackUntil = 3;
528     int PointCount = 6;
529     POINT points[6];
530     int fillClr;
531
532     static INT PointDepth = 4;
533     fillClr = infoPtr->flags & TB_DRAG_MODE ? COLOR_BTNHILIGHT : COLOR_BTNFACE;
534     oldbr = SelectObject (hdc, GetSysColorBrush(fillClr));
535     SetPolyFillMode (hdc, WINDING);
536
537     if (dwStyle & TBS_BOTH)
538     {
539        points[0].x=thumb.right;
540        points[0].y=thumb.top;
541        points[1].x=thumb.right;
542        points[1].y=thumb.bottom;
543        points[2].x=thumb.left;
544        points[2].y=thumb.bottom;
545        points[3].x=thumb.left;
546        points[3].y=thumb.top;
547        points[4].x=points[0].x;
548        points[4].y=points[0].y;
549        PointCount = 5;
550        BlackUntil = 3;
551     }
552     else
553     {
554         if (dwStyle & TBS_VERT)
555         {
556           if (dwStyle & TBS_LEFT)
557           {
558             points[0].x=thumb.right;
559             points[0].y=thumb.top;
560             points[1].x=thumb.right;
561             points[1].y=thumb.bottom;
562             points[2].x=thumb.left + PointDepth;
563             points[2].y=thumb.bottom;
564             points[3].x=thumb.left;
565             points[3].y=(thumb.bottom - thumb.top) / 2 + thumb.top;
566             points[4].x=thumb.left + PointDepth;
567             points[4].y=thumb.top;
568             points[5].x=points[0].x;
569             points[5].y=points[0].y;
570             BlackUntil = 4;
571           }
572           else
573           {
574             points[0].x=thumb.right;
575             points[0].y=(thumb.bottom - thumb.top) / 2 + thumb.top;
576             points[1].x=thumb.right - PointDepth;
577             points[1].y=thumb.bottom;
578             points[2].x=thumb.left;
579             points[2].y=thumb.bottom;
580             points[3].x=thumb.left;
581             points[3].y=thumb.top;
582             points[4].x=thumb.right - PointDepth;
583             points[4].y=thumb.top;
584             points[5].x=points[0].x;
585             points[5].y=points[0].y;
586           }
587         }
588         else
589         {
590           if (dwStyle & TBS_TOP)
591           {
592             points[0].x=(thumb.right - thumb.left) / 2 + thumb.left ;
593             points[0].y=thumb.top;
594             points[1].x=thumb.right;
595             points[1].y=thumb.top + PointDepth;
596             points[2].x=thumb.right;
597             points[2].y=thumb.bottom;
598             points[3].x=thumb.left;
599             points[3].y=thumb.bottom;
600             points[4].x=thumb.left;
601             points[4].y=thumb.top + PointDepth;
602             points[5].x=points[0].x;
603             points[5].y=points[0].y;
604             BlackUntil = 4;
605           }
606           else
607           {
608             points[0].x=thumb.right;
609             points[0].y=thumb.top;
610             points[1].x=thumb.right;
611             points[1].y=thumb.bottom - PointDepth;
612             points[2].x=(thumb.right - thumb.left) / 2 + thumb.left ;
613             points[2].y=thumb.bottom;
614             points[3].x=thumb.left;
615             points[3].y=thumb.bottom - PointDepth;
616             points[4].x=thumb.left;
617             points[4].y=thumb.top;
618             points[5].x=points[0].x;
619             points[5].y=points[0].y;
620           }
621         }
622
623     }
624
625     /* Draw the thumb now */
626     Polygon (hdc, points, PointCount);
627     oldpen = SelectObject(hdc, GetStockObject(BLACK_PEN));
628     Polyline(hdc,points, BlackUntil);
629     SelectObject(hdc, GetStockObject(WHITE_PEN));
630     Polyline(hdc, &points[BlackUntil-1], PointCount+1-BlackUntil);
631     SelectObject(hdc, oldpen);
632     SelectObject(hdc, oldbr);
633 }
634
635
636 static void inline
637 TRACKBAR_ActivateToolTip (TRACKBAR_INFO *infoPtr, BOOL fShow)
638 {
639     TTTOOLINFOW ti;
640
641     if (!infoPtr->hwndToolTip) return;
642
643     ZeroMemory(&ti, sizeof(ti));
644     ti.cbSize = sizeof(ti);
645     ti.hwnd   = infoPtr->hwndSelf;
646
647     SendMessageW (infoPtr->hwndToolTip, TTM_TRACKACTIVATE, fShow, (LPARAM)&ti);
648 }
649
650
651 static void
652 TRACKBAR_UpdateToolTip (TRACKBAR_INFO *infoPtr)
653 {
654     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
655     WCHAR buf[80], fmt[] = { '%', 'l', 'd', 0 };
656     TTTOOLINFOW ti;
657     POINT pt;
658     RECT rcClient;
659     LRESULT size;
660
661     if (!infoPtr->hwndToolTip) return;
662
663     ZeroMemory(&ti, sizeof(ti));
664     ti.cbSize = sizeof(ti);
665     ti.hwnd   = infoPtr->hwndSelf;
666     ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
667
668     wsprintfW (buf, fmt, infoPtr->lPos);
669     ti.lpszText = buf;
670     SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti);
671
672     GetClientRect (infoPtr->hwndSelf, &rcClient);
673     size = SendMessageW (infoPtr->hwndToolTip, TTM_GETBUBBLESIZE, 0, (LPARAM)&ti);
674     if (dwStyle & TBS_VERT) {
675         if (infoPtr->fLocation == TBTS_LEFT)
676             pt.x = 0 - LOWORD(size) - TOOLTIP_OFFSET;
677         else
678             pt.x = rcClient.right + TOOLTIP_OFFSET;
679         pt.y = (infoPtr->rcThumb.top + infoPtr->rcThumb.bottom - HIWORD(size))/2;
680     } else {
681         if (infoPtr->fLocation == TBTS_TOP)
682             pt.y = 0 - HIWORD(size) - TOOLTIP_OFFSET;
683         else
684             pt.y = rcClient.bottom + TOOLTIP_OFFSET;
685         pt.x = (infoPtr->rcThumb.left + infoPtr->rcThumb.right - LOWORD(size))/2;
686     }
687     ClientToScreen(infoPtr->hwndSelf, &pt);
688
689     SendMessageW (infoPtr->hwndToolTip, TTM_TRACKPOSITION,
690                   0, (LPARAM)MAKELPARAM(pt.x, pt.y));
691 }
692
693
694 static void
695 TRACKBAR_Refresh (TRACKBAR_INFO *infoPtr, HDC hdcDst)
696 {
697     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
698     RECT rcClient;
699     HDC hdc;
700     HBITMAP hOldBmp = 0, hOffScreenBmp = 0;
701     NMCUSTOMDRAW nmcd;
702     int gcdrf, icdrf;
703
704     if (infoPtr->flags & TB_THUMBCHANGED) {
705         TRACKBAR_UpdateThumb (infoPtr);
706         if (infoPtr->flags & TB_THUMBSIZECHANGED)
707             TRACKBAR_CalcChannel (infoPtr);
708     }
709     if (infoPtr->flags & TB_SELECTIONCHANGED)
710         TRACKBAR_CalcSelection (infoPtr);
711
712     if (infoPtr->flags & TB_DRAG_MODE)
713         TRACKBAR_UpdateToolTip (infoPtr);
714
715     infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED);
716
717     GetClientRect (infoPtr->hwndSelf, &rcClient);
718     
719     /* try to render offscreen, if we fail, carrry onscreen */
720     hdc = CreateCompatibleDC(hdcDst);
721     if (hdc) {
722         hOffScreenBmp = CreateCompatibleBitmap(hdcDst, rcClient.right, rcClient.bottom);
723         if (hOffScreenBmp) {
724             hOldBmp = SelectObject(hdc, hOffScreenBmp);
725         } else {
726             DeleteObject(hdc);
727             hdc = hdcDst;
728         }
729     } else {
730         hdc = hdcDst;
731     }
732
733     ZeroMemory(&nmcd, sizeof(nmcd));
734     nmcd.hdr.hwndFrom = infoPtr->hwndSelf;
735     nmcd.hdr.idFrom = GetWindowLongW (infoPtr->hwndSelf, GWL_ID);
736     nmcd.hdr.code = NM_CUSTOMDRAW;
737     nmcd.hdc = hdc;
738
739     /* start the paint cycle */
740     nmcd.rc = rcClient;
741     gcdrf = notify_customdraw(&nmcd, CDDS_PREPAINT);
742     if (gcdrf & CDRF_SKIPDEFAULT) goto cleanup;
743     
744     /* Erase backbround */
745     if (gcdrf == CDRF_DODEFAULT ||
746         notify_customdraw(&nmcd, CDDS_PREERASE) != CDRF_SKIPDEFAULT) {
747         FillRect (hdc, &rcClient, GetSysColorBrush(COLOR_BTNFACE));
748         if (gcdrf != CDRF_DODEFAULT)
749             notify_customdraw(&nmcd, CDDS_POSTERASE);
750     }
751     
752     /* draw channel */
753     if (gcdrf & CDRF_NOTIFYITEMDRAW) {
754         nmcd.dwItemSpec = TBCD_CHANNEL;
755         nmcd.uItemState = CDIS_DEFAULT;
756         nmcd.rc = infoPtr->rcChannel;
757         icdrf = notify_customdraw(&nmcd, CDDS_ITEMPREPAINT);
758     } else icdrf = CDRF_DODEFAULT;
759     if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
760         TRACKBAR_DrawChannel (infoPtr, hdc, dwStyle);
761         if (icdrf & CDRF_NOTIFYPOSTPAINT)
762             notify_customdraw(&nmcd, CDDS_ITEMPOSTPAINT);
763     }
764
765
766     /* draw tics */
767     if (!(dwStyle & TBS_NOTICKS)) {
768         if (gcdrf & CDRF_NOTIFYITEMDRAW) {
769             nmcd.dwItemSpec = TBCD_TICS;
770             nmcd.uItemState = CDIS_DEFAULT;
771             nmcd.rc = rcClient;
772             icdrf = notify_customdraw(&nmcd, CDDS_ITEMPREPAINT);
773         } else icdrf = CDRF_DODEFAULT;
774         if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
775             TRACKBAR_DrawTics (infoPtr, hdc, dwStyle);
776             if (icdrf & CDRF_NOTIFYPOSTPAINT)
777                 notify_customdraw(&nmcd, CDDS_ITEMPOSTPAINT);
778         }
779     }
780     
781     /* draw thumb */
782     if (!(dwStyle & TBS_NOTHUMB)) {
783         if (gcdrf & CDRF_NOTIFYITEMDRAW) {
784             nmcd.dwItemSpec = TBCD_THUMB;
785             nmcd.uItemState = infoPtr->flags & TB_DRAG_MODE ? CDIS_HOT : CDIS_DEFAULT;
786             nmcd.rc = infoPtr->rcThumb;
787             icdrf = notify_customdraw(&nmcd, CDDS_ITEMPREPAINT);
788         } else icdrf = CDRF_DODEFAULT;
789         if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
790             TRACKBAR_DrawThumb(infoPtr, hdc, dwStyle);
791             if (icdrf & CDRF_NOTIFYPOSTPAINT)
792                 notify_customdraw(&nmcd, CDDS_ITEMPOSTPAINT);
793         }
794     }
795
796     /* draw focus rectangle */
797     if (infoPtr->bFocussed) {
798         DrawFocusRect(hdc, &rcClient);
799     }
800
801     /* finish up the painting */
802     if (gcdrf & CDRF_NOTIFYPOSTPAINT)
803         notify_customdraw(&nmcd, CDDS_POSTPAINT);
804     
805 cleanup:
806     /* cleanup, if we rendered offscreen */
807     if (hdc != hdcDst) {
808         BitBlt(hdcDst, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY);
809         SelectObject(hdc, hOldBmp);
810         DeleteObject(hOffScreenBmp);
811         DeleteObject(hdc);
812     }
813 }
814
815
816 static void
817 TRACKBAR_AlignBuddies (TRACKBAR_INFO *infoPtr)
818 {
819     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
820     HWND hwndParent = GetParent (infoPtr->hwndSelf);
821     RECT rcSelf, rcBuddy;
822     INT x, y;
823
824     GetWindowRect (infoPtr->hwndSelf, &rcSelf);
825     MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcSelf, 2);
826
827     /* align buddy left or above */
828     if (infoPtr->hwndBuddyLA) {
829         GetWindowRect (infoPtr->hwndBuddyLA, &rcBuddy);
830         MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcBuddy, 2);
831
832         if (dwStyle & TBS_VERT) {
833             x = (infoPtr->rcChannel.right + infoPtr->rcChannel.left) / 2 -
834                 (rcBuddy.right - rcBuddy.left) / 2 + rcSelf.left;
835             y = rcSelf.top - (rcBuddy.bottom - rcBuddy.top);
836         }
837         else {
838             x = rcSelf.left - (rcBuddy.right - rcBuddy.left);
839             y = (infoPtr->rcChannel.bottom + infoPtr->rcChannel.top) / 2 -
840                 (rcBuddy.bottom - rcBuddy.top) / 2 + rcSelf.top;
841         }
842
843         SetWindowPos (infoPtr->hwndBuddyLA, 0, x, y, 0, 0,
844                       SWP_NOZORDER | SWP_NOSIZE);
845     }
846
847
848     /* align buddy right or below */
849     if (infoPtr->hwndBuddyRB) {
850         GetWindowRect (infoPtr->hwndBuddyRB, &rcBuddy);
851         MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcBuddy, 2);
852
853         if (dwStyle & TBS_VERT) {
854             x = (infoPtr->rcChannel.right + infoPtr->rcChannel.left) / 2 -
855                 (rcBuddy.right - rcBuddy.left) / 2 + rcSelf.left;
856             y = rcSelf.bottom;
857         }
858         else {
859             x = rcSelf.right;
860             y = (infoPtr->rcChannel.bottom + infoPtr->rcChannel.top) / 2 -
861                 (rcBuddy.bottom - rcBuddy.top) / 2 + rcSelf.top;
862         }
863         SetWindowPos (infoPtr->hwndBuddyRB, 0, x, y, 0, 0,
864                       SWP_NOZORDER | SWP_NOSIZE);
865     }
866 }
867
868
869 static LRESULT
870 TRACKBAR_ClearSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
871 {
872     infoPtr->lSelMin = 0;
873     infoPtr->lSelMax = 0;
874     infoPtr->flags |= TB_SELECTIONCHANGED;
875
876     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
877
878     return 0;
879 }
880
881
882 static LRESULT
883 TRACKBAR_ClearTics (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
884 {
885     if (infoPtr->tics) {
886         COMCTL32_Free (infoPtr->tics);
887         infoPtr->tics = NULL;
888         infoPtr->uNumTics = 0;
889     }
890
891     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
892
893     return 0;
894 }
895
896
897 static LRESULT inline
898 TRACKBAR_GetChannelRect (TRACKBAR_INFO *infoPtr, LPRECT lprc)
899 {
900     if (lprc == NULL) return 0;
901
902     lprc->left   = infoPtr->rcChannel.left;
903     lprc->right  = infoPtr->rcChannel.right;
904     lprc->bottom = infoPtr->rcChannel.bottom;
905     lprc->top    = infoPtr->rcChannel.top;
906
907     return 0;
908 }
909
910
911 static LONG inline
912 TRACKBAR_GetNumTics (TRACKBAR_INFO *infoPtr)
913 {
914     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_NOTICKS)
915         return 0;
916
917     return infoPtr->uNumTics + 2;
918 }
919
920
921 static int comp_tics(const void *ap, const void *bp)
922 {
923     DWORD a = *((DWORD *)ap);
924     DWORD b = *((DWORD *)bp);
925
926     TRACE("(a=%ld, b=%ld)\n", a, b);
927     if (a < b) return -1;
928     if (a > b) return 1;
929     return 0;
930 }
931
932
933 static LONG inline
934 TRACKBAR_GetTic (TRACKBAR_INFO *infoPtr, INT iTic)
935 {
936     if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics)
937         return -1;
938
939     qsort(infoPtr->tics, infoPtr->uNumTics, sizeof(DWORD), comp_tics);
940     return infoPtr->tics[iTic];
941 }
942
943
944 static LONG inline
945 TRACKBAR_GetTicPos (TRACKBAR_INFO *infoPtr, INT iTic)
946 {
947     LONG range, width, pos, tic;
948
949     if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics)
950         return -1;
951
952     tic   = TRACKBAR_GetTic (infoPtr, iTic);
953     range = infoPtr->lRangeMax - infoPtr->lRangeMin;
954     width = infoPtr->rcChannel.right - infoPtr->rcChannel.left;
955     pos   = infoPtr->rcChannel.left + (width * tic) / range;
956
957     return pos;
958 }
959
960
961 static HWND
962 TRACKBAR_SetBuddy (TRACKBAR_INFO *infoPtr, BOOL fLocation, HWND hwndBuddy)
963 {
964     HWND hwndTemp;
965
966     if (fLocation) {
967         /* buddy is left or above */
968         hwndTemp = infoPtr->hwndBuddyLA;
969         infoPtr->hwndBuddyLA = hwndBuddy;
970     }
971     else {
972         /* buddy is right or below */
973         hwndTemp = infoPtr->hwndBuddyRB;
974         infoPtr->hwndBuddyRB = hwndBuddy;
975     }
976
977     TRACKBAR_AlignBuddies (infoPtr);
978
979     return hwndTemp;
980 }
981
982
983 static LONG inline
984 TRACKBAR_SetLineSize (TRACKBAR_INFO *infoPtr, LONG lLineSize)
985 {
986     LONG lTemp = infoPtr->lLineSize;
987
988     infoPtr->lLineSize = lLineSize;
989
990     return lTemp;
991 }
992
993
994 static LONG inline
995 TRACKBAR_SetPageSize (TRACKBAR_INFO *infoPtr, LONG lPageSize)
996 {
997     LONG lTemp = infoPtr->lPageSize;
998
999     infoPtr->lPageSize = lPageSize;
1000
1001     return lTemp;
1002 }
1003
1004
1005 static LRESULT inline
1006 TRACKBAR_SetPos (TRACKBAR_INFO *infoPtr, BOOL fPosition, LONG lPosition)
1007 {
1008     LONG oldPos = infoPtr->lPos;
1009     infoPtr->lPos = lPosition;
1010
1011     if (infoPtr->lPos < infoPtr->lRangeMin)
1012         infoPtr->lPos = infoPtr->lRangeMin;
1013
1014     if (infoPtr->lPos > infoPtr->lRangeMax)
1015         infoPtr->lPos = infoPtr->lRangeMax;
1016     infoPtr->flags |= TB_THUMBPOSCHANGED;
1017
1018     if (fPosition) TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition);
1019
1020     return 0;
1021 }
1022
1023
1024 static LRESULT inline
1025 TRACKBAR_SetRange (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lRange)
1026 {
1027     infoPtr->lRangeMin = (SHORT)LOWORD(lRange);
1028     infoPtr->lRangeMax = (SHORT)HIWORD(lRange);
1029
1030     if (infoPtr->lPos < infoPtr->lRangeMin) {
1031         infoPtr->lPos = infoPtr->lRangeMin;
1032         infoPtr->flags |= TB_THUMBPOSCHANGED;
1033     }
1034
1035     if (infoPtr->lPos > infoPtr->lRangeMax) {
1036         infoPtr->lPos = infoPtr->lRangeMax;
1037         infoPtr->flags |= TB_THUMBPOSCHANGED;
1038     }
1039
1040     infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
1041     if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
1042
1043     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1044
1045     return 0;
1046 }
1047
1048
1049 static LRESULT inline
1050 TRACKBAR_SetRangeMax (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMax)
1051 {
1052     infoPtr->lRangeMax = lMax;
1053     if (infoPtr->lPos > infoPtr->lRangeMax) {
1054         infoPtr->lPos = infoPtr->lRangeMax;
1055         infoPtr->flags |= TB_THUMBPOSCHANGED;
1056     }
1057
1058     infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
1059     if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
1060
1061     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1062
1063     return 0;
1064 }
1065
1066
1067 static LRESULT inline
1068 TRACKBAR_SetRangeMin (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMin)
1069 {
1070     infoPtr->lRangeMin = lMin;
1071     if (infoPtr->lPos < infoPtr->lRangeMin) {
1072         infoPtr->lPos = infoPtr->lRangeMin;
1073         infoPtr->flags |= TB_THUMBPOSCHANGED;
1074     }
1075
1076     infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
1077     if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
1078
1079     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1080
1081     return 0;
1082 }
1083
1084
1085 static LRESULT inline
1086 TRACKBAR_SetSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lSel)
1087 {
1088     if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE)
1089         return 0;
1090
1091     infoPtr->lSelMin = (SHORT)LOWORD(lSel);
1092     infoPtr->lSelMax = (SHORT)HIWORD(lSel);
1093     infoPtr->flags |= TB_SELECTIONCHANGED;
1094
1095     if (infoPtr->lSelMin < infoPtr->lRangeMin)
1096         infoPtr->lSelMin = infoPtr->lRangeMin;
1097     if (infoPtr->lSelMax > infoPtr->lRangeMax)
1098         infoPtr->lSelMax = infoPtr->lRangeMax;
1099
1100     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1101
1102     return 0;
1103 }
1104
1105
1106 static LRESULT inline
1107 TRACKBAR_SetSelEnd (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lEnd)
1108 {
1109     if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE)
1110         return 0;
1111
1112     infoPtr->lSelMax = lEnd;
1113     infoPtr->flags |= TB_SELECTIONCHANGED;
1114
1115     if (infoPtr->lSelMax > infoPtr->lRangeMax)
1116         infoPtr->lSelMax = infoPtr->lRangeMax;
1117
1118     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1119
1120     return 0;
1121 }
1122
1123
1124 static LRESULT inline
1125 TRACKBAR_SetSelStart (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lStart)
1126 {
1127     if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE)
1128         return 0;
1129
1130     infoPtr->lSelMin = lStart;
1131     infoPtr->flags  |=TB_SELECTIONCHANGED;
1132
1133     if (infoPtr->lSelMin < infoPtr->lRangeMin)
1134         infoPtr->lSelMin = infoPtr->lRangeMin;
1135
1136     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1137
1138     return 0;
1139 }
1140
1141
1142 static LRESULT inline
1143 TRACKBAR_SetThumbLength (TRACKBAR_INFO *infoPtr, UINT iLength)
1144 {
1145     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_FIXEDLENGTH) {
1146         infoPtr->uThumbLen = iLength;
1147         infoPtr->flags |= TB_THUMBSIZECHANGED;
1148         InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
1149     }
1150
1151     return 0;
1152 }
1153
1154
1155 static LRESULT inline
1156 TRACKBAR_SetTic (TRACKBAR_INFO *infoPtr, LONG lPos)
1157 {
1158     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS)
1159         return FALSE;
1160
1161     if ((lPos < infoPtr->lRangeMin) || (lPos> infoPtr->lRangeMax))
1162         return FALSE;
1163
1164     TRACE("lPos=%ld\n", lPos);
1165
1166     infoPtr->uNumTics++;
1167     infoPtr->tics=COMCTL32_ReAlloc( infoPtr->tics,
1168                                     (infoPtr->uNumTics)*sizeof (DWORD));
1169     if (!infoPtr->tics) {
1170         infoPtr->uNumTics = 0;
1171         TRACKBAR_SendNotify(infoPtr, NM_OUTOFMEMORY);
1172         return FALSE;
1173     }
1174     infoPtr->tics[infoPtr->uNumTics-1] = lPos;
1175
1176     TRACKBAR_InvalidateAll(infoPtr);
1177
1178     return TRUE;
1179 }
1180
1181
1182 static LRESULT inline
1183 TRACKBAR_SetTicFreq (TRACKBAR_INFO *infoPtr, WORD wFreq)
1184 {
1185     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS) {
1186         infoPtr->uTicFreq = wFreq;
1187         TRACKBAR_RecalculateTics (infoPtr);
1188         TRACKBAR_InvalidateAll(infoPtr);
1189     }
1190
1191     return 0;
1192 }
1193
1194
1195 static INT inline
1196 TRACKBAR_SetTipSide (TRACKBAR_INFO *infoPtr, INT fLocation)
1197 {
1198     INT fTemp = infoPtr->fLocation;
1199
1200     infoPtr->fLocation = fLocation;
1201
1202     return fTemp;
1203 }
1204
1205
1206 static LRESULT inline
1207 TRACKBAR_SetToolTips (TRACKBAR_INFO *infoPtr, HWND hwndTT)
1208 {
1209     infoPtr->hwndToolTip = hwndTT;
1210
1211     return 0;
1212 }
1213
1214
1215 static BOOL inline
1216 TRACKBAR_SetUnicodeFormat (TRACKBAR_INFO *infoPtr, BOOL fUnicode)
1217 {
1218     BOOL bTemp = infoPtr->bUnicode;
1219
1220     infoPtr->bUnicode = fUnicode;
1221
1222     return bTemp;
1223 }
1224
1225
1226 static LRESULT
1227 TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr)
1228 {
1229     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
1230     RECT rect;
1231
1232     /* initial thumb length */
1233     GetClientRect(infoPtr->hwndSelf,&rect);
1234     if (dwStyle & TBS_VERT) {
1235         infoPtr->uThumbLen = (rect.right - rect.left - 6);
1236     } else {
1237         infoPtr->uThumbLen = (rect.bottom - rect.top);
1238     }
1239
1240     TRACKBAR_CalcChannel (infoPtr);
1241     TRACKBAR_UpdateThumb (infoPtr);
1242     infoPtr->flags &= ~TB_SELECTIONCHANGED;
1243
1244     return 0;
1245 }
1246
1247
1248 static LRESULT
1249 TRACKBAR_Create (HWND hwnd, LPCREATESTRUCTW lpcs)
1250 {
1251     TRACKBAR_INFO *infoPtr;
1252     DWORD oldStyle, newStyle;
1253
1254     infoPtr = (TRACKBAR_INFO *)COMCTL32_Alloc (sizeof(TRACKBAR_INFO));
1255     if (!infoPtr) return -1;
1256     SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
1257
1258     /* set default values */
1259     infoPtr->hwndSelf  = hwnd;
1260     infoPtr->lRangeMin = 0;
1261     infoPtr->lRangeMax = 100;
1262     infoPtr->lLineSize = 1;
1263     infoPtr->lPageSize = 20;
1264     infoPtr->lSelMin   = 0;
1265     infoPtr->lSelMax   = 0;
1266     infoPtr->lPos      = 0;
1267     infoPtr->fLocation = -1;
1268     infoPtr->uNumTics  = 0;    /* start and end tic are not included in count*/
1269     infoPtr->uTicFreq  = 1;
1270     infoPtr->tics      = NULL;
1271     infoPtr->hwndNotify= GetParent (hwnd);
1272
1273     TRACKBAR_InitializeThumb (infoPtr);
1274
1275     oldStyle = newStyle = GetWindowLongW (hwnd, GWL_STYLE);
1276     if (oldStyle & TBS_VERT) {
1277         if (! (oldStyle & (TBS_LEFT | TBS_RIGHT | TBS_BOTH)) )
1278             newStyle |= TBS_RIGHT;
1279     } else {
1280         if (! (oldStyle & (TBS_TOP | TBS_BOTTOM | TBS_BOTH)) )
1281             newStyle |= TBS_BOTTOM;
1282     }
1283     if (newStyle != oldStyle)
1284         SetWindowLongW (hwnd, GWL_STYLE, newStyle);
1285
1286     /* Create tooltip control */
1287     if (newStyle & TBS_TOOLTIPS) {
1288
1289         infoPtr->hwndToolTip =
1290             CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0,
1291                              CW_USEDEFAULT, CW_USEDEFAULT,
1292                              CW_USEDEFAULT, CW_USEDEFAULT,
1293                              hwnd, 0, 0, 0);
1294
1295         if (infoPtr->hwndToolTip) {
1296             TTTOOLINFOW ti;         
1297             ZeroMemory (&ti, sizeof(ti));
1298             ti.cbSize   = sizeof(ti);
1299             ti.uFlags   = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
1300             ti.hwnd     = hwnd;
1301
1302             SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
1303          }
1304     }
1305
1306     return 0;
1307 }
1308
1309
1310 static LRESULT
1311 TRACKBAR_Destroy (TRACKBAR_INFO *infoPtr)
1312 {
1313     /* delete tooltip control */
1314     if (infoPtr->hwndToolTip)
1315         DestroyWindow (infoPtr->hwndToolTip);
1316
1317     COMCTL32_Free (infoPtr);
1318     SetWindowLongW (infoPtr->hwndSelf, 0, 0);
1319     return 0;
1320 }
1321
1322
1323 static LRESULT
1324 TRACKBAR_KillFocus (TRACKBAR_INFO *infoPtr, HWND hwndGetFocus)
1325 {
1326     TRACE("\n");
1327     infoPtr->bFocussed = FALSE;
1328     TRACKBAR_InvalidateAll(infoPtr);
1329
1330     return 0;
1331 }
1332
1333 static LRESULT
1334 TRACKBAR_LButtonDown (TRACKBAR_INFO *infoPtr, DWORD fwKeys, POINTS pts)
1335 {
1336     POINT clickPoint = { pts.x, pts.y };
1337
1338     SetFocus(infoPtr->hwndSelf);
1339
1340     if (PtInRect(&infoPtr->rcThumb, clickPoint)) {
1341         infoPtr->flags |= TB_DRAG_MODE;
1342         SetCapture (infoPtr->hwndSelf);
1343         TRACKBAR_UpdateToolTip (infoPtr);
1344         TRACKBAR_ActivateToolTip (infoPtr, TRUE);
1345         TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
1346     } else {
1347         LONG dir = TRACKBAR_GetAutoPageDirection(infoPtr, clickPoint);
1348         if (dir == 0) return 0;
1349         infoPtr->flags |= (dir < 0) ? TB_AUTO_PAGE_LEFT : TB_AUTO_PAGE_RIGHT;
1350         TRACKBAR_AutoPage (infoPtr, clickPoint);
1351         SetCapture (infoPtr->hwndSelf);
1352         SetTimer(infoPtr->hwndSelf, TB_REFRESH_TIMER, TB_REFRESH_DELAY, 0);
1353     }
1354
1355     return 0;
1356 }
1357
1358
1359 static LRESULT
1360 TRACKBAR_LButtonUp (TRACKBAR_INFO *infoPtr, DWORD fwKeys, POINTS pts)
1361 {
1362     if (infoPtr->flags & TB_DRAG_MODE) {
1363         TRACKBAR_SendNotify (infoPtr, TB_ENDTRACK);
1364         infoPtr->flags &= ~TB_DRAG_MODE;
1365         ReleaseCapture ();
1366         TRACKBAR_SendNotify(infoPtr, NM_RELEASEDCAPTURE);
1367         TRACKBAR_ActivateToolTip(infoPtr, FALSE);
1368         TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
1369     }
1370     if (infoPtr->flags & TB_AUTO_PAGE) {
1371         KillTimer (infoPtr->hwndSelf, TB_REFRESH_TIMER);
1372         infoPtr->flags &= ~TB_AUTO_PAGE;
1373         ReleaseCapture ();
1374         TRACKBAR_SendNotify(infoPtr, NM_RELEASEDCAPTURE);
1375     }
1376
1377     return 0;
1378 }
1379
1380
1381 static LRESULT
1382 TRACKBAR_CaptureChanged (TRACKBAR_INFO *infoPtr)
1383 {
1384     TRACKBAR_SendNotify (infoPtr, TB_ENDTRACK);
1385     return 0;
1386 }
1387
1388
1389 static LRESULT
1390 TRACKBAR_Paint (TRACKBAR_INFO *infoPtr, HDC hdc)
1391 {
1392     if (hdc) {
1393         TRACKBAR_Refresh(infoPtr, hdc);
1394     } else {
1395         PAINTSTRUCT ps;
1396         hdc = BeginPaint (infoPtr->hwndSelf, &ps);
1397         TRACKBAR_Refresh (infoPtr, hdc);
1398         EndPaint (infoPtr->hwndSelf, &ps);
1399     }
1400
1401     return 0;
1402 }
1403
1404
1405 static LRESULT
1406 TRACKBAR_SetFocus (TRACKBAR_INFO *infoPtr, HWND hwndLoseFocus)
1407 {
1408     TRACE("\n");
1409     infoPtr->bFocussed = TRUE;
1410     TRACKBAR_InvalidateAll(infoPtr);
1411
1412     return 0;
1413 }
1414
1415
1416 static LRESULT
1417 TRACKBAR_Size (TRACKBAR_INFO *infoPtr, DWORD fwSizeType, INT nWidth, INT nHeight)
1418 {
1419     TRACKBAR_CalcChannel (infoPtr);
1420     TRACKBAR_AlignBuddies (infoPtr);
1421
1422     return 0;
1423 }
1424
1425
1426 static LRESULT
1427 TRACKBAR_Timer (TRACKBAR_INFO *infoPtr, INT wTimerID, TIMERPROC *tmrpc)
1428 {
1429     if (infoPtr->flags & TB_AUTO_PAGE) {
1430         POINT pt;
1431         if (GetCursorPos(&pt))
1432             if (ScreenToClient(infoPtr->hwndSelf, &pt))
1433                 TRACKBAR_AutoPage(infoPtr, pt);
1434     }
1435     return 0;
1436 }
1437
1438
1439 static BOOL
1440 TRACKBAR_SendNotify (TRACKBAR_INFO *infoPtr, UINT code)
1441 {
1442     BOOL bVert = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_VERT;
1443
1444     TRACE("%x\n", code);
1445
1446     return (BOOL) SendMessageW (GetParent (infoPtr->hwndSelf),
1447                                 bVert ? WM_VSCROLL : WM_HSCROLL,
1448                                 (WPARAM)code, (LPARAM)infoPtr->hwndSelf);
1449 }
1450
1451
1452 static LRESULT
1453 TRACKBAR_MouseMove (TRACKBAR_INFO *infoPtr, DWORD fwKeys, POINTS pts)
1454 {
1455     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
1456     INT clickPlace = (dwStyle & TBS_VERT) ? pts.y : pts.x;
1457     DOUBLE dragPos, oldPos = infoPtr->lPos;
1458
1459     TRACE("(x=%d. y=%d)\n", pts.x, pts.y);
1460
1461     if (infoPtr->flags & TB_AUTO_PAGE) {
1462         POINT pt;
1463         POINTSTOPOINT(pt, pts);
1464         TRACKBAR_AutoPage (infoPtr, pt);
1465         return TRUE;
1466     }
1467
1468     if (!(infoPtr->flags & TB_DRAG_MODE)) return TRUE;
1469
1470     dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace,
1471                                                dwStyle & TBS_VERT);
1472     if (dragPos > ((INT)dragPos) + 0.5) dragPos++;
1473
1474     if (dragPos == oldPos) return TRUE;
1475
1476     infoPtr->lPos = dragPos;
1477
1478     infoPtr->flags |= TB_THUMBPOSCHANGED;
1479     TRACKBAR_SendNotify (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16));
1480
1481
1482     TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos);
1483     UpdateWindow (infoPtr->hwndSelf);
1484
1485     return TRUE;
1486 }
1487
1488
1489 static BOOL
1490 TRACKBAR_KeyDown (TRACKBAR_INFO *infoPtr, INT nVirtKey, DWORD lKeyData)
1491 {
1492     BOOL downIsLeft = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_DOWNISLEFT;
1493     LONG pos = infoPtr->lPos;
1494
1495     TRACE("%x\n", nVirtKey);
1496
1497     switch (nVirtKey) {
1498     case VK_UP:
1499         if (downIsLeft) goto step_right;
1500     case VK_LEFT:
1501     step_left:
1502         if (infoPtr->lPos == infoPtr->lRangeMin) return FALSE;
1503         infoPtr->lPos -= infoPtr->lLineSize;
1504         if (infoPtr->lPos < infoPtr->lRangeMin)
1505             infoPtr->lPos = infoPtr->lRangeMin;
1506         TRACKBAR_SendNotify (infoPtr, TB_LINEUP);
1507         break;
1508     case VK_DOWN:
1509         if (downIsLeft) goto step_left;
1510     case VK_RIGHT:
1511     step_right:
1512         if (infoPtr->lPos == infoPtr->lRangeMax) return FALSE;
1513         infoPtr->lPos += infoPtr->lLineSize;
1514         if (infoPtr->lPos > infoPtr->lRangeMax)
1515             infoPtr->lPos = infoPtr->lRangeMax;
1516         TRACKBAR_SendNotify (infoPtr, TB_LINEDOWN);
1517         break;
1518     case VK_NEXT:
1519         if (downIsLeft) goto page_left;
1520     page_right:
1521         TRACKBAR_PageUp(infoPtr);
1522         break;
1523     case VK_PRIOR:
1524         if (downIsLeft) goto page_right;
1525     page_left:
1526         TRACKBAR_PageDown(infoPtr);
1527         break;
1528     case VK_HOME:
1529         if (infoPtr->lPos == infoPtr->lRangeMin) return FALSE;
1530         infoPtr->lPos = infoPtr->lRangeMin;
1531         TRACKBAR_SendNotify (infoPtr, TB_TOP);
1532         break;
1533     case VK_END:
1534         if (infoPtr->lPos == infoPtr->lRangeMax) return FALSE;
1535         infoPtr->lPos = infoPtr->lRangeMax;
1536         TRACKBAR_SendNotify (infoPtr, TB_BOTTOM);
1537         break;
1538     }
1539
1540     if (pos != infoPtr->lPos) {
1541         infoPtr->flags |=TB_THUMBPOSCHANGED;
1542         TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos);
1543     }
1544
1545     return TRUE;
1546 }
1547
1548
1549 static BOOL inline
1550 TRACKBAR_KeyUp (TRACKBAR_INFO *infoPtr, INT nVirtKey, DWORD lKeyData)
1551 {
1552     switch (nVirtKey) {
1553     case VK_LEFT:
1554     case VK_UP:
1555     case VK_RIGHT:
1556     case VK_DOWN:
1557     case VK_NEXT:
1558     case VK_PRIOR:
1559     case VK_HOME:
1560     case VK_END:
1561         TRACKBAR_SendNotify (infoPtr, TB_ENDTRACK);
1562     }
1563     return TRUE;
1564 }
1565
1566
1567 static LRESULT WINAPI
1568 TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1569 {
1570     TRACKBAR_INFO *infoPtr = (TRACKBAR_INFO *)GetWindowLongW (hwnd, 0);
1571
1572     TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam);
1573
1574     if (!infoPtr && (uMsg != WM_CREATE))
1575         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
1576
1577     switch (uMsg)
1578     {
1579     case TBM_CLEARSEL:
1580         return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam);
1581
1582     case TBM_CLEARTICS:
1583         return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam);
1584
1585     case TBM_GETBUDDY:
1586         return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB);
1587
1588     case TBM_GETCHANNELRECT:
1589         return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam);
1590
1591     case TBM_GETLINESIZE:
1592         return infoPtr->lLineSize;
1593
1594     case TBM_GETNUMTICS:
1595         return TRACKBAR_GetNumTics (infoPtr);
1596
1597     case TBM_GETPAGESIZE:
1598         return infoPtr->lPageSize;
1599
1600     case TBM_GETPOS:
1601         return infoPtr->lPos;
1602
1603     case TBM_GETPTICS:
1604         return (LRESULT)infoPtr->tics;
1605
1606     case TBM_GETRANGEMAX:
1607         return infoPtr->lRangeMax;
1608
1609     case TBM_GETRANGEMIN:
1610         return infoPtr->lRangeMin;
1611
1612     case TBM_GETSELEND:
1613         return infoPtr->lSelMax;
1614
1615     case TBM_GETSELSTART:
1616         return infoPtr->lSelMin;
1617
1618     case TBM_GETTHUMBLENGTH:
1619         return infoPtr->uThumbLen;
1620
1621     case TBM_GETTHUMBRECT:
1622         return CopyRect((LPRECT)lParam, &infoPtr->rcThumb);
1623
1624     case TBM_GETTIC:
1625         return TRACKBAR_GetTic (infoPtr, (INT)wParam);
1626
1627     case TBM_GETTICPOS:
1628         return TRACKBAR_GetTicPos (infoPtr, (INT)wParam);
1629
1630     case TBM_GETTOOLTIPS:
1631         return (LRESULT)infoPtr->hwndToolTip;
1632
1633     case TBM_GETUNICODEFORMAT:
1634         return infoPtr->bUnicode;
1635
1636     case TBM_SETBUDDY:
1637         return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam);
1638
1639     case TBM_SETLINESIZE:
1640         return TRACKBAR_SetLineSize (infoPtr, (LONG)lParam);
1641
1642     case TBM_SETPAGESIZE:
1643         return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam);
1644
1645     case TBM_SETPOS:
1646         return TRACKBAR_SetPos (infoPtr, (BOOL)wParam, (LONG)lParam);
1647
1648     case TBM_SETRANGE:
1649         return TRACKBAR_SetRange (infoPtr, (BOOL)wParam, (LONG)lParam);
1650
1651     case TBM_SETRANGEMAX:
1652         return TRACKBAR_SetRangeMax (infoPtr, (BOOL)wParam, (LONG)lParam);
1653
1654     case TBM_SETRANGEMIN:
1655         return TRACKBAR_SetRangeMin (infoPtr, (BOOL)wParam, (LONG)lParam);
1656
1657     case TBM_SETSEL:
1658         return TRACKBAR_SetSel (infoPtr, (BOOL)wParam, (LONG)lParam);
1659
1660     case TBM_SETSELEND:
1661         return TRACKBAR_SetSelEnd (infoPtr, (BOOL)wParam, (LONG)lParam);
1662
1663     case TBM_SETSELSTART:
1664         return TRACKBAR_SetSelStart (infoPtr, (BOOL)wParam, (LONG)lParam);
1665
1666     case TBM_SETTHUMBLENGTH:
1667         return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam);
1668
1669     case TBM_SETTIC:
1670         return TRACKBAR_SetTic (infoPtr, (LONG)lParam);
1671
1672     case TBM_SETTICFREQ:
1673         return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam);
1674
1675     case TBM_SETTIPSIDE:
1676         return TRACKBAR_SetTipSide (infoPtr, (INT)wParam);
1677
1678     case TBM_SETTOOLTIPS:
1679         return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam);
1680
1681     case TBM_SETUNICODEFORMAT:
1682         return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam);
1683
1684
1685     case WM_CAPTURECHANGED:
1686         return TRACKBAR_CaptureChanged (infoPtr);
1687
1688     case WM_CREATE:
1689         return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam);
1690
1691     case WM_DESTROY:
1692         return TRACKBAR_Destroy (infoPtr);
1693
1694 /*      case WM_ENABLE: */
1695
1696     case WM_ERASEBKGND:
1697         return 0;
1698
1699     case WM_GETDLGCODE:
1700         return DLGC_WANTARROWS;
1701
1702     case WM_KEYDOWN:
1703         return TRACKBAR_KeyDown (infoPtr, (INT)wParam, (DWORD)lParam);
1704
1705     case WM_KEYUP:
1706         return TRACKBAR_KeyUp (infoPtr, (INT)wParam, (DWORD)lParam);
1707
1708     case WM_KILLFOCUS:
1709         return TRACKBAR_KillFocus (infoPtr, (HWND)wParam);
1710
1711     case WM_LBUTTONDOWN:
1712         return TRACKBAR_LButtonDown (infoPtr, wParam, MAKEPOINTS(lParam));
1713
1714     case WM_LBUTTONUP:
1715         return TRACKBAR_LButtonUp (infoPtr, wParam, MAKEPOINTS(lParam));
1716
1717     case WM_MOUSEMOVE:
1718         return TRACKBAR_MouseMove (infoPtr, wParam, MAKEPOINTS(lParam));
1719
1720     case WM_PAINT:
1721         return TRACKBAR_Paint (infoPtr, (HDC)wParam);
1722
1723     case WM_SETFOCUS:
1724         return TRACKBAR_SetFocus (infoPtr, (HWND)wParam);
1725
1726     case WM_SIZE:
1727         return TRACKBAR_Size (infoPtr, wParam, LOWORD(lParam), HIWORD(lParam));
1728
1729     case WM_TIMER:
1730         return TRACKBAR_Timer (infoPtr, (INT)wParam, (TIMERPROC *)lParam);
1731
1732     case WM_WININICHANGE:
1733         return TRACKBAR_InitializeThumb (infoPtr);
1734
1735     default:
1736         if ((uMsg >= WM_USER) && (uMsg < WM_APP))
1737             ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam);
1738         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
1739     }
1740     return 0;
1741 }
1742
1743
1744 void TRACKBAR_Register (void)
1745 {
1746     WNDCLASSW wndClass;
1747
1748     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
1749     wndClass.style         = CS_GLOBALCLASS;
1750     wndClass.lpfnWndProc   = (WNDPROC)TRACKBAR_WindowProc;
1751     wndClass.cbClsExtra    = 0;
1752     wndClass.cbWndExtra    = sizeof(TRACKBAR_INFO *);
1753     wndClass.hCursor       = LoadCursorW (0, IDC_ARROWW);
1754     wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
1755     wndClass.lpszClassName = TRACKBAR_CLASSW;
1756
1757     RegisterClassW (&wndClass);
1758 }
1759
1760
1761 void TRACKBAR_Unregister (void)
1762 {
1763     UnregisterClassW (TRACKBAR_CLASSW, NULL);
1764 }