Like the AUTORADIOBUTTON, the parent of a RADIOBUTTON style button
[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     pos+=infoPtr->nRangeMin;
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)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     SetWindowLongA (hwnd, 0, 0);
1122     return 0;
1123 }
1124
1125
1126 static LRESULT
1127 TRACKBAR_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
1128 {
1129     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
1130
1131     TRACE("\n");
1132
1133     infoPtr->bFocus = FALSE;
1134     infoPtr->flags &= ~TB_DRAG_MODE;
1135
1136     InvalidateRect (hwnd, NULL, FALSE);
1137
1138     return 0;
1139 }
1140
1141
1142 static LRESULT
1143 TRACKBAR_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1144 {
1145     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
1146     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1147     int clickPlace,prevPos,vertical;
1148     DOUBLE clickPos;
1149
1150     SetFocus (hwnd);
1151
1152     vertical = (dwStyle & TBS_VERT) ? 1 : 0;
1153     if (vertical)
1154         clickPlace=(INT)HIWORD(lParam);
1155     else
1156         clickPlace=(INT)LOWORD(lParam);
1157
1158     if ((vertical && 
1159          (clickPlace>infoPtr->rcThumb.top) && 
1160          (clickPlace<infoPtr->rcThumb.bottom))   ||
1161         (!vertical && 
1162          (clickPlace>infoPtr->rcThumb.left) && 
1163          (clickPlace<infoPtr->rcThumb.right))) {
1164         infoPtr->flags |= TB_DRAG_MODE;
1165         if (dwStyle & TBS_TOOLTIPS) {  /* enable tooltip */
1166             TTTOOLINFOA ti;
1167             POINT pt;
1168
1169             GetCursorPos (&pt);
1170             SendMessageA (infoPtr->hwndToolTip, TTM_TRACKPOSITION, 0,
1171                           (LPARAM)MAKELPARAM(pt.x, pt.y));
1172
1173             ti.cbSize   = sizeof(TTTOOLINFOA);
1174             ti.uId      = 0;
1175             ti.hwnd     = (UINT)hwnd;
1176
1177             infoPtr->flags |= TB_SHOW_TOOLTIP;
1178             SetCapture (hwnd);
1179             SendMessageA (infoPtr->hwndToolTip, TTM_TRACKACTIVATE, 
1180                           (WPARAM)TRUE, (LPARAM)&ti);
1181         }
1182         return 0;
1183     }
1184
1185     clickPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace, vertical);
1186     prevPos = infoPtr->nPos;
1187
1188     if (vertical ^ (clickPos < (int)prevPos)) {  /* similar to VK_NEXT */
1189         infoPtr->nPos += infoPtr->nPageSize;
1190         if (infoPtr->nPos > infoPtr->nRangeMax)
1191             infoPtr->nPos = infoPtr->nRangeMax;
1192         TRACKBAR_SendNotify (hwnd, TB_PAGEUP);  
1193     } else {
1194         infoPtr->nPos -= infoPtr->nPageSize;  /* similar to VK_PRIOR */
1195         if (infoPtr->nPos < infoPtr->nRangeMin)
1196             infoPtr->nPos = infoPtr->nRangeMin;
1197         TRACKBAR_SendNotify (hwnd, TB_PAGEDOWN);
1198     }
1199         
1200     if (prevPos!=infoPtr->nPos) {
1201         infoPtr->flags |= TB_THUMBPOSCHANGED;
1202         InvalidateRect (hwnd, NULL, FALSE);
1203     }
1204         
1205     return 0;
1206 }
1207
1208
1209 static LRESULT
1210 TRACKBAR_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
1211 {
1212     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
1213
1214     TRACKBAR_SendNotify (hwnd, TB_ENDTRACK);
1215
1216     if (infoPtr->flags & TB_DRAG_MODE)
1217     {
1218         infoPtr->flags &= ~TB_DRAG_MODE;
1219         ReleaseCapture ();
1220     }
1221
1222     if (GetWindowLongA (hwnd, GWL_STYLE) & TBS_TOOLTIPS) {  /* disable tooltip */
1223         TTTOOLINFOA ti;
1224
1225         ti.cbSize   = sizeof(TTTOOLINFOA);
1226         ti.uId      = 0;
1227         ti.hwnd     = (UINT)hwnd;
1228
1229         infoPtr->flags &= ~TB_SHOW_TOOLTIP;
1230         SendMessageA (infoPtr->hwndToolTip, TTM_TRACKACTIVATE,
1231                       (WPARAM)FALSE, (LPARAM)&ti);
1232     }
1233     
1234     InvalidateRect (hwnd, NULL, FALSE);
1235
1236     return 0;
1237 }
1238
1239
1240 static LRESULT
1241 TRACKBAR_CaptureChanged (HWND hwnd, WPARAM wParam, LPARAM lParam)
1242 {
1243     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
1244         
1245     if (infoPtr->flags & TB_DRAGPOSVALID) {
1246         infoPtr->nPos=infoPtr->dragPos;
1247         InvalidateRect (hwnd, NULL, FALSE);
1248     }
1249         
1250     infoPtr->flags &= ~ TB_DRAGPOSVALID;
1251
1252     TRACKBAR_SendNotify (hwnd, TB_ENDTRACK);
1253     return 0;
1254 }
1255
1256
1257 static LRESULT
1258 TRACKBAR_Paint (HWND hwnd, WPARAM wParam)
1259 {
1260     HDC hdc;
1261     PAINTSTRUCT ps;
1262
1263     hdc = wParam==0 ? BeginPaint (hwnd, &ps) : (HDC)wParam;
1264     TRACKBAR_Refresh (hwnd, hdc);
1265     if(!wParam)
1266         EndPaint (hwnd, &ps);
1267     return 0;
1268 }
1269
1270
1271 static LRESULT
1272 TRACKBAR_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam)
1273 {
1274     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
1275
1276     TRACE("\n");
1277     infoPtr->bFocus = TRUE;
1278
1279     InvalidateRect (hwnd, NULL, FALSE);
1280
1281     return 0;
1282 }
1283
1284
1285 static LRESULT
1286 TRACKBAR_Size (HWND hwnd, WPARAM wParam, LPARAM lParam)
1287 {
1288     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
1289
1290     TRACKBAR_CalcChannel (hwnd, infoPtr);
1291     TRACKBAR_AlignBuddies (hwnd, infoPtr);
1292
1293     return 0;
1294 }
1295
1296
1297 static BOOL
1298 TRACKBAR_SendNotify (HWND hwnd, UINT code)
1299 {
1300     TRACE("%x\n",code);
1301
1302     if (GetWindowLongA (hwnd, GWL_STYLE) & TBS_VERT) 
1303         return (BOOL) SendMessageA (GetParent (hwnd), 
1304                                     WM_VSCROLL, (WPARAM)code, (LPARAM)hwnd);
1305
1306     return (BOOL) SendMessageA (GetParent (hwnd), 
1307                                 WM_HSCROLL, (WPARAM)code, (LPARAM)hwnd);
1308 }
1309
1310
1311 static LRESULT
1312 TRACKBAR_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
1313 {
1314     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
1315     DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
1316     SHORT clickPlace;
1317     DOUBLE dragPos;
1318     char buf[80];
1319                         
1320     TRACE("%x\n",wParam);
1321
1322     if (dwStyle & TBS_VERT)
1323         clickPlace=(SHORT)HIWORD(lParam);
1324     else
1325         clickPlace=(SHORT)LOWORD(lParam);
1326
1327     if (!(infoPtr->flags & TB_DRAG_MODE))
1328         return TRUE;
1329
1330     SetCapture (hwnd);
1331     dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace, 
1332                                                dwStyle & TBS_VERT);
1333     if (dragPos > ((INT)dragPos) + 0.5)
1334         infoPtr->dragPos = dragPos + 1;
1335     else
1336         infoPtr->dragPos = dragPos;
1337
1338     infoPtr->flags |= TB_DRAGPOSVALID;
1339     TRACKBAR_SendNotify (hwnd, TB_THUMBTRACK | (infoPtr->nPos<<16));
1340
1341     if (infoPtr->flags & TB_SHOW_TOOLTIP) {
1342         POINT pt;
1343         TTTOOLINFOA ti;
1344         
1345         ti.cbSize = sizeof(TTTOOLINFOA);
1346         ti.hwnd = hwnd;
1347         ti.uId = 0;
1348         ti.hinst=0;
1349         sprintf (buf,"%d",infoPtr->nPos);
1350         ti.lpszText = (LPSTR) buf;
1351         GetCursorPos (&pt);
1352                 
1353         if (dwStyle & TBS_VERT) {
1354             SendMessageA (infoPtr->hwndToolTip, TTM_TRACKPOSITION, 
1355                           0, (LPARAM)MAKELPARAM(pt.x+5, pt.y+15));
1356         } else {
1357             SendMessageA (infoPtr->hwndToolTip, TTM_TRACKPOSITION, 
1358                           0, (LPARAM)MAKELPARAM(pt.x+15, pt.y+5));
1359         }
1360         SendMessageA (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTA,
1361                       0, (LPARAM)&ti);
1362     }
1363
1364     InvalidateRect (hwnd, NULL, FALSE);
1365     UpdateWindow (hwnd);
1366
1367     return TRUE;
1368 }
1369
1370
1371 static LRESULT
1372 TRACKBAR_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
1373 {
1374     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
1375     INT pos;
1376
1377     TRACE("%x\n",wParam);
1378
1379     pos=infoPtr->nPos;
1380     switch (wParam) {
1381     case VK_LEFT:
1382     case VK_UP: 
1383         if (infoPtr->nPos == infoPtr->nRangeMin) return FALSE;
1384         infoPtr->nPos -= infoPtr->nLineSize;
1385         if (infoPtr->nPos < infoPtr->nRangeMin) 
1386             infoPtr->nPos = infoPtr->nRangeMin;
1387         TRACKBAR_SendNotify (hwnd, TB_LINEUP);
1388         break;
1389     case VK_RIGHT:
1390     case VK_DOWN: 
1391         if (infoPtr->nPos == infoPtr->nRangeMax) return FALSE;
1392         infoPtr->nPos += infoPtr->nLineSize;
1393         if (infoPtr->nPos > infoPtr->nRangeMax) 
1394             infoPtr->nPos = infoPtr->nRangeMax;
1395         TRACKBAR_SendNotify (hwnd, TB_LINEDOWN);
1396         break;
1397     case VK_NEXT:
1398         if (infoPtr->nPos == infoPtr->nRangeMax) return FALSE;
1399         infoPtr->nPos += infoPtr->nPageSize;
1400         if (infoPtr->nPos > infoPtr->nRangeMax) 
1401             infoPtr->nPos = infoPtr->nRangeMax;
1402         TRACKBAR_SendNotify (hwnd, TB_PAGEUP);
1403         break;
1404     case VK_PRIOR:
1405         if (infoPtr->nPos == infoPtr->nRangeMin) return FALSE;
1406         infoPtr->nPos -= infoPtr->nPageSize;
1407         if (infoPtr->nPos < infoPtr->nRangeMin) 
1408             infoPtr->nPos = infoPtr->nRangeMin;
1409         TRACKBAR_SendNotify (hwnd, TB_PAGEDOWN);
1410         break;
1411     case VK_HOME: 
1412         if (infoPtr->nPos == infoPtr->nRangeMin) return FALSE;
1413         infoPtr->nPos = infoPtr->nRangeMin;
1414         TRACKBAR_SendNotify (hwnd, TB_TOP);
1415         break;
1416     case VK_END: 
1417         if (infoPtr->nPos == infoPtr->nRangeMax) return FALSE;
1418         infoPtr->nPos = infoPtr->nRangeMax;
1419         TRACKBAR_SendNotify (hwnd, TB_BOTTOM);
1420         break;
1421     }
1422
1423     if (pos!=infoPtr->nPos) { 
1424         infoPtr->flags |=TB_THUMBPOSCHANGED;
1425         InvalidateRect (hwnd, NULL, FALSE);
1426     }
1427
1428     return TRUE;
1429 }
1430
1431
1432 static LRESULT
1433 TRACKBAR_KeyUp (HWND hwnd, WPARAM wParam)
1434 {
1435     switch (wParam) {
1436     case VK_LEFT:
1437     case VK_UP: 
1438     case VK_RIGHT:
1439     case VK_DOWN: 
1440     case VK_NEXT:
1441     case VK_PRIOR:
1442     case VK_HOME: 
1443     case VK_END:
1444         TRACKBAR_SendNotify (hwnd, TB_ENDTRACK);
1445     }
1446     return TRUE;
1447 }
1448
1449
1450 static LRESULT WINAPI
1451 TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
1452 {
1453     TRACE("hwnd=%x msg=%x wparam=%x lparam=%lx\n", hwnd, uMsg, wParam, lParam);
1454     if (!TRACKBAR_GetInfoPtr (hwnd) && (uMsg != WM_CREATE))
1455         return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1456     switch (uMsg)
1457     {
1458     case TBM_CLEARSEL:
1459         return TRACKBAR_ClearSel (hwnd, wParam, lParam);
1460
1461     case TBM_CLEARTICS:
1462         return TRACKBAR_ClearTics (hwnd, wParam, lParam);
1463
1464     case TBM_GETBUDDY:
1465         return TRACKBAR_GetBuddy (hwnd, wParam, lParam);
1466
1467     case TBM_GETCHANNELRECT:
1468         return TRACKBAR_GetChannelRect (hwnd, wParam, lParam);
1469
1470     case TBM_GETLINESIZE:
1471         return TRACKBAR_GetLineSize (hwnd, wParam, lParam);
1472
1473     case TBM_GETNUMTICS:
1474         return TRACKBAR_GetNumTics (hwnd, wParam, lParam);
1475
1476     case TBM_GETPAGESIZE:
1477         return TRACKBAR_GetPageSize (hwnd, wParam, lParam);
1478
1479     case TBM_GETPOS:
1480         return TRACKBAR_GetPos (hwnd, wParam, lParam);
1481
1482     case TBM_GETPTICS:
1483         return TRACKBAR_GetPTics (hwnd);
1484
1485     case TBM_GETRANGEMAX:
1486         return TRACKBAR_GetRangeMax (hwnd, wParam, lParam);
1487
1488     case TBM_GETRANGEMIN:
1489         return TRACKBAR_GetRangeMin (hwnd, wParam, lParam);
1490
1491     case TBM_GETSELEND:
1492         return TRACKBAR_GetSelEnd (hwnd, wParam, lParam);
1493
1494     case TBM_GETSELSTART:
1495         return TRACKBAR_GetSelStart (hwnd, wParam, lParam);
1496
1497     case TBM_GETTHUMBLENGTH:
1498         return TRACKBAR_GetThumbLength (hwnd, wParam, lParam);
1499
1500     case TBM_GETTHUMBRECT:
1501         return TRACKBAR_GetThumbRect (hwnd, wParam, lParam);
1502
1503     case TBM_GETTIC:
1504         return TRACKBAR_GetTic (hwnd, wParam, lParam);
1505  
1506     case TBM_GETTICPOS:
1507         return TRACKBAR_GetTicPos (hwnd, wParam, lParam);
1508  
1509     case TBM_GETTOOLTIPS:
1510         return TRACKBAR_GetToolTips (hwnd, wParam, lParam);
1511
1512 /*      case TBM_GETUNICODEFORMAT: */
1513
1514     case TBM_SETBUDDY:
1515         return TRACKBAR_SetBuddy (hwnd, wParam, lParam);
1516
1517     case TBM_SETLINESIZE:
1518         return TRACKBAR_SetLineSize (hwnd, wParam, lParam);
1519
1520     case TBM_SETPAGESIZE:
1521         return TRACKBAR_SetPageSize (hwnd, wParam, lParam);
1522
1523     case TBM_SETPOS:
1524         return TRACKBAR_SetPos (hwnd, wParam, lParam);
1525
1526     case TBM_SETRANGE:
1527         return TRACKBAR_SetRange (hwnd, wParam, lParam);
1528
1529     case TBM_SETRANGEMAX:
1530         return TRACKBAR_SetRangeMax (hwnd, wParam, lParam);
1531
1532     case TBM_SETRANGEMIN:
1533         return TRACKBAR_SetRangeMin (hwnd, wParam, lParam);
1534
1535     case TBM_SETSEL:
1536         return TRACKBAR_SetSel (hwnd, wParam, lParam);
1537
1538     case TBM_SETSELEND:
1539         return TRACKBAR_SetSelEnd (hwnd, wParam, lParam);
1540
1541     case TBM_SETSELSTART:
1542         return TRACKBAR_SetSelStart (hwnd, wParam, lParam);
1543
1544     case TBM_SETTHUMBLENGTH:
1545         return TRACKBAR_SetThumbLength (hwnd, wParam, lParam);
1546
1547     case TBM_SETTIC:
1548         return TRACKBAR_SetTic (hwnd, wParam, lParam);
1549
1550     case TBM_SETTICFREQ:
1551         return TRACKBAR_SetTicFreq (hwnd, wParam);
1552
1553     case TBM_SETTIPSIDE:
1554         return TRACKBAR_SetTipSide (hwnd, wParam, lParam);
1555
1556     case TBM_SETTOOLTIPS:
1557         return TRACKBAR_SetToolTips (hwnd, wParam, lParam);
1558
1559 /*      case TBM_SETUNICODEFORMAT: */
1560
1561
1562     case WM_CAPTURECHANGED:
1563         return TRACKBAR_CaptureChanged (hwnd, wParam, lParam);
1564
1565     case WM_CREATE:
1566         return TRACKBAR_Create (hwnd, wParam, lParam);
1567
1568     case WM_DESTROY:
1569         return TRACKBAR_Destroy (hwnd, wParam, lParam);
1570
1571 /*      case WM_ENABLE: */
1572
1573 /*      case WM_ERASEBKGND: */
1574 /*          return 0; */
1575
1576     case WM_GETDLGCODE:
1577         return DLGC_WANTARROWS;
1578
1579     case WM_KEYDOWN:
1580         return TRACKBAR_KeyDown (hwnd, wParam, lParam);
1581         
1582     case WM_KEYUP:
1583         return TRACKBAR_KeyUp (hwnd, wParam);
1584
1585     case WM_KILLFOCUS:
1586         return TRACKBAR_KillFocus (hwnd, wParam, lParam);
1587
1588     case WM_LBUTTONDOWN:
1589         return TRACKBAR_LButtonDown (hwnd, wParam, lParam);
1590
1591     case WM_LBUTTONUP:
1592         return TRACKBAR_LButtonUp (hwnd, wParam, lParam);
1593
1594     case WM_MOUSEMOVE:
1595         return TRACKBAR_MouseMove (hwnd, wParam, lParam);
1596
1597     case WM_PAINT:
1598         return TRACKBAR_Paint (hwnd, wParam);
1599
1600     case WM_SETFOCUS:
1601         return TRACKBAR_SetFocus (hwnd, wParam, lParam);
1602
1603     case WM_SIZE:
1604         return TRACKBAR_Size (hwnd, wParam, lParam);
1605
1606     case WM_WININICHANGE:
1607         return TRACKBAR_InitializeThumb (hwnd);
1608
1609     default:
1610         if (uMsg >= WM_USER)
1611             ERR("unknown msg %04x wp=%08x lp=%08lx\n",
1612                  uMsg, wParam, lParam);
1613         return DefWindowProcA (hwnd, uMsg, wParam, lParam);
1614     }
1615     return 0;
1616 }
1617
1618
1619 VOID
1620 TRACKBAR_Register (void)
1621 {
1622     WNDCLASSA wndClass;
1623
1624     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
1625     wndClass.style         = CS_GLOBALCLASS;
1626     wndClass.lpfnWndProc   = (WNDPROC)TRACKBAR_WindowProc;
1627     wndClass.cbClsExtra    = 0;
1628     wndClass.cbWndExtra    = sizeof(TRACKBAR_INFO *);
1629     wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
1630     wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
1631     wndClass.lpszClassName = TRACKBAR_CLASSA;
1632  
1633     RegisterClassA (&wndClass);
1634 }
1635
1636
1637 VOID
1638 TRACKBAR_Unregister (void)
1639 {
1640     UnregisterClassA (TRACKBAR_CLASSA, (HINSTANCE)NULL);
1641 }
1642