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