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