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