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