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