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