Minor fixes and updates to the German resource files.
[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];
732     static const WCHAR fmt[] = { '%', 'l', 'd', 0 };
733     TTTOOLINFOW ti;
734     POINT pt;
735     RECT rcClient;
736     LRESULT size;
737
738     if (!infoPtr->hwndToolTip) return;
739
740     ZeroMemory(&ti, sizeof(ti));
741     ti.cbSize = sizeof(ti);
742     ti.hwnd   = infoPtr->hwndSelf;
743     ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
744
745     wsprintfW (buf, fmt, infoPtr->lPos);
746     ti.lpszText = buf;
747     SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti);
748
749     GetClientRect (infoPtr->hwndSelf, &rcClient);
750     size = SendMessageW (infoPtr->hwndToolTip, TTM_GETBUBBLESIZE, 0, (LPARAM)&ti);
751     if (dwStyle & TBS_VERT) {
752         if (infoPtr->fLocation == TBTS_LEFT)
753             pt.x = 0 - LOWORD(size) - TOOLTIP_OFFSET;
754         else
755             pt.x = rcClient.right + TOOLTIP_OFFSET;
756         pt.y = (infoPtr->rcThumb.top + infoPtr->rcThumb.bottom - HIWORD(size))/2;
757     } else {
758         if (infoPtr->fLocation == TBTS_TOP)
759             pt.y = 0 - HIWORD(size) - TOOLTIP_OFFSET;
760         else
761             pt.y = rcClient.bottom + TOOLTIP_OFFSET;
762         pt.x = (infoPtr->rcThumb.left + infoPtr->rcThumb.right - LOWORD(size))/2;
763     }
764     ClientToScreen(infoPtr->hwndSelf, &pt);
765
766     SendMessageW (infoPtr->hwndToolTip, TTM_TRACKPOSITION,
767                   0, (LPARAM)MAKELPARAM(pt.x, pt.y));
768 }
769
770
771 static void
772 TRACKBAR_Refresh (TRACKBAR_INFO *infoPtr, HDC hdcDst)
773 {
774     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
775     RECT rcClient;
776     HDC hdc;
777     HBITMAP hOldBmp = 0, hOffScreenBmp = 0;
778     NMCUSTOMDRAW nmcd;
779     int gcdrf, icdrf;
780
781     if (infoPtr->flags & TB_THUMBCHANGED) {
782         TRACKBAR_UpdateThumb (infoPtr);
783         if (infoPtr->flags & TB_THUMBSIZECHANGED)
784             TRACKBAR_CalcChannel (infoPtr);
785     }
786     if (infoPtr->flags & TB_SELECTIONCHANGED)
787         TRACKBAR_CalcSelection (infoPtr);
788
789     if (infoPtr->flags & TB_DRAG_MODE)
790         TRACKBAR_UpdateToolTip (infoPtr);
791
792     infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED);
793
794     GetClientRect (infoPtr->hwndSelf, &rcClient);
795     
796     /* try to render offscreen, if we fail, carrry onscreen */
797     hdc = CreateCompatibleDC(hdcDst);
798     if (hdc) {
799         hOffScreenBmp = CreateCompatibleBitmap(hdcDst, rcClient.right, rcClient.bottom);
800         if (hOffScreenBmp) {
801             hOldBmp = SelectObject(hdc, hOffScreenBmp);
802         } else {
803             DeleteObject(hdc);
804             hdc = hdcDst;
805         }
806     } else {
807         hdc = hdcDst;
808     }
809
810     ZeroMemory(&nmcd, sizeof(nmcd));
811     nmcd.hdr.hwndFrom = infoPtr->hwndSelf;
812     nmcd.hdr.idFrom = GetWindowLongW (infoPtr->hwndSelf, GWL_ID);
813     nmcd.hdr.code = NM_CUSTOMDRAW;
814     nmcd.hdc = hdc;
815
816     /* start the paint cycle */
817     nmcd.rc = rcClient;
818     gcdrf = notify_customdraw(infoPtr, &nmcd, CDDS_PREPAINT);
819     if (gcdrf & CDRF_SKIPDEFAULT) goto cleanup;
820     
821     /* Erase backbround */
822     if (gcdrf == CDRF_DODEFAULT ||
823         notify_customdraw(infoPtr, &nmcd, CDDS_PREERASE) != CDRF_SKIPDEFAULT) {
824         FillRect (hdc, &rcClient, GetSysColorBrush(COLOR_BTNFACE));
825         if (gcdrf != CDRF_DODEFAULT)
826             notify_customdraw(infoPtr, &nmcd, CDDS_POSTERASE);
827     }
828     
829     /* draw channel */
830     if (gcdrf & CDRF_NOTIFYITEMDRAW) {
831         nmcd.dwItemSpec = TBCD_CHANNEL;
832         nmcd.uItemState = CDIS_DEFAULT;
833         nmcd.rc = infoPtr->rcChannel;
834         icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
835     } else icdrf = CDRF_DODEFAULT;
836     if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
837         TRACKBAR_DrawChannel (infoPtr, hdc, dwStyle);
838         if (icdrf & CDRF_NOTIFYPOSTPAINT)
839             notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
840     }
841
842
843     /* draw tics */
844     if (!(dwStyle & TBS_NOTICKS)) {
845         if (gcdrf & CDRF_NOTIFYITEMDRAW) {
846             nmcd.dwItemSpec = TBCD_TICS;
847             nmcd.uItemState = CDIS_DEFAULT;
848             nmcd.rc = rcClient;
849             icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
850         } else icdrf = CDRF_DODEFAULT;
851         if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
852             TRACKBAR_DrawTics (infoPtr, hdc, dwStyle);
853             if (icdrf & CDRF_NOTIFYPOSTPAINT)
854                 notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
855         }
856     }
857     
858     /* draw thumb */
859     if (!(dwStyle & TBS_NOTHUMB)) {
860         if (gcdrf & CDRF_NOTIFYITEMDRAW) {
861             nmcd.dwItemSpec = TBCD_THUMB;
862             nmcd.uItemState = infoPtr->flags & TB_DRAG_MODE ? CDIS_HOT : CDIS_DEFAULT;
863             nmcd.rc = infoPtr->rcThumb;
864             icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
865         } else icdrf = CDRF_DODEFAULT;
866         if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
867             TRACKBAR_DrawThumb(infoPtr, hdc, dwStyle);
868             if (icdrf & CDRF_NOTIFYPOSTPAINT)
869                 notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
870         }
871     }
872
873     /* draw focus rectangle */
874     if (infoPtr->bFocussed) {
875         DrawFocusRect(hdc, &rcClient);
876     }
877
878     /* finish up the painting */
879     if (gcdrf & CDRF_NOTIFYPOSTPAINT)
880         notify_customdraw(infoPtr, &nmcd, CDDS_POSTPAINT);
881     
882 cleanup:
883     /* cleanup, if we rendered offscreen */
884     if (hdc != hdcDst) {
885         BitBlt(hdcDst, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY);
886         SelectObject(hdc, hOldBmp);
887         DeleteObject(hOffScreenBmp);
888         DeleteObject(hdc);
889     }
890 }
891
892
893 static void
894 TRACKBAR_AlignBuddies (TRACKBAR_INFO *infoPtr)
895 {
896     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
897     HWND hwndParent = GetParent (infoPtr->hwndSelf);
898     RECT rcSelf, rcBuddy;
899     INT x, y;
900
901     GetWindowRect (infoPtr->hwndSelf, &rcSelf);
902     MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcSelf, 2);
903
904     /* align buddy left or above */
905     if (infoPtr->hwndBuddyLA) {
906         GetWindowRect (infoPtr->hwndBuddyLA, &rcBuddy);
907         MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcBuddy, 2);
908
909         if (dwStyle & TBS_VERT) {
910             x = (infoPtr->rcChannel.right + infoPtr->rcChannel.left) / 2 -
911                 (rcBuddy.right - rcBuddy.left) / 2 + rcSelf.left;
912             y = rcSelf.top - (rcBuddy.bottom - rcBuddy.top);
913         }
914         else {
915             x = rcSelf.left - (rcBuddy.right - rcBuddy.left);
916             y = (infoPtr->rcChannel.bottom + infoPtr->rcChannel.top) / 2 -
917                 (rcBuddy.bottom - rcBuddy.top) / 2 + rcSelf.top;
918         }
919
920         SetWindowPos (infoPtr->hwndBuddyLA, 0, x, y, 0, 0,
921                       SWP_NOZORDER | SWP_NOSIZE);
922     }
923
924
925     /* align buddy right or below */
926     if (infoPtr->hwndBuddyRB) {
927         GetWindowRect (infoPtr->hwndBuddyRB, &rcBuddy);
928         MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcBuddy, 2);
929
930         if (dwStyle & TBS_VERT) {
931             x = (infoPtr->rcChannel.right + infoPtr->rcChannel.left) / 2 -
932                 (rcBuddy.right - rcBuddy.left) / 2 + rcSelf.left;
933             y = rcSelf.bottom;
934         }
935         else {
936             x = rcSelf.right;
937             y = (infoPtr->rcChannel.bottom + infoPtr->rcChannel.top) / 2 -
938                 (rcBuddy.bottom - rcBuddy.top) / 2 + rcSelf.top;
939         }
940         SetWindowPos (infoPtr->hwndBuddyRB, 0, x, y, 0, 0,
941                       SWP_NOZORDER | SWP_NOSIZE);
942     }
943 }
944
945
946 static LRESULT
947 TRACKBAR_ClearSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
948 {
949     infoPtr->lSelMin = 0;
950     infoPtr->lSelMax = 0;
951     infoPtr->flags |= TB_SELECTIONCHANGED;
952
953     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
954
955     return 0;
956 }
957
958
959 static LRESULT
960 TRACKBAR_ClearTics (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
961 {
962     if (infoPtr->tics) {
963         Free (infoPtr->tics);
964         infoPtr->tics = NULL;
965         infoPtr->uNumTics = 0;
966     }
967
968     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
969
970     return 0;
971 }
972
973
974 static LRESULT inline
975 TRACKBAR_GetChannelRect (TRACKBAR_INFO *infoPtr, LPRECT lprc)
976 {
977     if (lprc == NULL) return 0;
978
979     lprc->left   = infoPtr->rcChannel.left;
980     lprc->right  = infoPtr->rcChannel.right;
981     lprc->bottom = infoPtr->rcChannel.bottom;
982     lprc->top    = infoPtr->rcChannel.top;
983
984     return 0;
985 }
986
987
988 static LONG inline
989 TRACKBAR_GetNumTics (TRACKBAR_INFO *infoPtr)
990 {
991     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_NOTICKS)
992         return 0;
993
994     return infoPtr->uNumTics + 2;
995 }
996
997
998 static int comp_tics(const void *ap, const void *bp)
999 {
1000     DWORD a = *((DWORD *)ap);
1001     DWORD b = *((DWORD *)bp);
1002
1003     TRACE("(a=%ld, b=%ld)\n", a, b);
1004     if (a < b) return -1;
1005     if (a > b) return 1;
1006     return 0;
1007 }
1008
1009
1010 static LONG inline
1011 TRACKBAR_GetTic (TRACKBAR_INFO *infoPtr, INT iTic)
1012 {
1013     if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics)
1014         return -1;
1015
1016     qsort(infoPtr->tics, infoPtr->uNumTics, sizeof(DWORD), comp_tics);
1017     return infoPtr->tics[iTic];
1018 }
1019
1020
1021 static LONG inline
1022 TRACKBAR_GetTicPos (TRACKBAR_INFO *infoPtr, INT iTic)
1023 {
1024     LONG range, width, pos, tic;
1025     int offsetthumb;
1026
1027     if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics)
1028         return -1;
1029
1030     tic   = TRACKBAR_GetTic (infoPtr, iTic);
1031     range = infoPtr->lRangeMax - infoPtr->lRangeMin;
1032     if (range <= 0) range = 1;
1033     offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2;
1034     width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - offsetthumb*2;
1035     pos   = infoPtr->rcChannel.left + offsetthumb + (width * tic) / range;
1036
1037     return pos;
1038 }
1039
1040
1041 static HWND
1042 TRACKBAR_SetBuddy (TRACKBAR_INFO *infoPtr, BOOL fLocation, HWND hwndBuddy)
1043 {
1044     HWND hwndTemp;
1045
1046     if (fLocation) {
1047         /* buddy is left or above */
1048         hwndTemp = infoPtr->hwndBuddyLA;
1049         infoPtr->hwndBuddyLA = hwndBuddy;
1050     }
1051     else {
1052         /* buddy is right or below */
1053         hwndTemp = infoPtr->hwndBuddyRB;
1054         infoPtr->hwndBuddyRB = hwndBuddy;
1055     }
1056
1057     TRACKBAR_AlignBuddies (infoPtr);
1058
1059     return hwndTemp;
1060 }
1061
1062
1063 static LONG inline
1064 TRACKBAR_SetLineSize (TRACKBAR_INFO *infoPtr, LONG lLineSize)
1065 {
1066     LONG lTemp = infoPtr->lLineSize;
1067
1068     infoPtr->lLineSize = lLineSize;
1069
1070     return lTemp;
1071 }
1072
1073
1074 static LONG inline
1075 TRACKBAR_SetPageSize (TRACKBAR_INFO *infoPtr, LONG lPageSize)
1076 {
1077     LONG lTemp = infoPtr->lPageSize;
1078
1079     infoPtr->lPageSize = lPageSize;
1080
1081     return lTemp;
1082 }
1083
1084
1085 static LRESULT inline
1086 TRACKBAR_SetPos (TRACKBAR_INFO *infoPtr, BOOL fPosition, LONG lPosition)
1087 {
1088     LONG oldPos = infoPtr->lPos;
1089     infoPtr->lPos = lPosition;
1090
1091     if (infoPtr->lPos < infoPtr->lRangeMin)
1092         infoPtr->lPos = infoPtr->lRangeMin;
1093
1094     if (infoPtr->lPos > infoPtr->lRangeMax)
1095         infoPtr->lPos = infoPtr->lRangeMax;
1096     infoPtr->flags |= TB_THUMBPOSCHANGED;
1097
1098     if (fPosition) TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition);
1099
1100     return 0;
1101 }
1102
1103
1104 static LRESULT inline
1105 TRACKBAR_SetRange (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lRange)
1106 {
1107     infoPtr->lRangeMin = (SHORT)LOWORD(lRange);
1108     infoPtr->lRangeMax = (SHORT)HIWORD(lRange);
1109
1110     if (infoPtr->lPos < infoPtr->lRangeMin) {
1111         infoPtr->lPos = infoPtr->lRangeMin;
1112         infoPtr->flags |= TB_THUMBPOSCHANGED;
1113     }
1114
1115     if (infoPtr->lPos > infoPtr->lRangeMax) {
1116         infoPtr->lPos = infoPtr->lRangeMax;
1117         infoPtr->flags |= TB_THUMBPOSCHANGED;
1118     }
1119
1120     infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
1121     if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
1122
1123     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1124
1125     return 0;
1126 }
1127
1128
1129 static LRESULT inline
1130 TRACKBAR_SetRangeMax (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMax)
1131 {
1132     infoPtr->lRangeMax = lMax;
1133     if (infoPtr->lPos > infoPtr->lRangeMax) {
1134         infoPtr->lPos = infoPtr->lRangeMax;
1135         infoPtr->flags |= TB_THUMBPOSCHANGED;
1136     }
1137
1138     infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
1139     if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
1140
1141     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1142
1143     return 0;
1144 }
1145
1146
1147 static LRESULT inline
1148 TRACKBAR_SetRangeMin (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMin)
1149 {
1150     infoPtr->lRangeMin = lMin;
1151     if (infoPtr->lPos < infoPtr->lRangeMin) {
1152         infoPtr->lPos = infoPtr->lRangeMin;
1153         infoPtr->flags |= TB_THUMBPOSCHANGED;
1154     }
1155
1156     infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
1157     if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
1158
1159     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1160
1161     return 0;
1162 }
1163
1164
1165 static LRESULT inline
1166 TRACKBAR_SetSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lSel)
1167 {
1168     if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE)
1169         return 0;
1170
1171     infoPtr->lSelMin = (SHORT)LOWORD(lSel);
1172     infoPtr->lSelMax = (SHORT)HIWORD(lSel);
1173     infoPtr->flags |= TB_SELECTIONCHANGED;
1174
1175     if (infoPtr->lSelMin < infoPtr->lRangeMin)
1176         infoPtr->lSelMin = infoPtr->lRangeMin;
1177     if (infoPtr->lSelMax > infoPtr->lRangeMax)
1178         infoPtr->lSelMax = infoPtr->lRangeMax;
1179
1180     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1181
1182     return 0;
1183 }
1184
1185
1186 static LRESULT inline
1187 TRACKBAR_SetSelEnd (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lEnd)
1188 {
1189     if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE)
1190         return 0;
1191
1192     infoPtr->lSelMax = lEnd;
1193     infoPtr->flags |= TB_SELECTIONCHANGED;
1194
1195     if (infoPtr->lSelMax > infoPtr->lRangeMax)
1196         infoPtr->lSelMax = infoPtr->lRangeMax;
1197
1198     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1199
1200     return 0;
1201 }
1202
1203
1204 static LRESULT inline
1205 TRACKBAR_SetSelStart (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lStart)
1206 {
1207     if (!GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE)
1208         return 0;
1209
1210     infoPtr->lSelMin = lStart;
1211     infoPtr->flags  |=TB_SELECTIONCHANGED;
1212
1213     if (infoPtr->lSelMin < infoPtr->lRangeMin)
1214         infoPtr->lSelMin = infoPtr->lRangeMin;
1215
1216     if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
1217
1218     return 0;
1219 }
1220
1221
1222 static LRESULT inline
1223 TRACKBAR_SetThumbLength (TRACKBAR_INFO *infoPtr, UINT iLength)
1224 {
1225     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_FIXEDLENGTH) {
1226         infoPtr->uThumbLen = iLength;
1227         infoPtr->flags |= TB_THUMBSIZECHANGED;
1228         InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
1229     }
1230
1231     return 0;
1232 }
1233
1234
1235 static LRESULT inline
1236 TRACKBAR_SetTic (TRACKBAR_INFO *infoPtr, LONG lPos)
1237 {
1238     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS)
1239         return FALSE;
1240
1241     if ((lPos < infoPtr->lRangeMin) || (lPos> infoPtr->lRangeMax))
1242         return FALSE;
1243
1244     TRACE("lPos=%ld\n", lPos);
1245
1246     infoPtr->uNumTics++;
1247     infoPtr->tics=ReAlloc( infoPtr->tics,
1248                                     (infoPtr->uNumTics)*sizeof (DWORD));
1249     if (!infoPtr->tics) {
1250         infoPtr->uNumTics = 0;
1251         notify(infoPtr, NM_OUTOFMEMORY);
1252         return FALSE;
1253     }
1254     infoPtr->tics[infoPtr->uNumTics-1] = lPos;
1255
1256     TRACKBAR_InvalidateAll(infoPtr);
1257
1258     return TRUE;
1259 }
1260
1261
1262 static LRESULT inline
1263 TRACKBAR_SetTicFreq (TRACKBAR_INFO *infoPtr, WORD wFreq)
1264 {
1265     if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS) {
1266         infoPtr->uTicFreq = wFreq;
1267         TRACKBAR_RecalculateTics (infoPtr);
1268         TRACKBAR_InvalidateAll(infoPtr);
1269     }
1270
1271     return 0;
1272 }
1273
1274
1275 static INT inline
1276 TRACKBAR_SetTipSide (TRACKBAR_INFO *infoPtr, INT fLocation)
1277 {
1278     INT fTemp = infoPtr->fLocation;
1279
1280     infoPtr->fLocation = fLocation;
1281
1282     return fTemp;
1283 }
1284
1285
1286 static LRESULT inline
1287 TRACKBAR_SetToolTips (TRACKBAR_INFO *infoPtr, HWND hwndTT)
1288 {
1289     infoPtr->hwndToolTip = hwndTT;
1290
1291     return 0;
1292 }
1293
1294
1295 static BOOL inline
1296 TRACKBAR_SetUnicodeFormat (TRACKBAR_INFO *infoPtr, BOOL fUnicode)
1297 {
1298     BOOL bTemp = infoPtr->bUnicode;
1299
1300     infoPtr->bUnicode = fUnicode;
1301
1302     return bTemp;
1303 }
1304
1305
1306 static LRESULT
1307 TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr)
1308 {
1309     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
1310     RECT rect;
1311     int clientWidth, clientMetric;
1312
1313     /* initial thumb length */
1314     clientMetric = (dwStyle & TBS_ENABLESELRANGE) ? 23 : 21;
1315     GetClientRect(infoPtr->hwndSelf,&rect);
1316     if (dwStyle & TBS_VERT) {
1317         clientWidth = rect.right - rect.left;
1318     } else {
1319         clientWidth = rect.bottom - rect.top;
1320     }
1321     if (clientWidth >= clientMetric)
1322         infoPtr->uThumbLen = clientMetric;
1323     else
1324         infoPtr->uThumbLen = clientWidth > 9 ? clientWidth - 6 : 4;
1325
1326     TRACKBAR_CalcChannel (infoPtr);
1327     TRACKBAR_UpdateThumb (infoPtr);
1328     infoPtr->flags &= ~TB_SELECTIONCHANGED;
1329
1330     return 0;
1331 }
1332
1333
1334 static LRESULT
1335 TRACKBAR_Create (HWND hwnd, LPCREATESTRUCTW lpcs)
1336 {
1337     TRACKBAR_INFO *infoPtr;
1338     DWORD oldStyle, newStyle;
1339
1340     infoPtr = (TRACKBAR_INFO *)Alloc (sizeof(TRACKBAR_INFO));
1341     if (!infoPtr) return -1;
1342     SetWindowLongW (hwnd, 0, (DWORD)infoPtr);
1343
1344     /* set default values */
1345     infoPtr->hwndSelf  = hwnd;
1346     infoPtr->lRangeMin = 0;
1347     infoPtr->lRangeMax = 100;
1348     infoPtr->lLineSize = 1;
1349     infoPtr->lPageSize = 20;
1350     infoPtr->lSelMin   = 0;
1351     infoPtr->lSelMax   = 0;
1352     infoPtr->lPos      = 0;
1353     infoPtr->fLocation = -1;
1354     infoPtr->uNumTics  = 0;    /* start and end tic are not included in count*/
1355     infoPtr->uTicFreq  = 1;
1356     infoPtr->tics      = NULL;
1357     infoPtr->hwndNotify= lpcs->hwndParent;
1358
1359     TRACKBAR_InitializeThumb (infoPtr);
1360
1361     oldStyle = newStyle = GetWindowLongW (hwnd, GWL_STYLE);
1362     if (oldStyle & TBS_VERT) {
1363         if (! (oldStyle & (TBS_LEFT | TBS_RIGHT | TBS_BOTH)) )
1364             newStyle |= TBS_RIGHT;
1365     } else {
1366         if (! (oldStyle & (TBS_TOP | TBS_BOTTOM | TBS_BOTH)) )
1367             newStyle |= TBS_BOTTOM;
1368     }
1369     if (newStyle != oldStyle)
1370         SetWindowLongW (hwnd, GWL_STYLE, newStyle);
1371
1372     /* Create tooltip control */
1373     if (newStyle & TBS_TOOLTIPS) {
1374
1375         infoPtr->hwndToolTip =
1376             CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, 0,
1377                              CW_USEDEFAULT, CW_USEDEFAULT,
1378                              CW_USEDEFAULT, CW_USEDEFAULT,
1379                              hwnd, 0, 0, 0);
1380
1381         if (infoPtr->hwndToolTip) {
1382             TTTOOLINFOW ti;         
1383             ZeroMemory (&ti, sizeof(ti));
1384             ti.cbSize   = sizeof(ti);
1385             ti.uFlags   = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
1386             ti.hwnd     = hwnd;
1387
1388             SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
1389          }
1390     }
1391
1392     return 0;
1393 }
1394
1395
1396 static LRESULT
1397 TRACKBAR_Destroy (TRACKBAR_INFO *infoPtr)
1398 {
1399     /* delete tooltip control */
1400     if (infoPtr->hwndToolTip)
1401         DestroyWindow (infoPtr->hwndToolTip);
1402
1403     Free (infoPtr);
1404     SetWindowLongW (infoPtr->hwndSelf, 0, 0);
1405     return 0;
1406 }
1407
1408
1409 static LRESULT
1410 TRACKBAR_KillFocus (TRACKBAR_INFO *infoPtr, HWND hwndGetFocus)
1411 {
1412     TRACE("\n");
1413     infoPtr->bFocussed = FALSE;
1414     TRACKBAR_InvalidateAll(infoPtr);
1415
1416     return 0;
1417 }
1418
1419 static LRESULT
1420 TRACKBAR_LButtonDown (TRACKBAR_INFO *infoPtr, DWORD fwKeys, POINTS pts)
1421 {
1422     POINT clickPoint = { pts.x, pts.y };
1423
1424     SetFocus(infoPtr->hwndSelf);
1425
1426     if (PtInRect(&infoPtr->rcThumb, clickPoint)) {
1427         infoPtr->flags |= TB_DRAG_MODE;
1428         SetCapture (infoPtr->hwndSelf);
1429         TRACKBAR_UpdateToolTip (infoPtr);
1430         TRACKBAR_ActivateToolTip (infoPtr, TRUE);
1431         TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
1432     } else {
1433         LONG dir = TRACKBAR_GetAutoPageDirection(infoPtr, clickPoint);
1434         if (dir == 0) return 0;
1435         infoPtr->flags |= (dir < 0) ? TB_AUTO_PAGE_LEFT : TB_AUTO_PAGE_RIGHT;
1436         TRACKBAR_AutoPage (infoPtr, clickPoint);
1437         SetCapture (infoPtr->hwndSelf);
1438         SetTimer(infoPtr->hwndSelf, TB_REFRESH_TIMER, TB_REFRESH_DELAY, 0);
1439     }
1440
1441     return 0;
1442 }
1443
1444
1445 static LRESULT
1446 TRACKBAR_LButtonUp (TRACKBAR_INFO *infoPtr, DWORD fwKeys, POINTS pts)
1447 {
1448     if (infoPtr->flags & TB_DRAG_MODE) {
1449         notify_with_scroll (infoPtr, TB_THUMBPOSITION | (infoPtr->lPos<<16));
1450         notify_with_scroll (infoPtr, TB_ENDTRACK);
1451         infoPtr->flags &= ~TB_DRAG_MODE;
1452         ReleaseCapture ();
1453         notify(infoPtr, NM_RELEASEDCAPTURE);
1454         TRACKBAR_ActivateToolTip(infoPtr, FALSE);
1455         TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
1456     }
1457     if (infoPtr->flags & TB_AUTO_PAGE) {
1458         KillTimer (infoPtr->hwndSelf, TB_REFRESH_TIMER);
1459         infoPtr->flags &= ~TB_AUTO_PAGE;
1460         notify_with_scroll (infoPtr, TB_ENDTRACK);
1461         ReleaseCapture ();
1462         notify(infoPtr, NM_RELEASEDCAPTURE);
1463     }
1464
1465     return 0;
1466 }
1467
1468
1469 static LRESULT
1470 TRACKBAR_CaptureChanged (TRACKBAR_INFO *infoPtr)
1471 {
1472     notify_with_scroll (infoPtr, TB_ENDTRACK);
1473     return 0;
1474 }
1475
1476
1477 static LRESULT
1478 TRACKBAR_Paint (TRACKBAR_INFO *infoPtr, HDC hdc)
1479 {
1480     if (hdc) {
1481         TRACKBAR_Refresh(infoPtr, hdc);
1482     } else {
1483         PAINTSTRUCT ps;
1484         hdc = BeginPaint (infoPtr->hwndSelf, &ps);
1485         TRACKBAR_Refresh (infoPtr, hdc);
1486         EndPaint (infoPtr->hwndSelf, &ps);
1487     }
1488
1489     return 0;
1490 }
1491
1492
1493 static LRESULT
1494 TRACKBAR_SetFocus (TRACKBAR_INFO *infoPtr, HWND hwndLoseFocus)
1495 {
1496     TRACE("\n");
1497     infoPtr->bFocussed = TRUE;
1498     TRACKBAR_InvalidateAll(infoPtr);
1499
1500     return 0;
1501 }
1502
1503
1504 static LRESULT
1505 TRACKBAR_Size (TRACKBAR_INFO *infoPtr, DWORD fwSizeType, INT nWidth, INT nHeight)
1506 {
1507     TRACKBAR_InitializeThumb (infoPtr);
1508     TRACKBAR_AlignBuddies (infoPtr);
1509
1510     return 0;
1511 }
1512
1513
1514 static LRESULT
1515 TRACKBAR_Timer (TRACKBAR_INFO *infoPtr, INT wTimerID, TIMERPROC *tmrpc)
1516 {
1517     if (infoPtr->flags & TB_AUTO_PAGE) {
1518         POINT pt;
1519         if (GetCursorPos(&pt))
1520             if (ScreenToClient(infoPtr->hwndSelf, &pt))
1521                 TRACKBAR_AutoPage(infoPtr, pt);
1522     }
1523     return 0;
1524 }
1525
1526
1527 static LRESULT
1528 TRACKBAR_MouseMove (TRACKBAR_INFO *infoPtr, DWORD fwKeys, POINTS pts)
1529 {
1530     DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
1531     INT clickPlace = (dwStyle & TBS_VERT) ? pts.y : pts.x;
1532     LONG dragPos, oldPos = infoPtr->lPos;
1533
1534     TRACE("(x=%d. y=%d)\n", pts.x, pts.y);
1535
1536     if (infoPtr->flags & TB_AUTO_PAGE) {
1537         POINT pt;
1538         POINTSTOPOINT(pt, pts);
1539         TRACKBAR_AutoPage (infoPtr, pt);
1540         return TRUE;
1541     }
1542
1543     if (!(infoPtr->flags & TB_DRAG_MODE)) return TRUE;
1544
1545     dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace,
1546                                                dwStyle & TBS_VERT);
1547     if (dragPos == oldPos) return TRUE;
1548
1549     infoPtr->lPos = dragPos;
1550
1551     infoPtr->flags |= TB_THUMBPOSCHANGED;
1552     notify_with_scroll (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16));
1553
1554
1555     TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos);
1556     UpdateWindow (infoPtr->hwndSelf);
1557
1558     return TRUE;
1559 }
1560
1561 static BOOL
1562 TRACKBAR_KeyDown (TRACKBAR_INFO *infoPtr, INT nVirtKey, DWORD lKeyData)
1563 {
1564     DWORD style = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
1565     BOOL downIsLeft = style & TBS_DOWNISLEFT;
1566     BOOL vert = style & TBS_VERT;
1567     LONG pos = infoPtr->lPos;
1568
1569     TRACE("%x\n", nVirtKey);
1570
1571     switch (nVirtKey) {
1572     case VK_UP:
1573         if (!vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
1574         else TRACKBAR_LineUp(infoPtr);
1575         break;
1576     case VK_LEFT:
1577         if (vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
1578         else TRACKBAR_LineUp(infoPtr);
1579         break;
1580     case VK_DOWN:
1581         if (!vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
1582         else TRACKBAR_LineDown(infoPtr);
1583         break;
1584     case VK_RIGHT:
1585         if (vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
1586         else TRACKBAR_LineDown(infoPtr);
1587         break;
1588     case VK_NEXT:
1589         if (!vert && downIsLeft) TRACKBAR_PageUp(infoPtr);
1590         else TRACKBAR_PageDown(infoPtr);
1591         break;
1592     case VK_PRIOR:
1593         if (!vert && downIsLeft) TRACKBAR_PageDown(infoPtr);
1594         else TRACKBAR_PageUp(infoPtr);
1595         break;
1596     case VK_HOME:
1597         if (infoPtr->lPos == infoPtr->lRangeMin) return FALSE;
1598         infoPtr->lPos = infoPtr->lRangeMin;
1599         notify_with_scroll (infoPtr, TB_TOP);
1600         break;
1601     case VK_END:
1602         if (infoPtr->lPos == infoPtr->lRangeMax) return FALSE;
1603         infoPtr->lPos = infoPtr->lRangeMax;
1604         notify_with_scroll (infoPtr, TB_BOTTOM);
1605         break;
1606     }
1607
1608     if (pos != infoPtr->lPos) {
1609         infoPtr->flags |=TB_THUMBPOSCHANGED;
1610         TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos);
1611     }
1612
1613     return TRUE;
1614 }
1615
1616
1617 static BOOL inline
1618 TRACKBAR_KeyUp (TRACKBAR_INFO *infoPtr, INT nVirtKey, DWORD lKeyData)
1619 {
1620     switch (nVirtKey) {
1621     case VK_LEFT:
1622     case VK_UP:
1623     case VK_RIGHT:
1624     case VK_DOWN:
1625     case VK_NEXT:
1626     case VK_PRIOR:
1627     case VK_HOME:
1628     case VK_END:
1629         notify_with_scroll (infoPtr, TB_ENDTRACK);
1630     }
1631     return TRUE;
1632 }
1633
1634
1635 static LRESULT WINAPI
1636 TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1637 {
1638     TRACKBAR_INFO *infoPtr = (TRACKBAR_INFO *)GetWindowLongW (hwnd, 0);
1639
1640     TRACE("hwnd=%p msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam);
1641
1642     if (!infoPtr && (uMsg != WM_CREATE))
1643         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
1644
1645     switch (uMsg)
1646     {
1647     case TBM_CLEARSEL:
1648         return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam);
1649
1650     case TBM_CLEARTICS:
1651         return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam);
1652
1653     case TBM_GETBUDDY:
1654         return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB);
1655
1656     case TBM_GETCHANNELRECT:
1657         return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam);
1658
1659     case TBM_GETLINESIZE:
1660         return infoPtr->lLineSize;
1661
1662     case TBM_GETNUMTICS:
1663         return TRACKBAR_GetNumTics (infoPtr);
1664
1665     case TBM_GETPAGESIZE:
1666         return infoPtr->lPageSize;
1667
1668     case TBM_GETPOS:
1669         return infoPtr->lPos;
1670
1671     case TBM_GETPTICS:
1672         return (LRESULT)infoPtr->tics;
1673
1674     case TBM_GETRANGEMAX:
1675         return infoPtr->lRangeMax;
1676
1677     case TBM_GETRANGEMIN:
1678         return infoPtr->lRangeMin;
1679
1680     case TBM_GETSELEND:
1681         return infoPtr->lSelMax;
1682
1683     case TBM_GETSELSTART:
1684         return infoPtr->lSelMin;
1685
1686     case TBM_GETTHUMBLENGTH:
1687         return infoPtr->uThumbLen;
1688
1689     case TBM_GETTHUMBRECT:
1690         return CopyRect((LPRECT)lParam, &infoPtr->rcThumb);
1691
1692     case TBM_GETTIC:
1693         return TRACKBAR_GetTic (infoPtr, (INT)wParam);
1694
1695     case TBM_GETTICPOS:
1696         return TRACKBAR_GetTicPos (infoPtr, (INT)wParam);
1697
1698     case TBM_GETTOOLTIPS:
1699         return (LRESULT)infoPtr->hwndToolTip;
1700
1701     case TBM_GETUNICODEFORMAT:
1702         return infoPtr->bUnicode;
1703
1704     case TBM_SETBUDDY:
1705         return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam);
1706
1707     case TBM_SETLINESIZE:
1708         return TRACKBAR_SetLineSize (infoPtr, (LONG)lParam);
1709
1710     case TBM_SETPAGESIZE:
1711         return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam);
1712
1713     case TBM_SETPOS:
1714         return TRACKBAR_SetPos (infoPtr, (BOOL)wParam, (LONG)lParam);
1715
1716     case TBM_SETRANGE:
1717         return TRACKBAR_SetRange (infoPtr, (BOOL)wParam, (LONG)lParam);
1718
1719     case TBM_SETRANGEMAX:
1720         return TRACKBAR_SetRangeMax (infoPtr, (BOOL)wParam, (LONG)lParam);
1721
1722     case TBM_SETRANGEMIN:
1723         return TRACKBAR_SetRangeMin (infoPtr, (BOOL)wParam, (LONG)lParam);
1724
1725     case TBM_SETSEL:
1726         return TRACKBAR_SetSel (infoPtr, (BOOL)wParam, (LONG)lParam);
1727
1728     case TBM_SETSELEND:
1729         return TRACKBAR_SetSelEnd (infoPtr, (BOOL)wParam, (LONG)lParam);
1730
1731     case TBM_SETSELSTART:
1732         return TRACKBAR_SetSelStart (infoPtr, (BOOL)wParam, (LONG)lParam);
1733
1734     case TBM_SETTHUMBLENGTH:
1735         return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam);
1736
1737     case TBM_SETTIC:
1738         return TRACKBAR_SetTic (infoPtr, (LONG)lParam);
1739
1740     case TBM_SETTICFREQ:
1741         return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam);
1742
1743     case TBM_SETTIPSIDE:
1744         return TRACKBAR_SetTipSide (infoPtr, (INT)wParam);
1745
1746     case TBM_SETTOOLTIPS:
1747         return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam);
1748
1749     case TBM_SETUNICODEFORMAT:
1750         return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam);
1751
1752
1753     case WM_CAPTURECHANGED:
1754         return TRACKBAR_CaptureChanged (infoPtr);
1755
1756     case WM_CREATE:
1757         return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam);
1758
1759     case WM_DESTROY:
1760         return TRACKBAR_Destroy (infoPtr);
1761
1762 /*      case WM_ENABLE: */
1763
1764     case WM_ERASEBKGND:
1765         return 0;
1766
1767     case WM_GETDLGCODE:
1768         return DLGC_WANTARROWS;
1769
1770     case WM_KEYDOWN:
1771         return TRACKBAR_KeyDown (infoPtr, (INT)wParam, (DWORD)lParam);
1772
1773     case WM_KEYUP:
1774         return TRACKBAR_KeyUp (infoPtr, (INT)wParam, (DWORD)lParam);
1775
1776     case WM_KILLFOCUS:
1777         return TRACKBAR_KillFocus (infoPtr, (HWND)wParam);
1778
1779     case WM_LBUTTONDOWN:
1780         return TRACKBAR_LButtonDown (infoPtr, wParam, MAKEPOINTS(lParam));
1781
1782     case WM_LBUTTONUP:
1783         return TRACKBAR_LButtonUp (infoPtr, wParam, MAKEPOINTS(lParam));
1784
1785     case WM_MOUSEMOVE:
1786         return TRACKBAR_MouseMove (infoPtr, wParam, MAKEPOINTS(lParam));
1787
1788     case WM_PAINT:
1789         return TRACKBAR_Paint (infoPtr, (HDC)wParam);
1790
1791     case WM_SETFOCUS:
1792         return TRACKBAR_SetFocus (infoPtr, (HWND)wParam);
1793
1794     case WM_SIZE:
1795         return TRACKBAR_Size (infoPtr, wParam, LOWORD(lParam), HIWORD(lParam));
1796
1797     case WM_TIMER:
1798         return TRACKBAR_Timer (infoPtr, (INT)wParam, (TIMERPROC *)lParam);
1799
1800     case WM_WININICHANGE:
1801         return TRACKBAR_InitializeThumb (infoPtr);
1802
1803     default:
1804         if ((uMsg >= WM_USER) && (uMsg < WM_APP))
1805             ERR("unknown msg %04x wp=%08x lp=%08lx\n", uMsg, wParam, lParam);
1806         return DefWindowProcW (hwnd, uMsg, wParam, lParam);
1807     }
1808     return 0;
1809 }
1810
1811
1812 void TRACKBAR_Register (void)
1813 {
1814     WNDCLASSW wndClass;
1815
1816     ZeroMemory (&wndClass, sizeof(WNDCLASSW));
1817     wndClass.style         = CS_GLOBALCLASS;
1818     wndClass.lpfnWndProc   = (WNDPROC)TRACKBAR_WindowProc;
1819     wndClass.cbClsExtra    = 0;
1820     wndClass.cbWndExtra    = sizeof(TRACKBAR_INFO *);
1821     wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
1822     wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
1823     wndClass.lpszClassName = TRACKBAR_CLASSW;
1824
1825     RegisterClassW (&wndClass);
1826 }
1827
1828
1829 void TRACKBAR_Unregister (void)
1830 {
1831     UnregisterClassW (TRACKBAR_CLASSW, NULL);
1832 }