trackbar.c 52.8 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
#include "uxtheme.h"
45
#include "vssym32.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
    else return FALSE;

460
    TRACKBAR_UpdateThumb (infoPtr);
461 462 463 464 465
    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 redraw, LONG range)
Alexandre Julliard's avatar
Alexandre Julliard committed
1155
{
1156 1157 1158 1159 1160
    BOOL changed = infoPtr->lRangeMin != (SHORT)LOWORD(range) ||
                   infoPtr->lRangeMax != (SHORT)HIWORD(range);

    infoPtr->lRangeMin = (SHORT)LOWORD(range);
    infoPtr->lRangeMax = (SHORT)HIWORD(range);
Alexandre Julliard's avatar
Alexandre Julliard committed
1161

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

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

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

1175 1176 1177 1178
    if (changed && (infoPtr->dwStyle & TBS_AUTOTICKS))
        TRACKBAR_RecalculateTics (infoPtr);

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1179 1180 1181 1182 1183

    return 0;
}


1184
static inline LRESULT
1185
TRACKBAR_SetRangeMax (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG lMax)
Alexandre Julliard's avatar
Alexandre Julliard committed
1186
{
1187 1188
    BOOL changed = infoPtr->lRangeMax != lMax;

1189 1190 1191
    infoPtr->lRangeMax = lMax;
    if (infoPtr->lPos > infoPtr->lRangeMax) {
        infoPtr->lPos = infoPtr->lRangeMax;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1192
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1193
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1194

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

1198 1199 1200 1201
    if (changed && (infoPtr->dwStyle & TBS_AUTOTICKS))
        TRACKBAR_RecalculateTics (infoPtr);

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1202 1203 1204 1205 1206

    return 0;
}


1207
static inline LRESULT
1208
TRACKBAR_SetRangeMin (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG lMin)
Alexandre Julliard's avatar
Alexandre Julliard committed
1209
{
1210 1211
    BOOL changed = infoPtr->lRangeMin != lMin;

1212 1213 1214
    infoPtr->lRangeMin = lMin;
    if (infoPtr->lPos < infoPtr->lRangeMin) {
        infoPtr->lPos = infoPtr->lRangeMin;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1215
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1216
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1217

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

1221 1222 1223 1224
    if (changed && (infoPtr->dwStyle & TBS_AUTOTICKS))
        TRACKBAR_RecalculateTics (infoPtr);

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1225 1226 1227 1228

    return 0;
}

1229

1230
static inline LRESULT
1231
TRACKBAR_SetSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lSel)
Alexandre Julliard's avatar
Alexandre Julliard committed
1232
{
1233
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1234 1235
        infoPtr->lSelMin = 0;
        infoPtr->lSelMax = 0;
1236
        return 0;
1237
    }
1238

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1239 1240 1241
    infoPtr->lSelMin = (SHORT)LOWORD(lSel);
    infoPtr->lSelMax = (SHORT)HIWORD(lSel);
    infoPtr->flags |= TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1242

1243 1244 1245 1246
    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
1247

1248
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1249 1250 1251 1252 1253

    return 0;
}


1254
static inline LRESULT
1255
TRACKBAR_SetSelEnd (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lEnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
1256
{
1257
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1258
        infoPtr->lSelMax = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1259
	return 0;
1260
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1261

1262
    infoPtr->lSelMax = lEnd;
1263
    infoPtr->flags |= TB_SELECTIONCHANGED;
1264

1265 1266
    if (infoPtr->lSelMax > infoPtr->lRangeMax)
        infoPtr->lSelMax = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1267

1268
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1269 1270 1271 1272 1273

    return 0;
}


1274
static inline LRESULT
1275
TRACKBAR_SetSelStart (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lStart)
Alexandre Julliard's avatar
Alexandre Julliard committed
1276
{
1277
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1278
        infoPtr->lSelMin = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1279
	return 0;
1280
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1281

1282
    infoPtr->lSelMin = lStart;
1283
    infoPtr->flags  |=TB_SELECTIONCHANGED;
1284

1285 1286
    if (infoPtr->lSelMin < infoPtr->lRangeMin)
        infoPtr->lSelMin = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1287

1288
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1289 1290 1291 1292 1293

    return 0;
}


1294
static inline LRESULT
1295
TRACKBAR_SetThumbLength (TRACKBAR_INFO *infoPtr, UINT iLength)
Alexandre Julliard's avatar
Alexandre Julliard committed
1296
{
1297
    if (infoPtr->dwStyle & TBS_FIXEDLENGTH) {
1298
        infoPtr->uThumbLen = iLength;
1299 1300 1301
	infoPtr->flags |= TB_THUMBSIZECHANGED;
	InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
    }
1302

Alexandre Julliard's avatar
Alexandre Julliard committed
1303 1304 1305 1306
    return 0;
}


1307
static inline LRESULT
1308
TRACKBAR_SetTic (TRACKBAR_INFO *infoPtr, LONG lPos)
Alexandre Julliard's avatar
Alexandre Julliard committed
1309
{
1310
    if ((lPos < infoPtr->lRangeMin) || (lPos> infoPtr->lRangeMax))
1311
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1312

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

1315
    infoPtr->uNumTics++;
1316
    infoPtr->tics=ReAlloc( infoPtr->tics,
1317
                                    (infoPtr->uNumTics)*sizeof (DWORD));
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1318 1319
    if (!infoPtr->tics) {
	infoPtr->uNumTics = 0;
1320
	notify(infoPtr, NM_OUTOFMEMORY);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1321 1322 1323
	return FALSE;
    }
    infoPtr->tics[infoPtr->uNumTics-1] = lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1324

1325
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1326 1327 1328 1329 1330

    return TRUE;
}


1331
static inline LRESULT
1332 1333
TRACKBAR_SetTicFreq (TRACKBAR_INFO *infoPtr, WORD wFreq)
{
1334
    if (infoPtr->dwStyle & TBS_AUTOTICKS) {
1335
        infoPtr->uTicFreq = wFreq;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1336
	TRACKBAR_RecalculateTics (infoPtr);
1337
	TRACKBAR_InvalidateAll(infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1338
    }
1339 1340 1341 1342 1343

    return 0;
}


1344
static inline INT
1345
TRACKBAR_SetTipSide (TRACKBAR_INFO *infoPtr, INT fLocation)
Alexandre Julliard's avatar
Alexandre Julliard committed
1346
{
1347
    INT fTemp = infoPtr->fLocation;
Alexandre Julliard's avatar
Alexandre Julliard committed
1348

1349
    infoPtr->fLocation = fLocation;
1350

Alexandre Julliard's avatar
Alexandre Julliard committed
1351 1352 1353 1354
    return fTemp;
}


1355
static inline LRESULT
1356
TRACKBAR_SetToolTips (TRACKBAR_INFO *infoPtr, HWND hwndTT)
Alexandre Julliard's avatar
Alexandre Julliard committed
1357
{
1358
    infoPtr->hwndToolTip = hwndTT;
Alexandre Julliard's avatar
Alexandre Julliard committed
1359 1360 1361 1362 1363

    return 0;
}


1364
static inline BOOL
1365 1366 1367 1368 1369 1370 1371 1372
TRACKBAR_SetUnicodeFormat (TRACKBAR_INFO *infoPtr, BOOL fUnicode)
{
    BOOL bTemp = infoPtr->bUnicode;

    infoPtr->bUnicode = fUnicode;

    return bTemp;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1373 1374


Alexandre Julliard's avatar
Alexandre Julliard committed
1375
static LRESULT
1376
TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1377
{
1378
    RECT rect;
1379
    int clientWidth, clientMetric;
1380 1381

    /* initial thumb length */
1382
    clientMetric = (infoPtr->dwStyle & TBS_ENABLESELRANGE) ? 23 : 21;
1383
    GetClientRect(infoPtr->hwndSelf,&rect);
1384
    if (infoPtr->dwStyle & TBS_VERT) {
1385
	clientWidth = rect.right - rect.left;
1386
    } else {
1387
	clientWidth = rect.bottom - rect.top;
1388
    }
1389 1390
    if (clientWidth >= clientMetric)
        infoPtr->uThumbLen = clientMetric;
1391 1392
    else
        infoPtr->uThumbLen = clientWidth > 9 ? clientWidth - 6 : 4;
Alexandre Julliard's avatar
Alexandre Julliard committed
1393

1394
    TRACKBAR_CalcChannel (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1395
    TRACKBAR_UpdateThumb (infoPtr);
1396
    infoPtr->flags &= ~TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1397

1398
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1399
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1400 1401 1402


static LRESULT
1403
TRACKBAR_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
1404 1405 1406
{
    TRACKBAR_INFO *infoPtr;

1407
    infoPtr = Alloc (sizeof(TRACKBAR_INFO));
1408
    if (!infoPtr) return -1;
1409
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1410

1411
    /* set default values */
1412
    infoPtr->hwndSelf  = hwnd;
1413
    infoPtr->dwStyle   = lpcs->style;
1414 1415 1416
    infoPtr->lRangeMin = 0;
    infoPtr->lRangeMax = 100;
    infoPtr->lLineSize = 1;
1417
    infoPtr->lPageSize = TB_DEFAULTPAGESIZE;
1418 1419 1420
    infoPtr->lSelMin   = 0;
    infoPtr->lSelMax   = 0;
    infoPtr->lPos      = 0;
1421
    infoPtr->fLocation = TBTS_TOP;
Alexandre Julliard's avatar
Alexandre Julliard committed
1422
    infoPtr->uNumTics  = 0;    /* start and end tic are not included in count*/
1423
    infoPtr->uTicFreq  = 1;
1424
    infoPtr->tics      = NULL;
1425
    infoPtr->hwndNotify= lpcs->hwndParent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1426

1427
    TRACKBAR_InitializeThumb (infoPtr);
Alex Priem's avatar
Alex Priem committed
1428

1429
    /* Create tooltip control */
1430
    if (infoPtr->dwStyle & TBS_TOOLTIPS) {
Alex Priem's avatar
Alex Priem committed
1431 1432

    	infoPtr->hwndToolTip =
1433
            CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1434 1435 1436
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             hwnd, 0, 0, 0);
Alex Priem's avatar
Alex Priem committed
1437

1438
    	if (infoPtr->hwndToolTip) {
1439
            TTTOOLINFOW ti;	    
1440 1441 1442 1443
            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
1444

1445 1446
            SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
	 }
1447
    }
1448 1449
    
    OpenThemeData (hwnd, themeClass);
1450

Alexandre Julliard's avatar
Alexandre Julliard committed
1451 1452 1453 1454 1455
    return 0;
}


static LRESULT
1456
TRACKBAR_Destroy (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1457
{
1458
    /* delete tooltip control */
Alex Priem's avatar
Alex Priem committed
1459
    if (infoPtr->hwndToolTip)
1460
    	DestroyWindow (infoPtr->hwndToolTip);
Alex Priem's avatar
Alex Priem committed
1461

1462 1463 1464
    Free (infoPtr->tics);
    infoPtr->tics = NULL;

1465
    SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
1466
    CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
1467 1468
    Free (infoPtr);

Alexandre Julliard's avatar
Alexandre Julliard committed
1469 1470 1471 1472 1473
    return 0;
}


static LRESULT
1474
TRACKBAR_KillFocus (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1475
{
1476
    TRACE("\n");
1477
    infoPtr->bFocussed = FALSE;
1478
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1479 1480 1481 1482 1483

    return 0;
}

static LRESULT
1484
TRACKBAR_LButtonDown (TRACKBAR_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1485
{
1486 1487 1488 1489
    POINT clickPoint;

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

1491 1492
    SetFocus(infoPtr->hwndSelf);

1493
    if (PtInRect(&infoPtr->rcThumb, clickPoint)) {
1494
        infoPtr->flags |= TB_DRAG_MODE;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1495
        SetCapture (infoPtr->hwndSelf);
1496 1497
	TRACKBAR_UpdateToolTip (infoPtr);
	TRACKBAR_ActivateToolTip (infoPtr, TRUE);
1498
	TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1499
    } else {
1500 1501 1502 1503 1504 1505
	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);
1506
    }
1507

Alexandre Julliard's avatar
Alexandre Julliard committed
1508 1509 1510
    return 0;
}

1511

Alexandre Julliard's avatar
Alexandre Julliard committed
1512
static LRESULT
1513
TRACKBAR_LButtonUp (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1514
{
1515
    if (infoPtr->flags & TB_DRAG_MODE) {
1516 1517
        notify_with_scroll (infoPtr, TB_THUMBPOSITION | (infoPtr->lPos<<16));
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1518 1519
        infoPtr->flags &= ~TB_DRAG_MODE;
        ReleaseCapture ();
1520
	notify(infoPtr, NM_RELEASEDCAPTURE);
1521
        TRACKBAR_ActivateToolTip(infoPtr, FALSE);
1522
	TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
1523 1524 1525 1526
    }
    if (infoPtr->flags & TB_AUTO_PAGE) {
	KillTimer (infoPtr->hwndSelf, TB_REFRESH_TIMER);
        infoPtr->flags &= ~TB_AUTO_PAGE;
1527
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1528
        ReleaseCapture ();
1529
	notify(infoPtr, NM_RELEASEDCAPTURE);
1530
    }
1531

Alexandre Julliard's avatar
Alexandre Julliard committed
1532 1533 1534
    return 0;
}

1535

Alexandre Julliard's avatar
Alexandre Julliard committed
1536
static LRESULT
1537
TRACKBAR_CaptureChanged (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1538
{
1539
    notify_with_scroll (infoPtr, TB_ENDTRACK);
1540
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1541
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1542

1543

Alexandre Julliard's avatar
Alexandre Julliard committed
1544
static LRESULT
1545
TRACKBAR_Paint (TRACKBAR_INFO *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1546
{
1547 1548 1549 1550 1551 1552 1553 1554
    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
1555 1556 1557 1558 1559 1560

    return 0;
}


static LRESULT
1561
TRACKBAR_SetFocus (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1562
{
1563
    TRACE("\n");
1564
    infoPtr->bFocussed = TRUE;
1565
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1566 1567 1568 1569 1570 1571

    return 0;
}


static LRESULT
1572
TRACKBAR_Size (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1573
{
1574 1575
    TRACKBAR_CalcChannel (infoPtr);
    TRACKBAR_UpdateThumb (infoPtr);
1576
    TRACKBAR_AlignBuddies (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1577 1578 1579 1580

    return 0;
}

1581 1582 1583 1584 1585 1586 1587 1588 1589 1590
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
1591

1592
static LRESULT
1593
TRACKBAR_Timer (TRACKBAR_INFO *infoPtr)
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604
{
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
	if (GetCursorPos(&pt))
	    if (ScreenToClient(infoPtr->hwndSelf, &pt))
		TRACKBAR_AutoPage(infoPtr, pt);
    }
    return 0;
}


1605
/* update theme after a WM_THEMECHANGED message */
1606
static LRESULT theme_changed (const TRACKBAR_INFO* infoPtr)
1607 1608 1609
{
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
    CloseThemeData (theme);
1610
    OpenThemeData (infoPtr->hwndSelf, themeClass);
1611 1612 1613 1614
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1615
static LRESULT
1616
TRACKBAR_MouseMove (TRACKBAR_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1617
{
1618
    INT clickPlace = (infoPtr->dwStyle & TBS_VERT) ? y : x;
1619
    LONG dragPos, oldPos = infoPtr->lPos;
1620

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

1623 1624
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
1625 1626
	pt.x = x;
	pt.y = y;
1627
	TRACKBAR_AutoPage (infoPtr, pt);
1628
	return TRUE;
1629 1630
    }

1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660
    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
1661

1662 1663
    dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace);

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1666
    infoPtr->lPos = dragPos;
1667
    TRACKBAR_UpdateThumb (infoPtr);
1668

1669
    notify_with_scroll (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16));
1670

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1671
    TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos);
1672
    UpdateWindow (infoPtr->hwndSelf);
Alex Priem's avatar
Alex Priem committed
1673

1674
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1675 1676
}

1677
static BOOL
1678
TRACKBAR_KeyDown (TRACKBAR_INFO *infoPtr, INT nVirtKey)
Alexandre Julliard's avatar
Alexandre Julliard committed
1679
{
1680 1681
    BOOL downIsLeft = infoPtr->dwStyle & TBS_DOWNISLEFT;
    BOOL vert = infoPtr->dwStyle & TBS_VERT;
1682
    LONG pos = infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1683

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

1686
    switch (nVirtKey) {
1687
    case VK_UP:
1688 1689 1690
	if (!vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
        else TRACKBAR_LineUp(infoPtr);
        break;
1691
    case VK_LEFT:
1692 1693
        if (vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
        else TRACKBAR_LineUp(infoPtr);
1694
        break;
1695
    case VK_DOWN:
1696 1697 1698
	if (!vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
        else TRACKBAR_LineDown(infoPtr);
        break;
1699
    case VK_RIGHT:
1700 1701
	if (vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
        else TRACKBAR_LineDown(infoPtr);
1702 1703
        break;
    case VK_NEXT:
1704 1705
	if (!vert && downIsLeft) TRACKBAR_PageUp(infoPtr);
        else TRACKBAR_PageDown(infoPtr);
1706 1707
        break;
    case VK_PRIOR:
1708 1709
	if (!vert && downIsLeft) TRACKBAR_PageDown(infoPtr);
        else TRACKBAR_PageUp(infoPtr);
1710
        break;
1711
    case VK_HOME:
1712 1713
        if (infoPtr->lPos == infoPtr->lRangeMin) return FALSE;
        infoPtr->lPos = infoPtr->lRangeMin;
1714
        notify_with_scroll (infoPtr, TB_TOP);
1715
        break;
1716
    case VK_END:
1717 1718
        if (infoPtr->lPos == infoPtr->lRangeMax) return FALSE;
        infoPtr->lPos = infoPtr->lRangeMax;
1719
        notify_with_scroll (infoPtr, TB_BOTTOM);
1720 1721
        break;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1722

1723
    if (pos != infoPtr->lPos) {
Alex Priem's avatar
Alex Priem committed
1724
	infoPtr->flags |=TB_THUMBPOSCHANGED;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1725
	TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos);
1726
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1727

1728
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1729 1730
}

1731

1732
static inline BOOL
1733
TRACKBAR_KeyUp (const TRACKBAR_INFO *infoPtr, INT nVirtKey)
Alexandre Julliard's avatar
Alexandre Julliard committed
1734
{
1735
    switch (nVirtKey) {
1736
    case VK_LEFT:
1737
    case VK_UP:
1738
    case VK_RIGHT:
1739
    case VK_DOWN:
1740 1741
    case VK_NEXT:
    case VK_PRIOR:
1742
    case VK_HOME:
1743
    case VK_END:
1744
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1745 1746
    }
    return TRUE;
Alex Priem's avatar
Alex Priem committed
1747 1748 1749
}


1750
static LRESULT WINAPI
1751
TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1752
{
1753
    TRACKBAR_INFO *infoPtr = (TRACKBAR_INFO *)GetWindowLongPtrW (hwnd, 0);
1754

1755
    TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, uMsg, wParam, lParam);
1756 1757 1758 1759

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1760 1761
    switch (uMsg)
    {
1762
    case TBM_CLEARSEL:
1763
        return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1764

1765
    case TBM_CLEARTICS:
1766
        return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1767

1768
    case TBM_GETBUDDY:
1769
        return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB);
Alexandre Julliard's avatar
Alexandre Julliard committed
1770

1771
    case TBM_GETCHANNELRECT:
1772
        return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1773

1774
    case TBM_GETLINESIZE:
1775
        return infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1776

1777
    case TBM_GETNUMTICS:
1778
        return TRACKBAR_GetNumTics (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1779

1780
    case TBM_GETPAGESIZE:
1781
        return infoPtr->lPageSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1782

1783
    case TBM_GETPOS:
1784
        return infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1785

1786
    case TBM_GETPTICS:
1787
        return (LRESULT)infoPtr->tics;
Alexandre Julliard's avatar
Alexandre Julliard committed
1788

1789
    case TBM_GETRANGEMAX:
1790
        return infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1791

1792
    case TBM_GETRANGEMIN:
1793
        return infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1794

1795
    case TBM_GETSELEND:
1796
        return infoPtr->lSelMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1797

1798
    case TBM_GETSELSTART:
1799
        return infoPtr->lSelMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1800

1801
    case TBM_GETTHUMBLENGTH:
1802
        return infoPtr->uThumbLen;
Alexandre Julliard's avatar
Alexandre Julliard committed
1803

1804
    case TBM_GETTHUMBRECT:
1805
	return CopyRect((LPRECT)lParam, &infoPtr->rcThumb);
Alexandre Julliard's avatar
Alexandre Julliard committed
1806

Alexandre Julliard's avatar
Alexandre Julliard committed
1807
    case TBM_GETTIC:
1808
        return TRACKBAR_GetTic (infoPtr, (INT)wParam);
1809

Alexandre Julliard's avatar
Alexandre Julliard committed
1810
    case TBM_GETTICPOS:
1811
        return TRACKBAR_GetTicPos (infoPtr, (INT)wParam);
1812

1813
    case TBM_GETTOOLTIPS:
1814
        return (LRESULT)infoPtr->hwndToolTip;
Alexandre Julliard's avatar
Alexandre Julliard committed
1815

1816
    case TBM_GETUNICODEFORMAT:
1817
        return infoPtr->bUnicode;
Alexandre Julliard's avatar
Alexandre Julliard committed
1818

1819
    case TBM_SETBUDDY:
1820
        return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1821

1822
    case TBM_SETLINESIZE:
1823
        return TRACKBAR_SetLineSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1824

1825
    case TBM_SETPAGESIZE:
1826
        return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1827

1828
    case TBM_SETPOS:
1829
        return TRACKBAR_SetPos (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1830

1831
    case TBM_SETRANGE:
1832
        return TRACKBAR_SetRange (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1833

1834
    case TBM_SETRANGEMAX:
1835
        return TRACKBAR_SetRangeMax (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1836

1837
    case TBM_SETRANGEMIN:
1838
        return TRACKBAR_SetRangeMin (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1839

1840
    case TBM_SETSEL:
1841
        return TRACKBAR_SetSel (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1842

1843
    case TBM_SETSELEND:
1844
        return TRACKBAR_SetSelEnd (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1845

1846
    case TBM_SETSELSTART:
1847
        return TRACKBAR_SetSelStart (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1848

1849
    case TBM_SETTHUMBLENGTH:
1850
        return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1851

1852
    case TBM_SETTIC:
1853
        return TRACKBAR_SetTic (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1854

Alexandre Julliard's avatar
Alexandre Julliard committed
1855
    case TBM_SETTICFREQ:
1856
        return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1857

1858
    case TBM_SETTIPSIDE:
1859
        return TRACKBAR_SetTipSide (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1860

1861
    case TBM_SETTOOLTIPS:
1862
        return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1863

1864 1865
    case TBM_SETUNICODEFORMAT:
	return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1866 1867


1868
    case WM_CAPTURECHANGED:
1869
        return TRACKBAR_CaptureChanged (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1870

1871
    case WM_CREATE:
1872
        return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1873

1874
    case WM_DESTROY:
1875
        return TRACKBAR_Destroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1876

1877
/*	case WM_ENABLE: */
Alexandre Julliard's avatar
Alexandre Julliard committed
1878

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1879
    case WM_ERASEBKGND:
1880
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1881

1882 1883
    case WM_GETDLGCODE:
        return DLGC_WANTARROWS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1884

1885
    case WM_KEYDOWN:
1886
        return TRACKBAR_KeyDown (infoPtr, (INT)wParam);
1887

1888
    case WM_KEYUP:
1889
        return TRACKBAR_KeyUp (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1890

1891
    case WM_KILLFOCUS:
1892
        return TRACKBAR_KillFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1893

1894
    case WM_LBUTTONDOWN:
1895
        return TRACKBAR_LButtonDown (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
1896

1897
    case WM_LBUTTONUP:
1898
        return TRACKBAR_LButtonUp (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1899

1900 1901 1902 1903 1904
    case WM_MOUSELEAVE:
        infoPtr->flags &= ~TB_THUMB_HOT; 
        InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
        return 0;
    
1905
    case WM_MOUSEMOVE:
1906
        return TRACKBAR_MouseMove (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
1907

1908
    case WM_PRINTCLIENT:
1909
    case WM_PAINT:
1910
        return TRACKBAR_Paint (infoPtr, (HDC)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1911

1912
    case WM_SETFOCUS:
1913
        return TRACKBAR_SetFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1914

1915
    case WM_SIZE:
1916
        return TRACKBAR_Size (infoPtr);
1917 1918 1919

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

1921 1922 1923
    case WM_THEMECHANGED:
        return theme_changed (infoPtr);

1924
    case WM_TIMER:
1925
	return TRACKBAR_Timer (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1926

1927
    case WM_WININICHANGE:
1928
        return TRACKBAR_InitializeThumb (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1929

1930
    default:
1931
        if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
1932
            ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);
1933
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1934 1935 1936 1937
    }
}


1938
void TRACKBAR_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1939
{
1940
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
1941

1942
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
1943
    wndClass.style         = CS_GLOBALCLASS;
1944
    wndClass.lpfnWndProc   = TRACKBAR_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1945 1946
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(TRACKBAR_INFO *);
1947
    wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
1948
    wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1949
    wndClass.lpszClassName = TRACKBAR_CLASSW;
1950

1951
    RegisterClassW (&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
1952
}
1953 1954


1955
void TRACKBAR_Unregister (void)
1956
{
1957
    UnregisterClassW (TRACKBAR_CLASSW, NULL);
1958
}