trackbar.c 52.3 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Trackbar control
 *
4 5 6
 * Copyright 1998, 1999 Eric Kohl
 * Copyright 1998, 1999 Alex Priem
 * Copyright 2002 Dimitrie O. Paun
Alexandre Julliard's avatar
Alexandre Julliard committed
7
 *
8 9 10 11 12 13 14 15 16 17 18 19
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
21
 *
22 23 24 25 26 27 28 29 30
 * NOTE
 * 
 * This code was audited for completeness against the documented features
 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
 * 
 * Unless otherwise noted, we believe this code to be complete, as per
 * the specification mentioned above.
 * If you discover missing features, or bugs, please note them below.
 * 
Alexandre Julliard's avatar
Alexandre Julliard committed
31 32
 */

33
#include <stdarg.h>
34
#include <stdio.h>
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
35
#include <stdlib.h>
36
#include <string.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
37

38
#include "windef.h"
39
#include "winbase.h"
40 41 42
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
43
#include "commctrl.h"
44 45
#include "uxtheme.h"
#include "tmschema.h"
46
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
47

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
48 49
#include "comctl32.h"

50
WINE_DEFAULT_DEBUG_CHANNEL(trackbar);
51

52 53
typedef struct
{
54
    HWND hwndSelf;
55
    DWORD dwStyle;
56 57 58 59 60 61 62
    LONG lRangeMin;
    LONG lRangeMax;
    LONG lLineSize;
    LONG lPageSize;
    LONG lSelMin;
    LONG lSelMax;
    LONG lPos;
63 64
    UINT uThumbLen;
    UINT uNumTics;
65
    UINT uTicFreq;
66 67 68 69 70 71
    HWND hwndNotify;
    HWND hwndToolTip;
    HWND hwndBuddyLA;
    HWND hwndBuddyRB;
    INT  fLocation;
    INT  flags;
72
    BOOL bUnicode;
73
    BOOL bFocussed;
74 75 76 77 78 79
    RECT rcChannel;
    RECT rcSelection;
    RECT rcThumb;
    LPLONG tics;
} TRACKBAR_INFO;

80 81
#define TB_REFRESH_TIMER	1
#define TB_REFRESH_DELAY	500
Alexandre Julliard's avatar
Alexandre Julliard committed
82

83
#define TOOLTIP_OFFSET		2     /* distance from ctrl edge to tooltip */
Alexandre Julliard's avatar
Alexandre Julliard committed
84

85 86
#define TB_DEFAULTPAGESIZE	20

87
/* Used by TRACKBAR_Refresh to find out which parts of the control
88
   need to be recalculated */
Alexandre Julliard's avatar
Alexandre Julliard committed
89

90
#define TB_THUMBPOSCHANGED      1
91
#define TB_THUMBSIZECHANGED     2
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
92
#define TB_THUMBCHANGED 	(TB_THUMBPOSCHANGED | TB_THUMBSIZECHANGED)
93
#define TB_SELECTIONCHANGED     4
94
#define TB_DRAG_MODE            8     /* we're dragging the slider */
95 96 97
#define TB_AUTO_PAGE_LEFT	16
#define TB_AUTO_PAGE_RIGHT	32
#define TB_AUTO_PAGE		(TB_AUTO_PAGE_LEFT | TB_AUTO_PAGE_RIGHT)
98
#define TB_THUMB_HOT            64    /* mouse hovers above thumb */
Alexandre Julliard's avatar
Alexandre Julliard committed
99

Alex Priem's avatar
Alex Priem committed
100
/* helper defines for TRACKBAR_DrawTic */
101
#define TIC_EDGE                0x20
102 103 104
#define TIC_SELECTIONMARKMAX    0x80
#define TIC_SELECTIONMARKMIN    0x100
#define TIC_SELECTIONMARK       (TIC_SELECTIONMARKMAX | TIC_SELECTIONMARKMIN)
Alex Priem's avatar
Alex Priem committed
105

106 107
static const WCHAR themeClass[] = { 'T','r','a','c','k','b','a','r',0 };

108
static inline int 
109
notify_customdraw (const TRACKBAR_INFO *infoPtr, NMCUSTOMDRAW *pnmcd, int stage)
110 111
{
    pnmcd->dwDrawStage = stage;
112
    return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, 
113 114 115
		         pnmcd->hdr.idFrom, (LPARAM)pnmcd);
}

116
static LRESULT notify_hdr (const TRACKBAR_INFO *infoPtr, INT code, LPNMHDR pnmh)
117 118 119 120 121 122
{
    LRESULT result;
    
    TRACE("(code=%d)\n", code);

    pnmh->hwndFrom = infoPtr->hwndSelf;
123
    pnmh->idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
124
    pnmh->code = code;
125
    result = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, pnmh->idFrom, (LPARAM)pnmh);
126 127 128 129 130 131

    TRACE("  <= %ld\n", result);

    return result;
}

132
static inline int notify (const TRACKBAR_INFO *infoPtr, INT code)
133 134 135 136 137
{
    NMHDR nmh;
    return notify_hdr(infoPtr, code, &nmh);
}

138
static void notify_with_scroll (const TRACKBAR_INFO *infoPtr, UINT code)
139
{
140
    UINT scroll = infoPtr->dwStyle & TBS_VERT ? WM_VSCROLL : WM_HSCROLL;
141 142 143

    TRACE("%x\n", code);

144
    SendMessageW (infoPtr->hwndNotify, scroll, code, (LPARAM)infoPtr->hwndSelf);
145
}
146

147
static void TRACKBAR_RecalculateTics (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
148
{
149 150
    int tic;
    unsigned nrTics, i;
Alexandre Julliard's avatar
Alexandre Julliard committed
151

152 153 154
    if (infoPtr->uTicFreq && infoPtr->lRangeMax >= infoPtr->lRangeMin) {
        nrTics=(infoPtr->lRangeMax - infoPtr->lRangeMin)/infoPtr->uTicFreq;
        /* don't add extra tic if there's no remainder */
155
        if (nrTics && ((infoPtr->lRangeMax - infoPtr->lRangeMin) % infoPtr->uTicFreq == 0))
156 157
          nrTics--;
    }
158
    else {
159
        Free (infoPtr->tics);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
160 161
        infoPtr->tics = NULL;
        infoPtr->uNumTics = 0;
162 163
        return;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
164

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
165
    if (nrTics != infoPtr->uNumTics) {
166
    	infoPtr->tics=ReAlloc (infoPtr->tics,
167
                                        (nrTics+1)*sizeof (DWORD));
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
168 169
	if (!infoPtr->tics) {
	    infoPtr->uNumTics = 0;
170
	    notify(infoPtr, NM_OUTOFMEMORY);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
171 172 173
	    return;
	}
    	infoPtr->uNumTics = nrTics;
Alexandre Julliard's avatar
Alexandre Julliard committed
174
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
175

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
176 177 178 179
    tic = infoPtr->lRangeMin + infoPtr->uTicFreq;
    for (i = 0; i < nrTics; i++, tic += infoPtr->uTicFreq)
        infoPtr->tics[i] = tic;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
180

181
/* converts from physical (mouse) position to logical position
Alex Priem's avatar
Alex Priem committed
182
   (in range of trackbar) */
Alexandre Julliard's avatar
Alexandre Julliard committed
183

184
static inline LONG
185
TRACKBAR_ConvertPlaceToPosition (const TRACKBAR_INFO *infoPtr, int place)
Alexandre Julliard's avatar
Alexandre Julliard committed
186
{
187
    double range, width, pos, offsetthumb;
Alexandre Julliard's avatar
Alexandre Julliard committed
188

189
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
190
    if (infoPtr->dwStyle & TBS_VERT) {
191 192
        offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2;
        width = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - (offsetthumb * 2) - 1;
193
        pos = (range*(place - infoPtr->rcChannel.top - offsetthumb)) / width;
194
    } else {
195 196
        offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2;
        width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - (offsetthumb * 2) - 1;
197
        pos = (range*(place - infoPtr->rcChannel.left - offsetthumb)) / width;
198
    }
199 200 201 202 203
    pos += infoPtr->lRangeMin;
    if (pos > infoPtr->lRangeMax)
        pos = infoPtr->lRangeMax;
    else if (pos < infoPtr->lRangeMin)
        pos = infoPtr->lRangeMin;
204

205
    TRACE("%.2f\n", pos);
206 207 208 209 210 211
    return (LONG)(pos + 0.5);
}


/* return: 0> prev, 0 none, >0 next */
static LONG
212
TRACKBAR_GetAutoPageDirection (const TRACKBAR_INFO *infoPtr, POINT clickPoint)
213 214 215
{
    RECT pageRect;

216
    if (infoPtr->dwStyle & TBS_VERT) {
217 218 219 220 221 222 223 224 225 226 227 228 229 230
	pageRect.top = infoPtr->rcChannel.top;
	pageRect.bottom = infoPtr->rcChannel.bottom;
	pageRect.left = infoPtr->rcThumb.left;
	pageRect.right = infoPtr->rcThumb.right;
    } else {
	pageRect.top = infoPtr->rcThumb.top;
	pageRect.bottom = infoPtr->rcThumb.bottom;
	pageRect.left = infoPtr->rcChannel.left;
	pageRect.right = infoPtr->rcChannel.right;
    }


    if (PtInRect(&pageRect, clickPoint))
    {
231
	int clickPlace = (infoPtr->dwStyle & TBS_VERT) ? clickPoint.y : clickPoint.x;
232

233 234
        LONG clickPos = TRACKBAR_ConvertPlaceToPosition(infoPtr, clickPlace);

235 236 237 238 239 240
	return clickPos - infoPtr->lPos;
    }

    return 0;
}

241
static inline void
242
TRACKBAR_PageDown (TRACKBAR_INFO *infoPtr)
243 244 245 246 247 248
{
    if (infoPtr->lPos == infoPtr->lRangeMax) return;

    infoPtr->lPos += infoPtr->lPageSize;
    if (infoPtr->lPos > infoPtr->lRangeMax)
	infoPtr->lPos = infoPtr->lRangeMax;
249
    notify_with_scroll (infoPtr, TB_PAGEDOWN);
Alexandre Julliard's avatar
Alexandre Julliard committed
250 251
}

Alex Priem's avatar
Alex Priem committed
252

253
static inline void
254
TRACKBAR_PageUp (TRACKBAR_INFO *infoPtr)
255 256 257 258 259 260
{
    if (infoPtr->lPos == infoPtr->lRangeMin) return;

    infoPtr->lPos -= infoPtr->lPageSize;
    if (infoPtr->lPos < infoPtr->lRangeMin)
        infoPtr->lPos = infoPtr->lRangeMin;
261 262 263
    notify_with_scroll (infoPtr, TB_PAGEUP);
}

264
static inline void TRACKBAR_LineUp(TRACKBAR_INFO *infoPtr)
265 266 267 268 269 270 271 272
{
    if (infoPtr->lPos == infoPtr->lRangeMin) return;
    infoPtr->lPos -= infoPtr->lLineSize;
    if (infoPtr->lPos < infoPtr->lRangeMin)
        infoPtr->lPos = infoPtr->lRangeMin;
    notify_with_scroll (infoPtr, TB_LINEUP);
}

273
static inline void TRACKBAR_LineDown(TRACKBAR_INFO *infoPtr)
274 275 276 277 278 279
{
    if (infoPtr->lPos == infoPtr->lRangeMax) return;
    infoPtr->lPos += infoPtr->lLineSize;
    if (infoPtr->lPos > infoPtr->lRangeMax)
        infoPtr->lPos = infoPtr->lRangeMax;
    notify_with_scroll (infoPtr, TB_LINEDOWN);
280 281
}

282 283
static void
TRACKBAR_CalcChannel (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
284
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
285 286
    INT cyChannel, offsetthumb, offsetedge;
    RECT lpRect, *channel = & infoPtr->rcChannel;
Alexandre Julliard's avatar
Alexandre Julliard committed
287

288
    GetClientRect (infoPtr->hwndSelf, &lpRect);
Alexandre Julliard's avatar
Alexandre Julliard committed
289

290
    offsetthumb = infoPtr->uThumbLen / 4;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
291
    offsetedge  = offsetthumb + 3;
292 293
    cyChannel   = (infoPtr->dwStyle & TBS_ENABLESELRANGE) ? offsetthumb*3 : 4;
    if (infoPtr->dwStyle & TBS_VERT) {
294 295
        channel->top    = lpRect.top + offsetedge;
        channel->bottom = lpRect.bottom - offsetedge;
296
        if (infoPtr->dwStyle & TBS_ENABLESELRANGE)
297 298 299
            channel->left = lpRect.left + ((infoPtr->uThumbLen - cyChannel + 2) / 2);
        else
            channel->left = lpRect.left + (infoPtr->uThumbLen / 2) - 1;
300 301
        if (infoPtr->dwStyle & TBS_BOTH) {
            if (infoPtr->dwStyle & TBS_NOTICKS)
302 303 304 305
                channel->left += 1;
            else
                channel->left += 9;
        }
306 307
        else if (infoPtr->dwStyle & TBS_TOP) {
            if (infoPtr->dwStyle & TBS_NOTICKS)
308 309 310 311
                channel->left += 2;
            else
                channel->left += 10;
        }
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
312 313
        channel->right = channel->left + cyChannel;
    } else {
314 315
        channel->left = lpRect.left + offsetedge;
        channel->right = lpRect.right - offsetedge;
316
        if (infoPtr->dwStyle & TBS_ENABLESELRANGE)
317 318 319
            channel->top = lpRect.top + ((infoPtr->uThumbLen - cyChannel + 2) / 2);
        else
            channel->top = lpRect.top + (infoPtr->uThumbLen / 2) - 1;
320 321
        if (infoPtr->dwStyle & TBS_BOTH) {
            if (infoPtr->dwStyle & TBS_NOTICKS)
322 323 324 325
                channel->top += 1;
            else
                channel->top += 9;
        }
326 327
        else if (infoPtr->dwStyle & TBS_TOP) {
            if (infoPtr->dwStyle & TBS_NOTICKS)
328 329 330 331
                channel->top += 2;
            else
                channel->top += 10;
        }
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
332
        channel->bottom   = channel->top + cyChannel;
333
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
334 335
}

336
static void
337
TRACKBAR_CalcThumb (const TRACKBAR_INFO *infoPtr, LONG lPos, RECT *thumb)
Alexandre Julliard's avatar
Alexandre Julliard committed
338
{
339
    int range, width, height, thumbwidth;
340
    RECT lpRect;
341

342
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
343
    thumbwidth = (infoPtr->uThumbLen / 2) | 1;
344

345
    if (!range) range = 1;
346

347
    GetClientRect(infoPtr->hwndSelf, &lpRect);
348
    if (infoPtr->dwStyle & TBS_VERT)
349
    {
350
    	height = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - thumbwidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
351

352
        if ((infoPtr->dwStyle & (TBS_BOTH | TBS_LEFT)) && !(infoPtr->dwStyle & TBS_NOTICKS))
353
            thumb->left = 10;
354
        else
355
            thumb->left = 2;
356
        thumb->right = thumb->left + infoPtr->uThumbLen;
357
        thumb->top = infoPtr->rcChannel.top +
358 359
                     (height*(lPos - infoPtr->lRangeMin))/range;
        thumb->bottom = thumb->top + thumbwidth;
360 361
    }
    else
362
    {
363
    	width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - thumbwidth;
364 365

        thumb->left = infoPtr->rcChannel.left +
366 367
                      (width*(lPos - infoPtr->lRangeMin))/range;
        thumb->right = thumb->left + thumbwidth;
368
        if ((infoPtr->dwStyle & (TBS_BOTH | TBS_TOP)) && !(infoPtr->dwStyle & TBS_NOTICKS))
369
            thumb->top = 10;
370
        else
371
            thumb->top = 2;
372
        thumb->bottom = thumb->top + infoPtr->uThumbLen;
373
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
374 375
}

376
static inline void
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
377 378 379 380 381
TRACKBAR_UpdateThumb (TRACKBAR_INFO *infoPtr)
{
    TRACKBAR_CalcThumb(infoPtr, infoPtr->lPos, &infoPtr->rcThumb);
}

382
static inline void
383
TRACKBAR_InvalidateAll (const TRACKBAR_INFO *infoPtr)
384 385 386 387
{
    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
}

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
388
static void
389
TRACKBAR_InvalidateThumb (const TRACKBAR_INFO *infoPtr, LONG thumbPos)
390 391 392 393 394 395 396 397 398
{
    RECT rcThumb;

    TRACKBAR_CalcThumb(infoPtr, thumbPos, &rcThumb);
    InflateRect(&rcThumb, 1, 1);
    InvalidateRect(infoPtr->hwndSelf, &rcThumb, FALSE);
}

static inline void
399
TRACKBAR_InvalidateThumbMove (const TRACKBAR_INFO *infoPtr, LONG oldPos, LONG newPos)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
400
{
401 402 403
    TRACKBAR_InvalidateThumb (infoPtr, oldPos);
    if (newPos != oldPos)
        TRACKBAR_InvalidateThumb (infoPtr, newPos);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
404 405
}

406
static inline BOOL
407
TRACKBAR_HasSelection (const TRACKBAR_INFO *infoPtr)
408 409 410 411
{
    return infoPtr->lSelMin != infoPtr->lSelMax;
}

412 413
static void
TRACKBAR_CalcSelection (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
414
{
415 416
    RECT *selection = &infoPtr->rcSelection;
    int range = infoPtr->lRangeMax - infoPtr->lRangeMin;
417
    int offsetthumb, height, width;
418

419
    if (range <= 0) {
420
        SetRectEmpty (selection);
421
    } else {
422
        if (infoPtr->dwStyle & TBS_VERT) {
423 424 425
            offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2;
            height = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - offsetthumb*2;
            selection->top    = infoPtr->rcChannel.top + offsetthumb +
426
                (height*infoPtr->lSelMin)/range;
427
            selection->bottom = infoPtr->rcChannel.top + offsetthumb +
428 429 430 431
                (height*infoPtr->lSelMax)/range;
            selection->left   = infoPtr->rcChannel.left + 3;
            selection->right  = infoPtr->rcChannel.right - 3;
        } else {
432 433 434
            offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2;
            width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - offsetthumb*2;
            selection->left   = infoPtr->rcChannel.left + offsetthumb +
435
                (width*infoPtr->lSelMin)/range;
436
            selection->right  = infoPtr->rcChannel.left + offsetthumb +
437
                (width*infoPtr->lSelMax)/range;
438 439
            selection->top    = infoPtr->rcChannel.top + 3;
            selection->bottom = infoPtr->rcChannel.bottom - 3;
440
        }
441 442
    }

443
    TRACE("selection[%s]\n", wine_dbgstr_rect(selection));
Alexandre Julliard's avatar
Alexandre Julliard committed
444 445
}

446 447 448 449 450 451
static BOOL
TRACKBAR_AutoPage (TRACKBAR_INFO *infoPtr, POINT clickPoint)
{
    LONG dir = TRACKBAR_GetAutoPageDirection(infoPtr, clickPoint);
    LONG prevPos = infoPtr->lPos;

452
    TRACE("x=%d, y=%d, dir=%d\n", clickPoint.x, clickPoint.y, dir);
453 454 455

    if (dir > 0 && (infoPtr->flags & TB_AUTO_PAGE_RIGHT))
	TRACKBAR_PageDown(infoPtr);
456 457
    else if (dir < 0 && (infoPtr->flags & TB_AUTO_PAGE_LEFT))
	TRACKBAR_PageUp(infoPtr);
458 459 460 461 462 463 464 465
    else return FALSE;

    infoPtr->flags |= TB_THUMBPOSCHANGED;
    TRACKBAR_InvalidateThumbMove (infoPtr, prevPos, infoPtr->lPos);

    return TRUE;
}

Alex Priem's avatar
Alex Priem committed
466 467
/* Trackbar drawing code. I like my spaghetti done milanese.  */

468
static void
469
TRACKBAR_DrawChannel (const TRACKBAR_INFO *infoPtr, HDC hdc)
470 471
{
    RECT rcChannel = infoPtr->rcChannel;
472
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
473

474 475 476
    if (theme)
    {
        DrawThemeBackground (theme, hdc, 
477
            (infoPtr->dwStyle & TBS_VERT) ?
478 479 480 481 482
                TKP_TRACKVERT : TKP_TRACK, TKS_NORMAL, &rcChannel, 0);
    }
    else
    {
        DrawEdge (hdc, &rcChannel, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
483
        if (infoPtr->dwStyle & TBS_ENABLESELRANGE) {		 /* fill the channel */
484 485 486 487
            FillRect (hdc, &rcChannel, GetStockObject(WHITE_BRUSH));
            if (TRACKBAR_HasSelection(infoPtr))
                FillRect (hdc, &infoPtr->rcSelection, GetSysColorBrush(COLOR_HIGHLIGHT));
        }
488 489
    }
}
Alex Priem's avatar
Alex Priem committed
490

491
static void
492
TRACKBAR_DrawOneTic (const TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags)
Alex Priem's avatar
Alex Priem committed
493
{
494 495
    int x, y, ox, oy, range, side, indent = 0, len = 3;
    int offsetthumb;
496
    RECT rcTics;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
497

498
    if (flags & TBS_VERT) {
499
        offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2;
500 501
	rcTics.left = infoPtr->rcThumb.left - 2;
	rcTics.right = infoPtr->rcThumb.right + 2;
502
	rcTics.top    = infoPtr->rcChannel.top + offsetthumb + 1;
503
	rcTics.bottom = infoPtr->rcChannel.bottom - offsetthumb;
504
    } else {
505 506
        offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2;
	rcTics.left   = infoPtr->rcChannel.left + offsetthumb + 1;
507 508 509
	rcTics.right  = infoPtr->rcChannel.right - offsetthumb;
	rcTics.top = infoPtr->rcThumb.top - 2;
	rcTics.bottom = infoPtr->rcThumb.bottom + 2;
510
    }
Alex Priem's avatar
Alex Priem committed
511

512 513 514 515
    if (flags & (TBS_TOP | TBS_LEFT)) {
	x = rcTics.left;
	y = rcTics.top;
	side = -1;
516
    } else {
517 518 519
  	x = rcTics.right;
  	y = rcTics.bottom;
	side = 1;
520
    }
Alex Priem's avatar
Alex Priem committed
521

522
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
523
    if (range <= 0)
524
      range = 1; /* to avoid division by zero */
Alex Priem's avatar
Alex Priem committed
525

526
    if (flags & TIC_SELECTIONMARK) {
527 528 529
  	indent = (flags & TIC_SELECTIONMARKMIN) ? -1 : 1;
    } else if (flags & TIC_EDGE) {
	len++;
530
    }
Alex Priem's avatar
Alex Priem committed
531

532
    if (flags & TBS_VERT) {
533
	int height = rcTics.bottom - rcTics.top;
534 535 536 537
	y = rcTics.top + (height*(ticPos - infoPtr->lRangeMin))/range;
    } else {
        int width = rcTics.right - rcTics.left;
        x = rcTics.left + (width*(ticPos - infoPtr->lRangeMin))/range;
538
    }
Alex Priem's avatar
Alex Priem committed
539

540 541 542 543 544 545 546
    ox = x;
    oy = y;
    MoveToEx(hdc, x, y, 0);
    if (flags & TBS_VERT) x += len * side;
    else y += len * side;
    LineTo(hdc, x, y);
	    
547 548
    if (flags & TIC_SELECTIONMARK) {
	if (flags & TBS_VERT) {
549
	    x -= side;
550
	} else {
551
	    y -= side;
552
	}
553 554 555 556 557 558 559 560 561
	MoveToEx(hdc, x, y, 0);
	if (flags & TBS_VERT) {
	    y += 2 * indent;
	} else {
	    x += 2 * indent;
	}
	
	LineTo(hdc, x, y);
	LineTo(hdc, ox, oy);
562
    }
Alex Priem's avatar
Alex Priem committed
563 564 565
}


566
static inline void
567
TRACKBAR_DrawTic (const TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags)
Alex Priem's avatar
Alex Priem committed
568
{
569
    if ((flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH))
570
        TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags | TBS_LEFT);
Alex Priem's avatar
Alex Priem committed
571

572
    if (!(flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH))
573
        TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags & ~TBS_LEFT);
574 575 576
}

static void
577
TRACKBAR_DrawTics (const TRACKBAR_INFO *infoPtr, HDC hdc)
578
{
579
    unsigned int i;
580
    int ticFlags = infoPtr->dwStyle & 0x0f;
581 582
    LOGPEN ticPen = { PS_SOLID, {1, 0}, GetSysColor (COLOR_3DDKSHADOW) };
    HPEN hOldPen, hTicPen;
583
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
584
    
585 586
    if (theme)
    {
587
        int part = (infoPtr->dwStyle & TBS_VERT) ? TKP_TICSVERT : TKP_TICS;
588 589 590
        GetThemeColor (theme, part, TSS_NORMAL, TMT_COLOR, &ticPen.lopnColor);
    }
    /* create the pen to draw the tics with */
591 592 593 594 595 596 597 598 599 600
    hTicPen = CreatePenIndirect(&ticPen);
    hOldPen = hTicPen ? SelectObject(hdc, hTicPen) : 0;

    /* actually draw the tics */
    for (i=0; i<infoPtr->uNumTics; i++)
        TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->tics[i], ticFlags);

    TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lRangeMin, ticFlags | TIC_EDGE);
    TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lRangeMax, ticFlags | TIC_EDGE);

601
    if ((infoPtr->dwStyle & TBS_ENABLESELRANGE) && TRACKBAR_HasSelection(infoPtr)) {
602 603 604 605 606 607 608 609 610 611 612
        TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lSelMin,
                          ticFlags | TIC_SELECTIONMARKMIN);
        TRACKBAR_DrawTic (infoPtr, hdc, infoPtr->lSelMax,
                          ticFlags | TIC_SELECTIONMARKMAX);
    }
    
    /* clean up the pen, if we created one */
    if (hTicPen) {
	SelectObject(hdc, hOldPen);
	DeleteObject(hTicPen);
    }
Alex Priem's avatar
Alex Priem committed
613 614
}

615
static void
616
TRACKBAR_DrawThumb (const TRACKBAR_INFO *infoPtr, HDC hdc)
617
{
618 619
    HBRUSH oldbr;
    HPEN  oldpen;
620
    RECT thumb = infoPtr->rcThumb;
621 622
    int BlackUntil = 3;
    int PointCount = 6;
623
    POINT points[6];
624
    int fillClr;
625
    int PointDepth;
626 627 628 629 630 631
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
    
    if (theme)
    {
        int partId;
        int stateId;
632 633 634 635
        if (infoPtr->dwStyle & TBS_BOTH)
            partId = (infoPtr->dwStyle & TBS_VERT) ? TKP_THUMBVERT : TKP_THUMB;
        else if (infoPtr->dwStyle & TBS_LEFT)
            partId = (infoPtr->dwStyle & TBS_VERT) ? TKP_THUMBLEFT : TKP_THUMBTOP;
636
        else
637
            partId = (infoPtr->dwStyle & TBS_VERT) ? TKP_THUMBRIGHT : TKP_THUMBBOTTOM;
638
            
639
        if (infoPtr->dwStyle & WS_DISABLED)
640 641 642 643 644 645 646 647 648 649 650 651
            stateId = TUS_DISABLED;
        else if (infoPtr->flags & TB_DRAG_MODE)
            stateId = TUS_PRESSED;
        else if (infoPtr->flags & TB_THUMB_HOT)
            stateId = TUS_HOT;
        else
            stateId = TUS_NORMAL;
        
        DrawThemeBackground (theme, hdc, partId, stateId, &thumb, 0);
        
        return;
    }
652

653 654
    fillClr = infoPtr->flags & TB_DRAG_MODE ? COLOR_BTNHILIGHT : COLOR_BTNFACE;
    oldbr = SelectObject (hdc, GetSysColorBrush(fillClr));
655
    SetPolyFillMode (hdc, WINDING);
656

657
    if (infoPtr->dwStyle & TBS_BOTH)
658 659 660 661 662 663 664 665 666 667 668 669 670
    {
       points[0].x=thumb.right;
       points[0].y=thumb.top;
       points[1].x=thumb.right;
       points[1].y=thumb.bottom;
       points[2].x=thumb.left;
       points[2].y=thumb.bottom;
       points[3].x=thumb.left;
       points[3].y=thumb.top;
       points[4].x=points[0].x;
       points[4].y=points[0].y;
       PointCount = 5;
       BlackUntil = 3;
671 672
    }
    else
673
    {
674
        if (infoPtr->dwStyle & TBS_VERT)
675
        {
676
          PointDepth = (thumb.bottom - thumb.top) / 2;
677
          if (infoPtr->dwStyle & TBS_LEFT)
678 679 680 681 682 683 684 685
          {
            points[0].x=thumb.right;
            points[0].y=thumb.top;
            points[1].x=thumb.right;
            points[1].y=thumb.bottom;
            points[2].x=thumb.left + PointDepth;
            points[2].y=thumb.bottom;
            points[3].x=thumb.left;
686
            points[3].y=(thumb.bottom - thumb.top) / 2 + thumb.top + 1;
687 688 689 690 691 692 693 694 695
            points[4].x=thumb.left + PointDepth;
            points[4].y=thumb.top;
            points[5].x=points[0].x;
            points[5].y=points[0].y;
            BlackUntil = 4;
          }
          else
          {
            points[0].x=thumb.right;
696
            points[0].y=(thumb.bottom - thumb.top) / 2 + thumb.top + 1;
697 698 699 700 701 702 703 704 705 706 707 708 709 710
            points[1].x=thumb.right - PointDepth;
            points[1].y=thumb.bottom;
            points[2].x=thumb.left;
            points[2].y=thumb.bottom;
            points[3].x=thumb.left;
            points[3].y=thumb.top;
            points[4].x=thumb.right - PointDepth;
            points[4].y=thumb.top;
            points[5].x=points[0].x;
            points[5].y=points[0].y;
          }
        }
        else
        {
711
          PointDepth = (thumb.right - thumb.left) / 2;
712
          if (infoPtr->dwStyle & TBS_TOP)
713
          {
714
            points[0].x=(thumb.right - thumb.left) / 2 + thumb.left + 1;
715 716 717 718
            points[0].y=thumb.top;
            points[1].x=thumb.right;
            points[1].y=thumb.top + PointDepth;
            points[2].x=thumb.right;
719
            points[2].y=thumb.bottom;
720 721 722 723 724 725 726 727 728 729 730 731 732 733
            points[3].x=thumb.left;
            points[3].y=thumb.bottom;
            points[4].x=thumb.left;
            points[4].y=thumb.top + PointDepth;
            points[5].x=points[0].x;
            points[5].y=points[0].y;
            BlackUntil = 4;
          }
          else
          {
            points[0].x=thumb.right;
            points[0].y=thumb.top;
            points[1].x=thumb.right;
            points[1].y=thumb.bottom - PointDepth;
734
            points[2].x=(thumb.right - thumb.left) / 2 + thumb.left + 1;
735 736 737 738 739 740 741 742 743
            points[2].y=thumb.bottom;
            points[3].x=thumb.left;
            points[3].y=thumb.bottom - PointDepth;
            points[4].x=thumb.left;
            points[4].y=thumb.top;
            points[5].x=points[0].x;
            points[5].y=points[0].y;
          }
        }
744

745 746
    }

747
    /* Draw the thumb now */
748
    Polygon (hdc, points, PointCount);
749 750 751
    oldpen = SelectObject(hdc, GetStockObject(BLACK_PEN));
    Polyline(hdc,points, BlackUntil);
    SelectObject(hdc, GetStockObject(WHITE_PEN));
752
    Polyline(hdc, &points[BlackUntil-1], PointCount+1-BlackUntil);
753 754
    SelectObject(hdc, oldpen);
    SelectObject(hdc, oldbr);
755
}
Alex Priem's avatar
Alex Priem committed
756

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
757

758
static inline void
759
TRACKBAR_ActivateToolTip (const TRACKBAR_INFO *infoPtr, BOOL fShow)
760 761 762 763 764 765 766 767 768 769 770 771 772
{
    TTTOOLINFOW ti;

    if (!infoPtr->hwndToolTip) return;

    ZeroMemory(&ti, sizeof(ti));
    ti.cbSize = sizeof(ti);
    ti.hwnd   = infoPtr->hwndSelf;

    SendMessageW (infoPtr->hwndToolTip, TTM_TRACKACTIVATE, fShow, (LPARAM)&ti);
}


773
static void
774
TRACKBAR_UpdateToolTip (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
775
{
776 777
    WCHAR buf[80];
    static const WCHAR fmt[] = { '%', 'l', 'd', 0 };
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
778 779
    TTTOOLINFOW ti;
    POINT pt;
780
    RECT rcClient;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
781
    LRESULT size;
Alexandre Julliard's avatar
Alexandre Julliard committed
782

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
783
    if (!infoPtr->hwndToolTip) return;
Alexandre Julliard's avatar
Alexandre Julliard committed
784

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
785 786 787 788 789 790 791 792 793
    ZeroMemory(&ti, sizeof(ti));
    ti.cbSize = sizeof(ti);
    ti.hwnd   = infoPtr->hwndSelf;
    ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;

    wsprintfW (buf, fmt, infoPtr->lPos);
    ti.lpszText = buf;
    SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti);

794
    GetClientRect (infoPtr->hwndSelf, &rcClient);
795
    size = SendMessageW (infoPtr->hwndToolTip, TTM_GETBUBBLESIZE, 0, (LPARAM)&ti);
796
    if (infoPtr->dwStyle & TBS_VERT) {
797
	if (infoPtr->fLocation == TBTS_LEFT)
798
	    pt.x = 0 - LOWORD(size) - TOOLTIP_OFFSET;
799
	else
800
	    pt.x = rcClient.right + TOOLTIP_OFFSET;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
801 802
    	pt.y = (infoPtr->rcThumb.top + infoPtr->rcThumb.bottom - HIWORD(size))/2;
    } else {
803
	if (infoPtr->fLocation == TBTS_TOP)
804
	    pt.y = 0 - HIWORD(size) - TOOLTIP_OFFSET;
805
	else
806
            pt.y = rcClient.bottom + TOOLTIP_OFFSET;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
807
        pt.x = (infoPtr->rcThumb.left + infoPtr->rcThumb.right - LOWORD(size))/2;
Alex Priem's avatar
Alex Priem committed
808
    }
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
809 810 811
    ClientToScreen(infoPtr->hwndSelf, &pt);

    SendMessageW (infoPtr->hwndToolTip, TTM_TRACKPOSITION,
812
                  0, MAKELPARAM(pt.x, pt.y));
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
813 814 815 816
}


static void
817
TRACKBAR_Refresh (TRACKBAR_INFO *infoPtr, HDC hdcDst)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
818
{
819
    RECT rcClient;
820 821
    HDC hdc;
    HBITMAP hOldBmp = 0, hOffScreenBmp = 0;
822 823
    NMCUSTOMDRAW nmcd;
    int gcdrf, icdrf;
824

825
    if (infoPtr->flags & TB_THUMBCHANGED) {
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
826
        TRACKBAR_UpdateThumb (infoPtr);
827
        if (infoPtr->flags & TB_THUMBSIZECHANGED)
828
            TRACKBAR_CalcChannel (infoPtr);
829 830
    }
    if (infoPtr->flags & TB_SELECTIONCHANGED)
831
        TRACKBAR_CalcSelection (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
832

833
    if (infoPtr->flags & TB_DRAG_MODE)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
834 835
        TRACKBAR_UpdateToolTip (infoPtr);

836 837
    infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED);

838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853
    GetClientRect (infoPtr->hwndSelf, &rcClient);
    
    /* try to render offscreen, if we fail, carrry onscreen */
    hdc = CreateCompatibleDC(hdcDst);
    if (hdc) {
        hOffScreenBmp = CreateCompatibleBitmap(hdcDst, rcClient.right, rcClient.bottom);
        if (hOffScreenBmp) {
	    hOldBmp = SelectObject(hdc, hOffScreenBmp);
	} else {
	    DeleteObject(hdc);
	    hdc = hdcDst;
	}
    } else {
	hdc = hdcDst;
    }

854 855
    ZeroMemory(&nmcd, sizeof(nmcd));
    nmcd.hdr.hwndFrom = infoPtr->hwndSelf;
856
    nmcd.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
857 858
    nmcd.hdr.code = NM_CUSTOMDRAW;
    nmcd.hdc = hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
859

860 861
    /* start the paint cycle */
    nmcd.rc = rcClient;
862
    gcdrf = notify_customdraw(infoPtr, &nmcd, CDDS_PREPAINT);
863 864
    if (gcdrf & CDRF_SKIPDEFAULT) goto cleanup;
    
865
    /* Erase background */
866
    if (gcdrf == CDRF_DODEFAULT ||
867
        notify_customdraw(infoPtr, &nmcd, CDDS_PREERASE) != CDRF_SKIPDEFAULT) {
868
        if (GetWindowTheme (infoPtr->hwndSelf)) {
869
            DrawThemeParentBackground (infoPtr->hwndSelf, hdc, 0);
870
        }
871 872
        else
	    FillRect (hdc, &rcClient, GetSysColorBrush(COLOR_BTNFACE));
873
        if (gcdrf != CDRF_DODEFAULT)
874
	    notify_customdraw(infoPtr, &nmcd, CDDS_POSTERASE);
875
    }
876
    
Alexandre Julliard's avatar
Alexandre Julliard committed
877
    /* draw channel */
878 879 880 881
    if (gcdrf & CDRF_NOTIFYITEMDRAW) {
        nmcd.dwItemSpec = TBCD_CHANNEL;
	nmcd.uItemState = CDIS_DEFAULT;
	nmcd.rc = infoPtr->rcChannel;
882
	icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
883 884
    } else icdrf = CDRF_DODEFAULT;
    if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
885
	TRACKBAR_DrawChannel (infoPtr, hdc);
886
	if (icdrf & CDRF_NOTIFYPOSTPAINT)
887
	    notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
Alexandre Julliard's avatar
Alexandre Julliard committed
888 889
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
890 891

    /* draw tics */
892
    if (!(infoPtr->dwStyle & TBS_NOTICKS)) {
893 894 895 896
    	if (gcdrf & CDRF_NOTIFYITEMDRAW) {
            nmcd.dwItemSpec = TBCD_TICS;
	    nmcd.uItemState = CDIS_DEFAULT;
	    nmcd.rc = rcClient;
897
	    icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
898 899
        } else icdrf = CDRF_DODEFAULT;
	if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
900
	    TRACKBAR_DrawTics (infoPtr, hdc);
901
	    if (icdrf & CDRF_NOTIFYPOSTPAINT)
902
		notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
903
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
904
    }
905
    
906
    /* draw thumb */
907
    if (!(infoPtr->dwStyle & TBS_NOTHUMB)) {
908 909 910 911
	if (gcdrf & CDRF_NOTIFYITEMDRAW) {
	    nmcd.dwItemSpec = TBCD_THUMB;
	    nmcd.uItemState = infoPtr->flags & TB_DRAG_MODE ? CDIS_HOT : CDIS_DEFAULT;
	    nmcd.rc = infoPtr->rcThumb;
912
	    icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
913 914
	} else icdrf = CDRF_DODEFAULT;
	if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
915
            TRACKBAR_DrawThumb(infoPtr, hdc);
916
	    if (icdrf & CDRF_NOTIFYPOSTPAINT)
917
		notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
918 919
	}
    }
920

921 922 923 924 925
    /* draw focus rectangle */
    if (infoPtr->bFocussed) {
	DrawFocusRect(hdc, &rcClient);
    }

926 927
    /* finish up the painting */
    if (gcdrf & CDRF_NOTIFYPOSTPAINT)
928
	notify_customdraw(infoPtr, &nmcd, CDDS_POSTPAINT);
929 930
    
cleanup:
931 932 933 934 935 936 937
    /* cleanup, if we rendered offscreen */
    if (hdc != hdcDst) {
	BitBlt(hdcDst, 0, 0, rcClient.right, rcClient.bottom, hdc, 0, 0, SRCCOPY);
	SelectObject(hdc, hOldBmp);
	DeleteObject(hOffScreenBmp);
	DeleteObject(hdc);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
938 939 940
}


941
static void
942
TRACKBAR_AlignBuddies (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
943
{
944
    HWND hwndParent = GetParent (infoPtr->hwndSelf);
945 946
    RECT rcSelf, rcBuddy;
    INT x, y;
Alexandre Julliard's avatar
Alexandre Julliard committed
947

948
    GetWindowRect (infoPtr->hwndSelf, &rcSelf);
949
    MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcSelf, 2);
Alexandre Julliard's avatar
Alexandre Julliard committed
950 951 952

    /* align buddy left or above */
    if (infoPtr->hwndBuddyLA) {
953 954
	GetWindowRect (infoPtr->hwndBuddyLA, &rcBuddy);
	MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcBuddy, 2);
Alexandre Julliard's avatar
Alexandre Julliard committed
955

956
	if (infoPtr->dwStyle & TBS_VERT) {
Alexandre Julliard's avatar
Alexandre Julliard committed
957 958 959 960 961 962 963 964 965 966
	    x = (infoPtr->rcChannel.right + infoPtr->rcChannel.left) / 2 -
		(rcBuddy.right - rcBuddy.left) / 2 + rcSelf.left;
	    y = rcSelf.top - (rcBuddy.bottom - rcBuddy.top);
	}
	else {
	    x = rcSelf.left - (rcBuddy.right - rcBuddy.left);
	    y = (infoPtr->rcChannel.bottom + infoPtr->rcChannel.top) / 2 -
		(rcBuddy.bottom - rcBuddy.top) / 2 + rcSelf.top;
	}

967
	SetWindowPos (infoPtr->hwndBuddyLA, 0, x, y, 0, 0,
968
                      SWP_NOZORDER | SWP_NOSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
969 970 971 972 973
    }


    /* align buddy right or below */
    if (infoPtr->hwndBuddyRB) {
974 975
	GetWindowRect (infoPtr->hwndBuddyRB, &rcBuddy);
	MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcBuddy, 2);
Alexandre Julliard's avatar
Alexandre Julliard committed
976

977
	if (infoPtr->dwStyle & TBS_VERT) {
Alexandre Julliard's avatar
Alexandre Julliard committed
978 979 980 981 982 983 984 985 986
	    x = (infoPtr->rcChannel.right + infoPtr->rcChannel.left) / 2 -
		(rcBuddy.right - rcBuddy.left) / 2 + rcSelf.left;
	    y = rcSelf.bottom;
	}
	else {
	    x = rcSelf.right;
	    y = (infoPtr->rcChannel.bottom + infoPtr->rcChannel.top) / 2 -
		(rcBuddy.bottom - rcBuddy.top) / 2 + rcSelf.top;
	}
987
	SetWindowPos (infoPtr->hwndBuddyRB, 0, x, y, 0, 0,
988
                      SWP_NOZORDER | SWP_NOSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
989 990 991 992 993
    }
}


static LRESULT
994
TRACKBAR_ClearSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
995
{
996 997
    infoPtr->lSelMin = 0;
    infoPtr->lSelMax = 0;
998
    infoPtr->flags |= TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
999

1000
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1001 1002 1003 1004 1005 1006

    return 0;
}


static LRESULT
1007
TRACKBAR_ClearTics (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
1008 1009
{
    if (infoPtr->tics) {
1010
        Free (infoPtr->tics);
1011 1012
        infoPtr->tics = NULL;
        infoPtr->uNumTics = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1013 1014
    }

1015
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1016 1017 1018 1019 1020

    return 0;
}


1021
static inline LRESULT
1022
TRACKBAR_GetChannelRect (const TRACKBAR_INFO *infoPtr, LPRECT lprc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1023
{
1024
    if (lprc == NULL) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034

    lprc->left   = infoPtr->rcChannel.left;
    lprc->right  = infoPtr->rcChannel.right;
    lprc->bottom = infoPtr->rcChannel.bottom;
    lprc->top    = infoPtr->rcChannel.top;

    return 0;
}


1035
static inline LONG
1036
TRACKBAR_GetNumTics (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1037
{
1038
    if (infoPtr->dwStyle & TBS_NOTICKS) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1039

1040
    return infoPtr->uNumTics + 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1041 1042 1043
}


1044
static int comp_tics (const void *ap, const void *bp)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1045
{
1046 1047
    const DWORD a = *(const DWORD *)ap;
    const DWORD b = *(const DWORD *)bp;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1048

1049
    TRACE("(a=%d, b=%d)\n", a, b);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1050 1051 1052 1053 1054
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1055

1056
static inline LONG
1057
TRACKBAR_GetTic (const TRACKBAR_INFO *infoPtr, INT iTic)
Alexandre Julliard's avatar
Alexandre Julliard committed
1058
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1059
    if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics)
Alexandre Julliard's avatar
Alexandre Julliard committed
1060 1061
	return -1;

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1062
    qsort(infoPtr->tics, infoPtr->uNumTics, sizeof(DWORD), comp_tics);
1063
    return infoPtr->tics[iTic];
Alexandre Julliard's avatar
Alexandre Julliard committed
1064 1065 1066
}


1067
static inline LONG
1068
TRACKBAR_GetTicPos (const TRACKBAR_INFO *infoPtr, INT iTic)
Alexandre Julliard's avatar
Alexandre Julliard committed
1069
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1070
    LONG range, width, pos, tic;
1071
    int offsetthumb;
Alexandre Julliard's avatar
Alexandre Julliard committed
1072

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1073
    if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics)
Alexandre Julliard's avatar
Alexandre Julliard committed
1074 1075
	return -1;

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1076
    tic   = TRACKBAR_GetTic (infoPtr, iTic);
1077
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
1078
    if (range <= 0) range = 1;
1079 1080 1081
    offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2;
    width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - offsetthumb*2;
    pos   = infoPtr->rcChannel.left + offsetthumb + (width * tic) / range;
Alexandre Julliard's avatar
Alexandre Julliard committed
1082

1083
    return pos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1084 1085
}

1086

1087 1088
static HWND
TRACKBAR_SetBuddy (TRACKBAR_INFO *infoPtr, BOOL fLocation, HWND hwndBuddy)
Alexandre Julliard's avatar
Alexandre Julliard committed
1089
{
1090
    HWND hwndTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1091

1092
    if (fLocation) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1093 1094
	/* buddy is left or above */
	hwndTemp = infoPtr->hwndBuddyLA;
1095
	infoPtr->hwndBuddyLA = hwndBuddy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1096 1097
    }
    else {
1098 1099
        /* buddy is right or below */
        hwndTemp = infoPtr->hwndBuddyRB;
1100
        infoPtr->hwndBuddyRB = hwndBuddy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1101 1102
    }

1103
    TRACKBAR_AlignBuddies (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1104

1105
    return hwndTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1106 1107 1108
}


1109
static inline LONG
1110
TRACKBAR_SetLineSize (TRACKBAR_INFO *infoPtr, LONG lLineSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1111
{
1112
    LONG lTemp = infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1113

1114
    infoPtr->lLineSize = lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1115

1116
    return lTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1117 1118 1119
}


1120
static inline LONG
1121
TRACKBAR_SetPageSize (TRACKBAR_INFO *infoPtr, LONG lPageSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1122
{
1123
    LONG lTemp = infoPtr->lPageSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1124

1125 1126 1127 1128
    if (lPageSize != -1)
        infoPtr->lPageSize = lPageSize;
    else
        infoPtr->lPageSize = TB_DEFAULTPAGESIZE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1129

1130
    return lTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1131 1132 1133
}


1134
static inline LRESULT
1135
TRACKBAR_SetPos (TRACKBAR_INFO *infoPtr, BOOL fPosition, LONG lPosition)
Alexandre Julliard's avatar
Alexandre Julliard committed
1136
{
1137
    LONG oldPos = infoPtr->lPos;
1138
    infoPtr->lPos = lPosition;
Alexandre Julliard's avatar
Alexandre Julliard committed
1139

1140 1141
    if (infoPtr->lPos < infoPtr->lRangeMin)
	infoPtr->lPos = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1142

1143 1144
    if (infoPtr->lPos > infoPtr->lRangeMax)
	infoPtr->lPos = infoPtr->lRangeMax;
1145
    infoPtr->flags |= TB_THUMBPOSCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1146

1147
    if (fPosition && oldPos != lPosition) TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition);
Alexandre Julliard's avatar
Alexandre Julliard committed
1148 1149 1150 1151 1152

    return 0;
}


1153
static inline LRESULT
1154
TRACKBAR_SetRange (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lRange)
Alexandre Julliard's avatar
Alexandre Julliard committed
1155
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1156 1157
    infoPtr->lRangeMin = (SHORT)LOWORD(lRange);
    infoPtr->lRangeMax = (SHORT)HIWORD(lRange);
Alexandre Julliard's avatar
Alexandre Julliard committed
1158

1159 1160
    if (infoPtr->lPos < infoPtr->lRangeMin) {
        infoPtr->lPos = infoPtr->lRangeMin;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1161
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1162
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1163

1164 1165
    if (infoPtr->lPos > infoPtr->lRangeMax) {
        infoPtr->lPos = infoPtr->lRangeMax;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1166
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1167
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1168

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1169 1170
    infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
    if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1171

1172
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1173 1174 1175 1176 1177

    return 0;
}


1178
static inline LRESULT
1179
TRACKBAR_SetRangeMax (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMax)
Alexandre Julliard's avatar
Alexandre Julliard committed
1180
{
1181 1182 1183
    infoPtr->lRangeMax = lMax;
    if (infoPtr->lPos > infoPtr->lRangeMax) {
        infoPtr->lPos = infoPtr->lRangeMax;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1184
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1185
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1186

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1187 1188
    infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
    if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1189

1190
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1191 1192 1193 1194 1195

    return 0;
}


1196
static inline LRESULT
1197
TRACKBAR_SetRangeMin (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMin)
Alexandre Julliard's avatar
Alexandre Julliard committed
1198
{
1199 1200 1201
    infoPtr->lRangeMin = lMin;
    if (infoPtr->lPos < infoPtr->lRangeMin) {
        infoPtr->lPos = infoPtr->lRangeMin;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1202
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1203
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1204

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1205 1206
    infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
    if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1207

1208
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1209 1210 1211 1212

    return 0;
}

1213

1214
static inline LRESULT
1215
TRACKBAR_SetSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lSel)
Alexandre Julliard's avatar
Alexandre Julliard committed
1216
{
1217
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1218 1219
        infoPtr->lSelMin = 0;
        infoPtr->lSelMax = 0;
1220
        return 0;
1221
    }
1222

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1223 1224 1225
    infoPtr->lSelMin = (SHORT)LOWORD(lSel);
    infoPtr->lSelMax = (SHORT)HIWORD(lSel);
    infoPtr->flags |= TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1226

1227 1228 1229 1230
    if (infoPtr->lSelMin < infoPtr->lRangeMin)
        infoPtr->lSelMin = infoPtr->lRangeMin;
    if (infoPtr->lSelMax > infoPtr->lRangeMax)
        infoPtr->lSelMax = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1231

1232
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1233 1234 1235 1236 1237

    return 0;
}


1238
static inline LRESULT
1239
TRACKBAR_SetSelEnd (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lEnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
1240
{
1241
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1242
        infoPtr->lSelMax = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1243
	return 0;
1244
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1245

1246
    infoPtr->lSelMax = lEnd;
1247
    infoPtr->flags |= TB_SELECTIONCHANGED;
1248

1249 1250
    if (infoPtr->lSelMax > infoPtr->lRangeMax)
        infoPtr->lSelMax = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1251

1252
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1253 1254 1255 1256 1257

    return 0;
}


1258
static inline LRESULT
1259
TRACKBAR_SetSelStart (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lStart)
Alexandre Julliard's avatar
Alexandre Julliard committed
1260
{
1261
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1262
        infoPtr->lSelMin = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1263
	return 0;
1264
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1265

1266
    infoPtr->lSelMin = lStart;
1267
    infoPtr->flags  |=TB_SELECTIONCHANGED;
1268

1269 1270
    if (infoPtr->lSelMin < infoPtr->lRangeMin)
        infoPtr->lSelMin = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1271

1272
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1273 1274 1275 1276 1277

    return 0;
}


1278
static inline LRESULT
1279
TRACKBAR_SetThumbLength (TRACKBAR_INFO *infoPtr, UINT iLength)
Alexandre Julliard's avatar
Alexandre Julliard committed
1280
{
1281
    if (infoPtr->dwStyle & TBS_FIXEDLENGTH) {
1282
        infoPtr->uThumbLen = iLength;
1283 1284 1285
	infoPtr->flags |= TB_THUMBSIZECHANGED;
	InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
    }
1286

Alexandre Julliard's avatar
Alexandre Julliard committed
1287 1288 1289 1290
    return 0;
}


1291
static inline LRESULT
1292
TRACKBAR_SetTic (TRACKBAR_INFO *infoPtr, LONG lPos)
Alexandre Julliard's avatar
Alexandre Julliard committed
1293
{
1294
    if ((lPos < infoPtr->lRangeMin) || (lPos> infoPtr->lRangeMax))
1295
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1296

1297
    TRACE("lPos=%d\n", lPos);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1298

1299
    infoPtr->uNumTics++;
1300
    infoPtr->tics=ReAlloc( infoPtr->tics,
1301
                                    (infoPtr->uNumTics)*sizeof (DWORD));
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1302 1303
    if (!infoPtr->tics) {
	infoPtr->uNumTics = 0;
1304
	notify(infoPtr, NM_OUTOFMEMORY);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1305 1306 1307
	return FALSE;
    }
    infoPtr->tics[infoPtr->uNumTics-1] = lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1308

1309
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1310 1311 1312 1313 1314

    return TRUE;
}


1315
static inline LRESULT
1316 1317
TRACKBAR_SetTicFreq (TRACKBAR_INFO *infoPtr, WORD wFreq)
{
1318
    if (infoPtr->dwStyle & TBS_AUTOTICKS) {
1319
        infoPtr->uTicFreq = wFreq;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1320
	TRACKBAR_RecalculateTics (infoPtr);
1321
	TRACKBAR_InvalidateAll(infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1322
    }
1323 1324 1325 1326 1327

    return 0;
}


1328
static inline INT
1329
TRACKBAR_SetTipSide (TRACKBAR_INFO *infoPtr, INT fLocation)
Alexandre Julliard's avatar
Alexandre Julliard committed
1330
{
1331
    INT fTemp = infoPtr->fLocation;
Alexandre Julliard's avatar
Alexandre Julliard committed
1332

1333
    infoPtr->fLocation = fLocation;
1334

Alexandre Julliard's avatar
Alexandre Julliard committed
1335 1336 1337 1338
    return fTemp;
}


1339
static inline LRESULT
1340
TRACKBAR_SetToolTips (TRACKBAR_INFO *infoPtr, HWND hwndTT)
Alexandre Julliard's avatar
Alexandre Julliard committed
1341
{
1342
    infoPtr->hwndToolTip = hwndTT;
Alexandre Julliard's avatar
Alexandre Julliard committed
1343 1344 1345 1346 1347

    return 0;
}


1348
static inline BOOL
1349 1350 1351 1352 1353 1354 1355 1356
TRACKBAR_SetUnicodeFormat (TRACKBAR_INFO *infoPtr, BOOL fUnicode)
{
    BOOL bTemp = infoPtr->bUnicode;

    infoPtr->bUnicode = fUnicode;

    return bTemp;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1357 1358


Alexandre Julliard's avatar
Alexandre Julliard committed
1359
static LRESULT
1360
TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1361
{
1362
    RECT rect;
1363
    int clientWidth, clientMetric;
1364 1365

    /* initial thumb length */
1366
    clientMetric = (infoPtr->dwStyle & TBS_ENABLESELRANGE) ? 23 : 21;
1367
    GetClientRect(infoPtr->hwndSelf,&rect);
1368
    if (infoPtr->dwStyle & TBS_VERT) {
1369
	clientWidth = rect.right - rect.left;
1370
    } else {
1371
	clientWidth = rect.bottom - rect.top;
1372
    }
1373 1374
    if (clientWidth >= clientMetric)
        infoPtr->uThumbLen = clientMetric;
1375 1376
    else
        infoPtr->uThumbLen = clientWidth > 9 ? clientWidth - 6 : 4;
Alexandre Julliard's avatar
Alexandre Julliard committed
1377

1378
    TRACKBAR_CalcChannel (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1379
    TRACKBAR_UpdateThumb (infoPtr);
1380
    infoPtr->flags &= ~TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1381

1382
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1383
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1384 1385 1386


static LRESULT
1387
TRACKBAR_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
1388 1389 1390
{
    TRACKBAR_INFO *infoPtr;

1391
    infoPtr = Alloc (sizeof(TRACKBAR_INFO));
1392
    if (!infoPtr) return -1;
1393
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1394

1395
    /* set default values */
1396
    infoPtr->hwndSelf  = hwnd;
1397
    infoPtr->dwStyle   = lpcs->style;
1398 1399 1400
    infoPtr->lRangeMin = 0;
    infoPtr->lRangeMax = 100;
    infoPtr->lLineSize = 1;
1401
    infoPtr->lPageSize = TB_DEFAULTPAGESIZE;
1402 1403 1404
    infoPtr->lSelMin   = 0;
    infoPtr->lSelMax   = 0;
    infoPtr->lPos      = 0;
1405
    infoPtr->fLocation = TBTS_TOP;
Alexandre Julliard's avatar
Alexandre Julliard committed
1406
    infoPtr->uNumTics  = 0;    /* start and end tic are not included in count*/
1407
    infoPtr->uTicFreq  = 1;
1408
    infoPtr->tics      = NULL;
1409
    infoPtr->hwndNotify= lpcs->hwndParent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1410

1411
    TRACKBAR_InitializeThumb (infoPtr);
Alex Priem's avatar
Alex Priem committed
1412

1413
    /* Create tooltip control */
1414
    if (infoPtr->dwStyle & TBS_TOOLTIPS) {
Alex Priem's avatar
Alex Priem committed
1415 1416

    	infoPtr->hwndToolTip =
1417
            CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1418 1419 1420
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             hwnd, 0, 0, 0);
Alex Priem's avatar
Alex Priem committed
1421

1422
    	if (infoPtr->hwndToolTip) {
1423
            TTTOOLINFOW ti;	    
1424 1425 1426 1427
            ZeroMemory (&ti, sizeof(ti));
            ti.cbSize   = sizeof(ti);
     	    ti.uFlags   = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
	    ti.hwnd     = hwnd;
Alex Priem's avatar
Alex Priem committed
1428

1429 1430
            SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
	 }
1431
    }
1432 1433
    
    OpenThemeData (hwnd, themeClass);
1434

Alexandre Julliard's avatar
Alexandre Julliard committed
1435 1436 1437 1438 1439
    return 0;
}


static LRESULT
1440
TRACKBAR_Destroy (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1441
{
1442
    /* delete tooltip control */
Alex Priem's avatar
Alex Priem committed
1443
    if (infoPtr->hwndToolTip)
1444
    	DestroyWindow (infoPtr->hwndToolTip);
Alex Priem's avatar
Alex Priem committed
1445

1446 1447 1448
    Free (infoPtr->tics);
    infoPtr->tics = NULL;

1449
    SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
1450
    CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
1451 1452
    Free (infoPtr);

Alexandre Julliard's avatar
Alexandre Julliard committed
1453 1454 1455 1456 1457
    return 0;
}


static LRESULT
1458
TRACKBAR_KillFocus (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1459
{
1460
    TRACE("\n");
1461
    infoPtr->bFocussed = FALSE;
1462
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1463 1464 1465 1466 1467

    return 0;
}

static LRESULT
1468
TRACKBAR_LButtonDown (TRACKBAR_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1469
{
1470 1471 1472 1473
    POINT clickPoint;

    clickPoint.x = x;
    clickPoint.y = y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1474

1475 1476
    SetFocus(infoPtr->hwndSelf);

1477
    if (PtInRect(&infoPtr->rcThumb, clickPoint)) {
1478
        infoPtr->flags |= TB_DRAG_MODE;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1479
        SetCapture (infoPtr->hwndSelf);
1480 1481
	TRACKBAR_UpdateToolTip (infoPtr);
	TRACKBAR_ActivateToolTip (infoPtr, TRUE);
1482
	TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1483
    } else {
1484 1485 1486 1487 1488 1489
	LONG dir = TRACKBAR_GetAutoPageDirection(infoPtr, clickPoint);
	if (dir == 0) return 0;
	infoPtr->flags |= (dir < 0) ? TB_AUTO_PAGE_LEFT : TB_AUTO_PAGE_RIGHT;
	TRACKBAR_AutoPage (infoPtr, clickPoint);
        SetCapture (infoPtr->hwndSelf);
        SetTimer(infoPtr->hwndSelf, TB_REFRESH_TIMER, TB_REFRESH_DELAY, 0);
1490
    }
1491

Alexandre Julliard's avatar
Alexandre Julliard committed
1492 1493 1494
    return 0;
}

1495

Alexandre Julliard's avatar
Alexandre Julliard committed
1496
static LRESULT
1497
TRACKBAR_LButtonUp (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1498
{
1499
    if (infoPtr->flags & TB_DRAG_MODE) {
1500 1501
        notify_with_scroll (infoPtr, TB_THUMBPOSITION | (infoPtr->lPos<<16));
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1502 1503
        infoPtr->flags &= ~TB_DRAG_MODE;
        ReleaseCapture ();
1504
	notify(infoPtr, NM_RELEASEDCAPTURE);
1505
        TRACKBAR_ActivateToolTip(infoPtr, FALSE);
1506
	TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
1507 1508 1509 1510
    }
    if (infoPtr->flags & TB_AUTO_PAGE) {
	KillTimer (infoPtr->hwndSelf, TB_REFRESH_TIMER);
        infoPtr->flags &= ~TB_AUTO_PAGE;
1511
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1512
        ReleaseCapture ();
1513
	notify(infoPtr, NM_RELEASEDCAPTURE);
1514
    }
1515

Alexandre Julliard's avatar
Alexandre Julliard committed
1516 1517 1518
    return 0;
}

1519

Alexandre Julliard's avatar
Alexandre Julliard committed
1520
static LRESULT
1521
TRACKBAR_CaptureChanged (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1522
{
1523
    notify_with_scroll (infoPtr, TB_ENDTRACK);
1524
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1525
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1526

1527

Alexandre Julliard's avatar
Alexandre Julliard committed
1528
static LRESULT
1529
TRACKBAR_Paint (TRACKBAR_INFO *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1530
{
1531 1532 1533 1534 1535 1536 1537 1538
    if (hdc) {
	TRACKBAR_Refresh(infoPtr, hdc);
    } else {
	PAINTSTRUCT ps;
    	hdc = BeginPaint (infoPtr->hwndSelf, &ps);
    	TRACKBAR_Refresh (infoPtr, hdc);
    	EndPaint (infoPtr->hwndSelf, &ps);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1539 1540 1541 1542 1543 1544

    return 0;
}


static LRESULT
1545
TRACKBAR_SetFocus (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1546
{
1547
    TRACE("\n");
1548
    infoPtr->bFocussed = TRUE;
1549
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1550 1551 1552 1553 1554 1555

    return 0;
}


static LRESULT
1556
TRACKBAR_Size (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1557
{
1558
    TRACKBAR_InitializeThumb (infoPtr);
1559
    TRACKBAR_AlignBuddies (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1560 1561 1562 1563

    return 0;
}

1564 1565 1566 1567 1568 1569 1570 1571 1572 1573
static LRESULT
TRACKBAR_StyleChanged (TRACKBAR_INFO *infoPtr, WPARAM wStyleType,
                       const STYLESTRUCT *lpss)
{
    if (wStyleType != GWL_STYLE) return 0;

    infoPtr->dwStyle = lpss->styleNew;

    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1574

1575
static LRESULT
1576
TRACKBAR_Timer (TRACKBAR_INFO *infoPtr)
1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587
{
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
	if (GetCursorPos(&pt))
	    if (ScreenToClient(infoPtr->hwndSelf, &pt))
		TRACKBAR_AutoPage(infoPtr, pt);
    }
    return 0;
}


1588
/* update theme after a WM_THEMECHANGED message */
1589
static LRESULT theme_changed (const TRACKBAR_INFO* infoPtr)
1590 1591 1592
{
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
    CloseThemeData (theme);
1593
    OpenThemeData (infoPtr->hwndSelf, themeClass);
1594 1595 1596 1597
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1598
static LRESULT
1599
TRACKBAR_MouseMove (TRACKBAR_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1600
{
1601
    INT clickPlace = (infoPtr->dwStyle & TBS_VERT) ? y : x;
1602
    LONG dragPos, oldPos = infoPtr->lPos;
1603

1604
    TRACE("(x=%d. y=%d)\n", x, y);
Alex Priem's avatar
Alex Priem committed
1605

1606 1607
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
1608 1609
	pt.x = x;
	pt.y = y;
1610
	TRACKBAR_AutoPage (infoPtr, pt);
1611
	return TRUE;
1612 1613
    }

1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
    if (!(infoPtr->flags & TB_DRAG_MODE)) 
    {
        if (GetWindowTheme (infoPtr->hwndSelf))
        {
            DWORD oldFlags = infoPtr->flags;
            POINT pt;
            pt.x = x;
            pt.y = y;
            if (PtInRect (&infoPtr->rcThumb, pt))
            {
                TRACKMOUSEEVENT tme;
                tme.cbSize = sizeof( tme );
                tme.dwFlags = TME_LEAVE;
                tme.hwndTrack = infoPtr->hwndSelf;
                TrackMouseEvent( &tme );
                infoPtr->flags |= TB_THUMB_HOT;
            }
            else
            {
                TRACKMOUSEEVENT tme;
                tme.cbSize = sizeof( tme );
                tme.dwFlags = TME_CANCEL;
                tme.hwndTrack = infoPtr->hwndSelf;
                TrackMouseEvent( &tme );
                infoPtr->flags &= ~TB_THUMB_HOT; 
            }
            if (oldFlags != infoPtr->flags) InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
        }
        return TRUE;
    }
Alex Priem's avatar
Alex Priem committed
1644

1645 1646
    dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace);

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1647
    if (dragPos == oldPos) return TRUE;
Alex Priem's avatar
Alex Priem committed
1648

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1649
    infoPtr->lPos = dragPos;
1650

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1651
    infoPtr->flags |= TB_THUMBPOSCHANGED;
1652
    notify_with_scroll (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16));
1653

Alex Priem's avatar
Alex Priem committed
1654

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1655
    TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos);
1656
    UpdateWindow (infoPtr->hwndSelf);
Alex Priem's avatar
Alex Priem committed
1657

1658
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1659 1660
}

1661
static BOOL
1662
TRACKBAR_KeyDown (TRACKBAR_INFO *infoPtr, INT nVirtKey)
Alexandre Julliard's avatar
Alexandre Julliard committed
1663
{
1664 1665
    BOOL downIsLeft = infoPtr->dwStyle & TBS_DOWNISLEFT;
    BOOL vert = infoPtr->dwStyle & TBS_VERT;
1666
    LONG pos = infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1667

1668
    TRACE("%x\n", nVirtKey);
Alexandre Julliard's avatar
Alexandre Julliard committed
1669

1670
    switch (nVirtKey) {
1671
    case VK_UP:
1672 1673 1674
	if (!vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
        else TRACKBAR_LineUp(infoPtr);
        break;
1675
    case VK_LEFT:
1676 1677
        if (vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
        else TRACKBAR_LineUp(infoPtr);
1678
        break;
1679
    case VK_DOWN:
1680 1681 1682
	if (!vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
        else TRACKBAR_LineDown(infoPtr);
        break;
1683
    case VK_RIGHT:
1684 1685
	if (vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
        else TRACKBAR_LineDown(infoPtr);
1686 1687
        break;
    case VK_NEXT:
1688 1689
	if (!vert && downIsLeft) TRACKBAR_PageUp(infoPtr);
        else TRACKBAR_PageDown(infoPtr);
1690 1691
        break;
    case VK_PRIOR:
1692 1693
	if (!vert && downIsLeft) TRACKBAR_PageDown(infoPtr);
        else TRACKBAR_PageUp(infoPtr);
1694
        break;
1695
    case VK_HOME:
1696 1697
        if (infoPtr->lPos == infoPtr->lRangeMin) return FALSE;
        infoPtr->lPos = infoPtr->lRangeMin;
1698
        notify_with_scroll (infoPtr, TB_TOP);
1699
        break;
1700
    case VK_END:
1701 1702
        if (infoPtr->lPos == infoPtr->lRangeMax) return FALSE;
        infoPtr->lPos = infoPtr->lRangeMax;
1703
        notify_with_scroll (infoPtr, TB_BOTTOM);
1704 1705
        break;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1706

1707
    if (pos != infoPtr->lPos) {
Alex Priem's avatar
Alex Priem committed
1708
	infoPtr->flags |=TB_THUMBPOSCHANGED;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1709
	TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos);
1710
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1711

1712
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1713 1714
}

1715

1716
static inline BOOL
1717
TRACKBAR_KeyUp (const TRACKBAR_INFO *infoPtr, INT nVirtKey)
Alexandre Julliard's avatar
Alexandre Julliard committed
1718
{
1719
    switch (nVirtKey) {
1720
    case VK_LEFT:
1721
    case VK_UP:
1722
    case VK_RIGHT:
1723
    case VK_DOWN:
1724 1725
    case VK_NEXT:
    case VK_PRIOR:
1726
    case VK_HOME:
1727
    case VK_END:
1728
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1729 1730
    }
    return TRUE;
Alex Priem's avatar
Alex Priem committed
1731 1732 1733
}


1734
static LRESULT WINAPI
1735
TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1736
{
1737
    TRACKBAR_INFO *infoPtr = (TRACKBAR_INFO *)GetWindowLongPtrW (hwnd, 0);
1738

1739
    TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, uMsg, wParam, lParam);
1740 1741 1742 1743

    if (!infoPtr && (uMsg != WM_CREATE))
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);

Alexandre Julliard's avatar
Alexandre Julliard committed
1744 1745
    switch (uMsg)
    {
1746
    case TBM_CLEARSEL:
1747
        return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1748

1749
    case TBM_CLEARTICS:
1750
        return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1751

1752
    case TBM_GETBUDDY:
1753
        return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB);
Alexandre Julliard's avatar
Alexandre Julliard committed
1754

1755
    case TBM_GETCHANNELRECT:
1756
        return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1757

1758
    case TBM_GETLINESIZE:
1759
        return infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1760

1761
    case TBM_GETNUMTICS:
1762
        return TRACKBAR_GetNumTics (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1763

1764
    case TBM_GETPAGESIZE:
1765
        return infoPtr->lPageSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1766

1767
    case TBM_GETPOS:
1768
        return infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1769

1770
    case TBM_GETPTICS:
1771
        return (LRESULT)infoPtr->tics;
Alexandre Julliard's avatar
Alexandre Julliard committed
1772

1773
    case TBM_GETRANGEMAX:
1774
        return infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1775

1776
    case TBM_GETRANGEMIN:
1777
        return infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1778

1779
    case TBM_GETSELEND:
1780
        return infoPtr->lSelMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1781

1782
    case TBM_GETSELSTART:
1783
        return infoPtr->lSelMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1784

1785
    case TBM_GETTHUMBLENGTH:
1786
        return infoPtr->uThumbLen;
Alexandre Julliard's avatar
Alexandre Julliard committed
1787

1788
    case TBM_GETTHUMBRECT:
1789
	return CopyRect((LPRECT)lParam, &infoPtr->rcThumb);
Alexandre Julliard's avatar
Alexandre Julliard committed
1790

Alexandre Julliard's avatar
Alexandre Julliard committed
1791
    case TBM_GETTIC:
1792
        return TRACKBAR_GetTic (infoPtr, (INT)wParam);
1793

Alexandre Julliard's avatar
Alexandre Julliard committed
1794
    case TBM_GETTICPOS:
1795
        return TRACKBAR_GetTicPos (infoPtr, (INT)wParam);
1796

1797
    case TBM_GETTOOLTIPS:
1798
        return (LRESULT)infoPtr->hwndToolTip;
Alexandre Julliard's avatar
Alexandre Julliard committed
1799

1800
    case TBM_GETUNICODEFORMAT:
1801
        return infoPtr->bUnicode;
Alexandre Julliard's avatar
Alexandre Julliard committed
1802

1803
    case TBM_SETBUDDY:
1804
        return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1805

1806
    case TBM_SETLINESIZE:
1807
        return TRACKBAR_SetLineSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1808

1809
    case TBM_SETPAGESIZE:
1810
        return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1811

1812
    case TBM_SETPOS:
1813
        return TRACKBAR_SetPos (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1814

1815
    case TBM_SETRANGE:
1816
        return TRACKBAR_SetRange (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1817

1818
    case TBM_SETRANGEMAX:
1819
        return TRACKBAR_SetRangeMax (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1820

1821
    case TBM_SETRANGEMIN:
1822
        return TRACKBAR_SetRangeMin (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1823

1824
    case TBM_SETSEL:
1825
        return TRACKBAR_SetSel (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1826

1827
    case TBM_SETSELEND:
1828
        return TRACKBAR_SetSelEnd (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1829

1830
    case TBM_SETSELSTART:
1831
        return TRACKBAR_SetSelStart (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1832

1833
    case TBM_SETTHUMBLENGTH:
1834
        return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1835

1836
    case TBM_SETTIC:
1837
        return TRACKBAR_SetTic (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1838

Alexandre Julliard's avatar
Alexandre Julliard committed
1839
    case TBM_SETTICFREQ:
1840
        return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1841

1842
    case TBM_SETTIPSIDE:
1843
        return TRACKBAR_SetTipSide (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1844

1845
    case TBM_SETTOOLTIPS:
1846
        return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1847

1848 1849
    case TBM_SETUNICODEFORMAT:
	return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1850 1851


1852
    case WM_CAPTURECHANGED:
1853
        return TRACKBAR_CaptureChanged (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1854

1855
    case WM_CREATE:
1856
        return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1857

1858
    case WM_DESTROY:
1859
        return TRACKBAR_Destroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1860

1861
/*	case WM_ENABLE: */
Alexandre Julliard's avatar
Alexandre Julliard committed
1862

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1863
    case WM_ERASEBKGND:
1864
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1865

1866 1867
    case WM_GETDLGCODE:
        return DLGC_WANTARROWS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1868

1869
    case WM_KEYDOWN:
1870
        return TRACKBAR_KeyDown (infoPtr, (INT)wParam);
1871

1872
    case WM_KEYUP:
1873
        return TRACKBAR_KeyUp (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1874

1875
    case WM_KILLFOCUS:
1876
        return TRACKBAR_KillFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1877

1878
    case WM_LBUTTONDOWN:
1879
        return TRACKBAR_LButtonDown (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
1880

1881
    case WM_LBUTTONUP:
1882
        return TRACKBAR_LButtonUp (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1883

1884 1885 1886 1887 1888
    case WM_MOUSELEAVE:
        infoPtr->flags &= ~TB_THUMB_HOT; 
        InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
        return 0;
    
1889
    case WM_MOUSEMOVE:
1890
        return TRACKBAR_MouseMove (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
1891

1892
    case WM_PRINTCLIENT:
1893
    case WM_PAINT:
1894
        return TRACKBAR_Paint (infoPtr, (HDC)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1895

1896
    case WM_SETFOCUS:
1897
        return TRACKBAR_SetFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1898

1899
    case WM_SIZE:
1900
        return TRACKBAR_Size (infoPtr);
1901 1902 1903

    case WM_STYLECHANGED:
        return TRACKBAR_StyleChanged (infoPtr, wParam, (LPSTYLESTRUCT)lParam);
1904

1905 1906 1907
    case WM_THEMECHANGED:
        return theme_changed (infoPtr);

1908
    case WM_TIMER:
1909
	return TRACKBAR_Timer (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1910

1911
    case WM_WININICHANGE:
1912
        return TRACKBAR_InitializeThumb (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1913

1914
    default:
1915
        if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
1916
            ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);
1917
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1918 1919 1920 1921
    }
}


1922
void TRACKBAR_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1923
{
1924
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
1925

1926
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
1927
    wndClass.style         = CS_GLOBALCLASS;
1928
    wndClass.lpfnWndProc   = TRACKBAR_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1929 1930
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(TRACKBAR_INFO *);
1931
    wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
1932
    wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1933
    wndClass.lpszClassName = TRACKBAR_CLASSW;
1934

1935
    RegisterClassW (&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
1936
}
1937 1938


1939
void TRACKBAR_Unregister (void)
1940
{
1941
    UnregisterClassW (TRACKBAR_CLASSW, NULL);
1942
}