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