trackbar.c 57.2 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
#include <stdarg.h>
24
#include <stdio.h>
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
25
#include <stdlib.h>
26
#include <string.h>
27
#include <math.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
28

29
#include "windef.h"
30
#include "winbase.h"
31 32 33
#include "wingdi.h"
#include "winuser.h"
#include "winnls.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
34
#include "commctrl.h"
35
#include "uxtheme.h"
36
#include "vssym32.h"
37
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
38

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
39 40
#include "comctl32.h"

41
WINE_DEFAULT_DEBUG_CHANNEL(trackbar);
42

43 44
typedef struct
{
45
    HWND hwndSelf;
46
    DWORD dwStyle;
47 48 49 50 51 52 53
    LONG lRangeMin;
    LONG lRangeMax;
    LONG lLineSize;
    LONG lPageSize;
    LONG lSelMin;
    LONG lSelMax;
    LONG lPos;
54 55
    UINT uThumbLen;
    UINT uNumTics;
56
    UINT uTicFreq;
57 58 59 60 61
    HWND hwndNotify;
    HWND hwndToolTip;
    HWND hwndBuddyLA;
    HWND hwndBuddyRB;
    INT  fLocation;
62
    DWORD flags;
63
    BOOL bUnicode;
64 65 66 67 68 69
    RECT rcChannel;
    RECT rcSelection;
    RECT rcThumb;
    LPLONG tics;
} TRACKBAR_INFO;

70 71
#define TB_REFRESH_TIMER	1
#define TB_REFRESH_DELAY	500
Alexandre Julliard's avatar
Alexandre Julliard committed
72

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

75 76
#define TB_DEFAULTPAGESIZE	20

77
/* Used by TRACKBAR_Refresh to find out which parts of the control
78
   need to be recalculated */
Alexandre Julliard's avatar
Alexandre Julliard committed
79

80 81 82 83 84 85 86 87 88 89 90 91
#define TB_THUMBPOSCHANGED      0x00000001
#define TB_THUMBSIZECHANGED     0x00000002
#define TB_THUMBCHANGED        (TB_THUMBPOSCHANGED | TB_THUMBSIZECHANGED)
#define TB_SELECTIONCHANGED     0x00000004
#define TB_DRAG_MODE            0x00000008     /* we're dragging the slider */
#define TB_AUTO_PAGE_LEFT       0x00000010
#define TB_AUTO_PAGE_RIGHT      0x00000020
#define TB_AUTO_PAGE           (TB_AUTO_PAGE_LEFT | TB_AUTO_PAGE_RIGHT)
#define TB_THUMB_HOT            0x00000040    /* mouse hovers above thumb */

/* Page was set with TBM_SETPAGESIZE */
#define TB_USER_PAGE            0x00000080
92
#define TB_IS_FOCUSED           0x00000100
Alexandre Julliard's avatar
Alexandre Julliard committed
93

Alex Priem's avatar
Alex Priem committed
94
/* helper defines for TRACKBAR_DrawTic */
95
#define TIC_EDGE                0x20
96 97 98
#define TIC_SELECTIONMARKMAX    0x80
#define TIC_SELECTIONMARKMIN    0x100
#define TIC_SELECTIONMARK       (TIC_SELECTIONMARKMAX | TIC_SELECTIONMARKMIN)
Alex Priem's avatar
Alex Priem committed
99

100
static const WCHAR themeClass[] = L"Trackbar";
101

102
static inline int 
103
notify_customdraw (const TRACKBAR_INFO *infoPtr, NMCUSTOMDRAW *pnmcd, int stage)
104 105
{
    pnmcd->dwDrawStage = stage;
106
    return SendMessageW (infoPtr->hwndNotify, WM_NOTIFY, 
107 108 109
		         pnmcd->hdr.idFrom, (LPARAM)pnmcd);
}

110
static LRESULT notify_hdr (const TRACKBAR_INFO *infoPtr, INT code, LPNMHDR pnmh)
111 112 113 114 115 116
{
    LRESULT result;
    
    TRACE("(code=%d)\n", code);

    pnmh->hwndFrom = infoPtr->hwndSelf;
117
    pnmh->idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
118
    pnmh->code = code;
119
    result = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY, pnmh->idFrom, (LPARAM)pnmh);
120 121 122 123 124 125

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

    return result;
}

126
static inline int notify (const TRACKBAR_INFO *infoPtr, INT code)
127 128 129 130 131
{
    NMHDR nmh;
    return notify_hdr(infoPtr, code, &nmh);
}

132
static void notify_with_scroll (const TRACKBAR_INFO *infoPtr, UINT code)
133
{
134
    UINT scroll = infoPtr->dwStyle & TBS_VERT ? WM_VSCROLL : WM_HSCROLL;
135 136 137

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

138
    SendMessageW (infoPtr->hwndNotify, scroll, code, (LPARAM)infoPtr->hwndSelf);
139
}
140

141
static void TRACKBAR_RecalculateTics (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
142
{
143 144
    int tic;
    unsigned nrTics, i;
Alexandre Julliard's avatar
Alexandre Julliard committed
145

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
159
    if (nrTics != infoPtr->uNumTics) {
160
    	infoPtr->tics=ReAlloc (infoPtr->tics,
161
                                        (nrTics+1)*sizeof (DWORD));
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
162 163
	if (!infoPtr->tics) {
	    infoPtr->uNumTics = 0;
164
	    notify(infoPtr, NM_OUTOFMEMORY);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
165 166 167
	    return;
	}
    	infoPtr->uNumTics = nrTics;
Alexandre Julliard's avatar
Alexandre Julliard committed
168
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
169

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
170 171 172 173
    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
174

175
/* converts from physical (mouse) position to logical position
Alex Priem's avatar
Alex Priem committed
176
   (in range of trackbar) */
Alexandre Julliard's avatar
Alexandre Julliard committed
177

178
static inline LONG
179
TRACKBAR_ConvertPlaceToPosition (const TRACKBAR_INFO *infoPtr, int place)
Alexandre Julliard's avatar
Alexandre Julliard committed
180
{
181
    double range, width, pos, offsetthumb;
Alexandre Julliard's avatar
Alexandre Julliard committed
182

183
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
184
    if (infoPtr->dwStyle & TBS_VERT) {
185 186
        offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2;
        width = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - (offsetthumb * 2) - 1;
187
        pos = (range*(place - infoPtr->rcChannel.top - offsetthumb)) / width;
188
    } else {
189 190
        offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2;
        width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - (offsetthumb * 2) - 1;
191
        pos = (range*(place - infoPtr->rcChannel.left - offsetthumb)) / width;
192
    }
193 194 195 196 197
    pos += infoPtr->lRangeMin;
    if (pos > infoPtr->lRangeMax)
        pos = infoPtr->lRangeMax;
    else if (pos < infoPtr->lRangeMin)
        pos = infoPtr->lRangeMin;
198

199
    TRACE("%.2f\n", pos);
200
    return (LONG)floor(pos + 0.5);
201 202 203 204 205
}


/* return: 0> prev, 0 none, >0 next */
static LONG
206
TRACKBAR_GetAutoPageDirection (const TRACKBAR_INFO *infoPtr, POINT clickPoint)
207 208 209
{
    RECT pageRect;

210
    if (infoPtr->dwStyle & TBS_VERT) {
211 212 213 214 215 216 217 218 219 220 221 222 223 224
	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))
    {
225
	int clickPlace = (infoPtr->dwStyle & TBS_VERT) ? clickPoint.y : clickPoint.x;
226

227 228
        LONG clickPos = TRACKBAR_ConvertPlaceToPosition(infoPtr, clickPlace);

229 230 231 232 233 234
	return clickPos - infoPtr->lPos;
    }

    return 0;
}

235
static inline void
236
TRACKBAR_PageDown (TRACKBAR_INFO *infoPtr)
237 238 239 240 241 242
{
    if (infoPtr->lPos == infoPtr->lRangeMax) return;

    infoPtr->lPos += infoPtr->lPageSize;
    if (infoPtr->lPos > infoPtr->lRangeMax)
	infoPtr->lPos = infoPtr->lRangeMax;
243
    notify_with_scroll (infoPtr, TB_PAGEDOWN);
Alexandre Julliard's avatar
Alexandre Julliard committed
244 245
}

Alex Priem's avatar
Alex Priem committed
246

247
static inline void
248
TRACKBAR_PageUp (TRACKBAR_INFO *infoPtr)
249 250 251 252 253 254
{
    if (infoPtr->lPos == infoPtr->lRangeMin) return;

    infoPtr->lPos -= infoPtr->lPageSize;
    if (infoPtr->lPos < infoPtr->lRangeMin)
        infoPtr->lPos = infoPtr->lRangeMin;
255 256 257
    notify_with_scroll (infoPtr, TB_PAGEUP);
}

258
static inline void TRACKBAR_LineUp(TRACKBAR_INFO *infoPtr)
259 260 261 262 263 264 265 266
{
    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);
}

267
static inline void TRACKBAR_LineDown(TRACKBAR_INFO *infoPtr)
268 269 270 271 272 273
{
    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);
274 275
}

276 277
static void
TRACKBAR_CalcChannel (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
278
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
279 280
    INT cyChannel, offsetthumb, offsetedge;
    RECT lpRect, *channel = & infoPtr->rcChannel;
Alexandre Julliard's avatar
Alexandre Julliard committed
281

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

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

330
static void
331
TRACKBAR_CalcThumb (const TRACKBAR_INFO *infoPtr, LONG lPos, RECT *thumb)
Alexandre Julliard's avatar
Alexandre Julliard committed
332
{
333
    int range, width, height, thumbwidth;
334
    RECT lpRect;
335

336
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
337
    thumbwidth = (infoPtr->uThumbLen / 2) | 1;
338

339
    if (!range) range = 1;
340

341
    GetClientRect(infoPtr->hwndSelf, &lpRect);
342
    if (infoPtr->dwStyle & TBS_VERT)
343
    {
344
    	height = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - thumbwidth;
Alexandre Julliard's avatar
Alexandre Julliard committed
345

346
        if ((infoPtr->dwStyle & (TBS_BOTH | TBS_LEFT)) && !(infoPtr->dwStyle & TBS_NOTICKS))
347
            thumb->left = 10;
348
        else
349
            thumb->left = 2;
350
        thumb->right = thumb->left + infoPtr->uThumbLen;
351
        thumb->top = infoPtr->rcChannel.top +
352 353
                     (height*(lPos - infoPtr->lRangeMin))/range;
        thumb->bottom = thumb->top + thumbwidth;
354 355
    }
    else
356
    {
357
    	width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - thumbwidth;
358 359

        thumb->left = infoPtr->rcChannel.left +
360 361
                      (width*(lPos - infoPtr->lRangeMin))/range;
        thumb->right = thumb->left + thumbwidth;
362
        if ((infoPtr->dwStyle & (TBS_BOTH | TBS_TOP)) && !(infoPtr->dwStyle & TBS_NOTICKS))
363
            thumb->top = 10;
364
        else
365
            thumb->top = 2;
366
        thumb->bottom = thumb->top + infoPtr->uThumbLen;
367
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
368 369
}

370
static inline void
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
371 372 373 374 375
TRACKBAR_UpdateThumb (TRACKBAR_INFO *infoPtr)
{
    TRACKBAR_CalcThumb(infoPtr, infoPtr->lPos, &infoPtr->rcThumb);
}

376
static inline void
377
TRACKBAR_InvalidateAll (const TRACKBAR_INFO *infoPtr)
378 379 380 381
{
    InvalidateRect(infoPtr->hwndSelf, NULL, FALSE);
}

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
382
static void
383
TRACKBAR_InvalidateThumb (const TRACKBAR_INFO *infoPtr, LONG thumbPos)
384 385 386 387 388 389 390 391 392
{
    RECT rcThumb;

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

static inline void
393
TRACKBAR_InvalidateThumbMove (const TRACKBAR_INFO *infoPtr, LONG oldPos, LONG newPos)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
394
{
395 396 397
    TRACKBAR_InvalidateThumb (infoPtr, oldPos);
    if (newPos != oldPos)
        TRACKBAR_InvalidateThumb (infoPtr, newPos);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
398 399
}

400
static inline BOOL
401
TRACKBAR_HasSelection (const TRACKBAR_INFO *infoPtr)
402 403 404 405
{
    return infoPtr->lSelMin != infoPtr->lSelMax;
}

406 407
static void
TRACKBAR_CalcSelection (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
408
{
409 410
    RECT *selection = &infoPtr->rcSelection;
    int range = infoPtr->lRangeMax - infoPtr->lRangeMin;
411
    int offsetthumb, height, width;
412

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

437
    TRACE("selection[%s]\n", wine_dbgstr_rect(selection));
Alexandre Julliard's avatar
Alexandre Julliard committed
438 439
}

440 441 442 443 444 445
static BOOL
TRACKBAR_AutoPage (TRACKBAR_INFO *infoPtr, POINT clickPoint)
{
    LONG dir = TRACKBAR_GetAutoPageDirection(infoPtr, clickPoint);
    LONG prevPos = infoPtr->lPos;

446
    TRACE("clickPoint=%s, dir=%d\n", wine_dbgstr_point(&clickPoint), dir);
447 448 449

    if (dir > 0 && (infoPtr->flags & TB_AUTO_PAGE_RIGHT))
	TRACKBAR_PageDown(infoPtr);
450 451
    else if (dir < 0 && (infoPtr->flags & TB_AUTO_PAGE_LEFT))
	TRACKBAR_PageUp(infoPtr);
452 453
    else return FALSE;

454
    TRACKBAR_UpdateThumb (infoPtr);
455 456 457 458 459
    TRACKBAR_InvalidateThumbMove (infoPtr, prevPos, infoPtr->lPos);

    return TRUE;
}

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

462
static void
463
TRACKBAR_DrawChannel (const TRACKBAR_INFO *infoPtr, HDC hdc)
464 465
{
    RECT rcChannel = infoPtr->rcChannel;
466
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
467

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

485
static void
486
TRACKBAR_DrawOneTic (const TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags)
Alex Priem's avatar
Alex Priem committed
487
{
488 489
    int x, y, ox, oy, range, side, indent = 0, len = 3;
    int offsetthumb;
490
    RECT rcTics;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
491

492
    if (flags & TBS_VERT) {
493
        offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2;
494 495
        SetRect(&rcTics, infoPtr->rcThumb.left - 2, infoPtr->rcChannel.top + offsetthumb,
                infoPtr->rcThumb.right + 2, infoPtr->rcChannel.bottom - offsetthumb - 1);
496
    } else {
497
        offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2;
498 499
        SetRect(&rcTics, infoPtr->rcChannel.left + offsetthumb, infoPtr->rcThumb.top - 2,
                infoPtr->rcChannel.right - offsetthumb - 1, infoPtr->rcThumb.bottom + 2);
500
    }
Alex Priem's avatar
Alex Priem committed
501

502 503 504 505
    if (flags & (TBS_TOP | TBS_LEFT)) {
	x = rcTics.left;
	y = rcTics.top;
	side = -1;
506
    } else {
507 508 509
  	x = rcTics.right;
  	y = rcTics.bottom;
	side = 1;
510
    }
Alex Priem's avatar
Alex Priem committed
511

512
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
513
    if (range <= 0)
514
      range = 1; /* to avoid division by zero */
Alex Priem's avatar
Alex Priem committed
515

516
    if (flags & TIC_SELECTIONMARK) {
517 518 519
  	indent = (flags & TIC_SELECTIONMARKMIN) ? -1 : 1;
    } else if (flags & TIC_EDGE) {
	len++;
520
    }
Alex Priem's avatar
Alex Priem committed
521

522
    if (flags & TBS_VERT) {
523
	int height = rcTics.bottom - rcTics.top;
524 525 526 527
	y = rcTics.top + (height*(ticPos - infoPtr->lRangeMin))/range;
    } else {
        int width = rcTics.right - rcTics.left;
        x = rcTics.left + (width*(ticPos - infoPtr->lRangeMin))/range;
528
    }
Alex Priem's avatar
Alex Priem committed
529

530 531 532 533 534 535 536
    ox = x;
    oy = y;
    MoveToEx(hdc, x, y, 0);
    if (flags & TBS_VERT) x += len * side;
    else y += len * side;
    LineTo(hdc, x, y);
	    
537 538
    if (flags & TIC_SELECTIONMARK) {
	if (flags & TBS_VERT) {
539
	    x -= side;
540
	} else {
541
	    y -= side;
542
	}
543 544 545 546 547 548 549 550 551
	MoveToEx(hdc, x, y, 0);
	if (flags & TBS_VERT) {
	    y += 2 * indent;
	} else {
	    x += 2 * indent;
	}
	
	LineTo(hdc, x, y);
	LineTo(hdc, ox, oy);
552
    }
Alex Priem's avatar
Alex Priem committed
553 554 555
}


556
static inline void
557
TRACKBAR_DrawTic (const TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags)
Alex Priem's avatar
Alex Priem committed
558
{
559
    if ((flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH))
560
        TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags | TBS_LEFT);
Alex Priem's avatar
Alex Priem committed
561

562
    if (!(flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH))
563
        TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags & ~TBS_LEFT);
564 565 566
}

static void
567
TRACKBAR_DrawTics (const TRACKBAR_INFO *infoPtr, HDC hdc)
568
{
569
    unsigned int i;
570
    int ticFlags = infoPtr->dwStyle & 0x0f;
571 572
    LOGPEN ticPen = { PS_SOLID, {1, 0}, GetSysColor (COLOR_3DDKSHADOW) };
    HPEN hOldPen, hTicPen;
573
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
574
    
575 576
    if (theme)
    {
577
        int part = (infoPtr->dwStyle & TBS_VERT) ? TKP_TICSVERT : TKP_TICS;
578 579 580
        GetThemeColor (theme, part, TSS_NORMAL, TMT_COLOR, &ticPen.lopnColor);
    }
    /* create the pen to draw the tics with */
581 582 583 584 585 586 587 588 589 590
    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);

591
    if ((infoPtr->dwStyle & TBS_ENABLESELRANGE) && TRACKBAR_HasSelection(infoPtr)) {
592 593 594 595 596 597 598 599 600 601 602
        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
603 604
}

605 606 607 608
static int
TRACKBAR_FillThumb (const TRACKBAR_INFO *infoPtr, HDC hdc, HBRUSH hbrush)
{
    const RECT *thumb = &infoPtr->rcThumb;
609
    POINT points[6];
610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689
    int PointDepth;
    HBRUSH oldbr;

    if (infoPtr->dwStyle & TBS_BOTH)
    {
        FillRect(hdc, thumb, hbrush);
        return 0;
    }

    if (infoPtr->dwStyle & TBS_VERT)
    {
        PointDepth = (thumb->bottom - thumb->top) / 2;
        if (infoPtr->dwStyle & TBS_LEFT)
        {
            points[0].x = thumb->right-1;
            points[0].y = thumb->top;
            points[1].x = thumb->right-1;
            points[1].y = thumb->bottom-1;
            points[2].x = thumb->left + PointDepth;
            points[2].y = thumb->bottom-1;
            points[3].x = thumb->left;
            points[3].y = thumb->top + PointDepth;
            points[4].x = thumb->left + PointDepth;
            points[4].y = thumb->top;
            points[5].x = points[0].x;
            points[5].y = points[0].y;
        }
        else
        {
            points[0].x = thumb->right;
            points[0].y = thumb->top + PointDepth;
            points[1].x = thumb->right - PointDepth;
            points[1].y = thumb->bottom-1;
            points[2].x = thumb->left;
            points[2].y = thumb->bottom-1;
            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
    {
        PointDepth = (thumb->right - thumb->left) / 2;
        if (infoPtr->dwStyle & TBS_TOP)
        {
            points[0].x = thumb->left + PointDepth;
            points[0].y = thumb->top+1;
            points[1].x = thumb->right-1;
            points[1].y = thumb->top + PointDepth + 1;
            points[2].x = thumb->right-1;
            points[2].y = thumb->bottom-1;
            points[3].x = thumb->left;
            points[3].y = thumb->bottom-1;
            points[4].x = thumb->left;
            points[4].y = thumb->top + PointDepth + 1;
            points[5].x = points[0].x;
            points[5].y = points[0].y;
        }
        else
        {
            points[0].x = thumb->right-1;
            points[0].y = thumb->top;
            points[1].x = thumb->right-1;
            points[1].y = thumb->bottom - PointDepth - 1;
            points[2].x = thumb->left + PointDepth;
            points[2].y = thumb->bottom-1;
            points[3].x = thumb->left;
            points[3].y = thumb->bottom - PointDepth - 1;
            points[4].x = thumb->left;
            points[4].y = thumb->top;
            points[5].x = points[0].x;
            points[5].y = points[0].y;
        }
    }

    oldbr = SelectObject(hdc, hbrush);
    SetPolyFillMode(hdc, WINDING);
690
    Polygon(hdc, points, ARRAY_SIZE(points));
691 692 693 694 695
    SelectObject(hdc, oldbr);

    return PointDepth;
}

696
static void
697
TRACKBAR_DrawThumb (TRACKBAR_INFO *infoPtr, HDC hdc)
698
{
699
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
700
    int PointDepth;
701 702
    HBRUSH brush;

703 704 705 706
    if (theme)
    {
        int partId;
        int stateId;
707 708 709 710
        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;
711
        else
712
            partId = (infoPtr->dwStyle & TBS_VERT) ? TKP_THUMBRIGHT : TKP_THUMBBOTTOM;
713
            
714
        if (infoPtr->dwStyle & WS_DISABLED)
715 716 717 718 719
            stateId = TUS_DISABLED;
        else if (infoPtr->flags & TB_DRAG_MODE)
            stateId = TUS_PRESSED;
        else if (infoPtr->flags & TB_THUMB_HOT)
            stateId = TUS_HOT;
720 721
        else if (infoPtr->flags & TB_IS_FOCUSED)
            stateId = TUS_FOCUSED;
722 723 724
        else
            stateId = TUS_NORMAL;
        
725
        DrawThemeBackground (theme, hdc, partId, stateId, &infoPtr->rcThumb, NULL);
726 727 728
        
        return;
    }
729

730
    if (infoPtr->dwStyle & WS_DISABLED || infoPtr->flags & TB_DRAG_MODE)
731 732 733 734 735 736 737 738 739 740
    {
        if (comctl32_color.clr3dHilight == comctl32_color.clrWindow)
            brush = COMCTL32_hPattern55AABrush;
        else
            brush = GetSysColorBrush(COLOR_SCROLLBAR);

        SetTextColor(hdc, comctl32_color.clr3dFace);
        SetBkColor(hdc, comctl32_color.clr3dHilight);
    }
    else
741 742 743
        brush = GetSysColorBrush(COLOR_BTNFACE);

    PointDepth = TRACKBAR_FillThumb(infoPtr, hdc, brush);
744

745
    if (infoPtr->dwStyle & TBS_BOTH)
746
    {
747 748
       DrawEdge(hdc, &infoPtr->rcThumb, EDGE_RAISED, BF_RECT | BF_SOFT);
       return;
749 750
    }
    else
751
    {
752 753
        RECT thumb = infoPtr->rcThumb;

754
        if (infoPtr->dwStyle & TBS_VERT)
755
        {
756
          if (infoPtr->dwStyle & TBS_LEFT)
757
          {
758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773
            /* rectangular part */
            thumb.left += PointDepth;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_TOP | BF_RIGHT | BF_BOTTOM | BF_SOFT);

            /* light edge */
            thumb.left -= PointDepth;
            thumb.right = thumb.left + PointDepth;
            thumb.bottom = infoPtr->rcThumb.top + PointDepth + 1;
            thumb.top = infoPtr->rcThumb.top;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_DIAGONAL_ENDTOPRIGHT | BF_SOFT);

            /* shadowed edge */
            thumb.top += PointDepth;
            thumb.bottom += PointDepth;
            DrawEdge(hdc, &thumb, EDGE_SUNKEN, BF_DIAGONAL_ENDTOPLEFT | BF_SOFT);
            return;
774 775 776
          }
          else
          {
777 778 779 780 781 782 783 784 785 786 787 788 789 790 791
            /* rectangular part */
            thumb.right -= PointDepth;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_TOP | BF_LEFT | BF_BOTTOM | BF_SOFT);

            /* light edge */
            thumb.left = thumb.right;
            thumb.right += PointDepth + 1;
            thumb.bottom = infoPtr->rcThumb.top + PointDepth + 1;
            thumb.top = infoPtr->rcThumb.top;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_DIAGONAL_ENDTOPLEFT | BF_SOFT);

            /* shadowed edge */
            thumb.top += PointDepth;
            thumb.bottom += PointDepth;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_DIAGONAL_ENDBOTTOMLEFT | BF_SOFT);
792 793 794 795
          }
        }
        else
        {
796
          if (infoPtr->dwStyle & TBS_TOP)
797
          {
798 799 800 801 802 803 804 805 806 807 808 809 810 811 812
            /* rectangular part */
            thumb.top += PointDepth;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_LEFT | BF_BOTTOM | BF_RIGHT | BF_SOFT);

            /* light edge */
            thumb.left = infoPtr->rcThumb.left;
            thumb.right = thumb.left + PointDepth;
            thumb.bottom = infoPtr->rcThumb.top + PointDepth + 1;
            thumb.top -= PointDepth;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_DIAGONAL_ENDTOPRIGHT | BF_SOFT);

            /* shadowed edge */
            thumb.left += PointDepth;
            thumb.right += PointDepth;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_DIAGONAL_ENDBOTTOMRIGHT | BF_SOFT);
813 814 815
          }
          else
          {
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830
            /* rectangular part */
            thumb.bottom -= PointDepth;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_LEFT | BF_TOP | BF_RIGHT | BF_SOFT);

            /* light edge */
            thumb.left = infoPtr->rcThumb.left;
            thumb.right = thumb.left + PointDepth;
            thumb.top = infoPtr->rcThumb.bottom - PointDepth - 1;
            thumb.bottom += PointDepth;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_DIAGONAL_ENDTOPLEFT | BF_SOFT);

            /* shadowed edge */
            thumb.left += PointDepth;
            thumb.right += PointDepth;
            DrawEdge(hdc, &thumb, EDGE_RAISED, BF_DIAGONAL_ENDBOTTOMLEFT | BF_SOFT);
831 832 833 834
          }
        }
    }
}
Alex Priem's avatar
Alex Priem committed
835

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

837
static inline void
838
TRACKBAR_ActivateToolTip (const TRACKBAR_INFO *infoPtr, BOOL fShow)
839 840 841 842 843 844 845 846 847 848 849 850 851
{
    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);
}


852
static void
853
TRACKBAR_UpdateToolTip (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
854
{
855
    WCHAR buf[80];
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
856 857
    TTTOOLINFOW ti;
    POINT pt;
858
    RECT rcClient;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
859
    LRESULT size;
Alexandre Julliard's avatar
Alexandre Julliard committed
860

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
863 864 865 866 867
    ZeroMemory(&ti, sizeof(ti));
    ti.cbSize = sizeof(ti);
    ti.hwnd   = infoPtr->hwndSelf;
    ti.uFlags = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;

868
    wsprintfW (buf, L"%ld", infoPtr->lPos);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
869 870 871
    ti.lpszText = buf;
    SendMessageW (infoPtr->hwndToolTip, TTM_UPDATETIPTEXTW, 0, (LPARAM)&ti);

872
    GetClientRect (infoPtr->hwndSelf, &rcClient);
873
    size = SendMessageW (infoPtr->hwndToolTip, TTM_GETBUBBLESIZE, 0, (LPARAM)&ti);
874
    if (infoPtr->dwStyle & TBS_VERT) {
875
	if (infoPtr->fLocation == TBTS_LEFT)
876
	    pt.x = 0 - LOWORD(size) - TOOLTIP_OFFSET;
877
	else
878
	    pt.x = rcClient.right + TOOLTIP_OFFSET;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
879 880
    	pt.y = (infoPtr->rcThumb.top + infoPtr->rcThumb.bottom - HIWORD(size))/2;
    } else {
881
	if (infoPtr->fLocation == TBTS_TOP)
882
	    pt.y = 0 - HIWORD(size) - TOOLTIP_OFFSET;
883
	else
884
            pt.y = rcClient.bottom + TOOLTIP_OFFSET;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
885
        pt.x = (infoPtr->rcThumb.left + infoPtr->rcThumb.right - LOWORD(size))/2;
Alex Priem's avatar
Alex Priem committed
886
    }
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
887 888 889
    ClientToScreen(infoPtr->hwndSelf, &pt);

    SendMessageW (infoPtr->hwndToolTip, TTM_TRACKPOSITION,
890
                  0, MAKELPARAM(pt.x, pt.y));
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
891 892 893 894
}


static void
895
TRACKBAR_Refresh (TRACKBAR_INFO *infoPtr, HDC hdcDst)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
896
{
897
    RECT rcClient;
898 899
    HDC hdc;
    HBITMAP hOldBmp = 0, hOffScreenBmp = 0;
900 901
    NMCUSTOMDRAW nmcd;
    int gcdrf, icdrf;
902

903
    if (infoPtr->flags & TB_THUMBCHANGED) {
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
904
        TRACKBAR_UpdateThumb (infoPtr);
905
        if (infoPtr->flags & TB_THUMBSIZECHANGED)
906
            TRACKBAR_CalcChannel (infoPtr);
907 908
    }
    if (infoPtr->flags & TB_SELECTIONCHANGED)
909
        TRACKBAR_CalcSelection (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
910

911
    if (infoPtr->flags & TB_DRAG_MODE)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
912 913
        TRACKBAR_UpdateToolTip (infoPtr);

914 915
    infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED);

916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
    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;
    }

932 933
    ZeroMemory(&nmcd, sizeof(nmcd));
    nmcd.hdr.hwndFrom = infoPtr->hwndSelf;
934
    nmcd.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
935 936
    nmcd.hdr.code = NM_CUSTOMDRAW;
    nmcd.hdc = hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
937

938 939
    /* start the paint cycle */
    nmcd.rc = rcClient;
940
    gcdrf = notify_customdraw(infoPtr, &nmcd, CDDS_PREPAINT);
941 942
    if (gcdrf & CDRF_SKIPDEFAULT) goto cleanup;
    
943
    /* Erase background */
944
    if (gcdrf == CDRF_DODEFAULT ||
945
        notify_customdraw(infoPtr, &nmcd, CDDS_PREERASE) != CDRF_SKIPDEFAULT) {
946
        if (GetWindowTheme (infoPtr->hwndSelf)) {
947
            DrawThemeParentBackground (infoPtr->hwndSelf, hdc, 0);
948
        }
949 950 951 952 953
        else {
            HBRUSH brush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC,
                    (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf);
            FillRect (hdc, &rcClient, brush ? brush : GetSysColorBrush(COLOR_BTNFACE));
        }
954
        if (gcdrf != CDRF_DODEFAULT)
955
	    notify_customdraw(infoPtr, &nmcd, CDDS_POSTERASE);
956
    }
957
    
Alexandre Julliard's avatar
Alexandre Julliard committed
958
    /* draw channel */
959 960 961 962
    if (gcdrf & CDRF_NOTIFYITEMDRAW) {
        nmcd.dwItemSpec = TBCD_CHANNEL;
	nmcd.uItemState = CDIS_DEFAULT;
	nmcd.rc = infoPtr->rcChannel;
963
	icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
964 965
    } else icdrf = CDRF_DODEFAULT;
    if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
966
	TRACKBAR_DrawChannel (infoPtr, hdc);
967
	if (icdrf & CDRF_NOTIFYPOSTPAINT)
968
	    notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
Alexandre Julliard's avatar
Alexandre Julliard committed
969 970
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
971 972

    /* draw tics */
973
    if (!(infoPtr->dwStyle & TBS_NOTICKS)) {
974 975 976 977
    	if (gcdrf & CDRF_NOTIFYITEMDRAW) {
            nmcd.dwItemSpec = TBCD_TICS;
	    nmcd.uItemState = CDIS_DEFAULT;
	    nmcd.rc = rcClient;
978
	    icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
979 980
        } else icdrf = CDRF_DODEFAULT;
	if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
981
	    TRACKBAR_DrawTics (infoPtr, hdc);
982
	    if (icdrf & CDRF_NOTIFYPOSTPAINT)
983
		notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
984
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
985
    }
986
    
987
    /* draw thumb */
988
    if (!(infoPtr->dwStyle & TBS_NOTHUMB)) {
989 990 991 992
	if (gcdrf & CDRF_NOTIFYITEMDRAW) {
	    nmcd.dwItemSpec = TBCD_THUMB;
	    nmcd.uItemState = infoPtr->flags & TB_DRAG_MODE ? CDIS_HOT : CDIS_DEFAULT;
	    nmcd.rc = infoPtr->rcThumb;
993
	    icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
994 995
	} else icdrf = CDRF_DODEFAULT;
	if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
996
            TRACKBAR_DrawThumb(infoPtr, hdc);
997
	    if (icdrf & CDRF_NOTIFYPOSTPAINT)
998
		notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
999 1000
	}
    }
1001

1002
    /* draw focus rectangle */
1003
    if (infoPtr->flags & TB_IS_FOCUSED) {
1004 1005 1006
	DrawFocusRect(hdc, &rcClient);
    }

1007 1008
    /* finish up the painting */
    if (gcdrf & CDRF_NOTIFYPOSTPAINT)
1009
	notify_customdraw(infoPtr, &nmcd, CDDS_POSTPAINT);
1010 1011
    
cleanup:
1012 1013 1014 1015 1016 1017 1018
    /* 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
1019 1020 1021
}


1022
static void
1023
TRACKBAR_AlignBuddies (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1024
{
1025
    HWND hwndParent = GetParent (infoPtr->hwndSelf);
1026 1027
    RECT rcSelf, rcBuddy;
    INT x, y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1028

1029
    GetWindowRect (infoPtr->hwndSelf, &rcSelf);
1030
    MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcSelf, 2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1031 1032 1033

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

1037
	if (infoPtr->dwStyle & TBS_VERT) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1038 1039 1040 1041 1042 1043 1044 1045 1046 1047
	    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;
	}

1048
	SetWindowPos (infoPtr->hwndBuddyLA, 0, x, y, 0, 0,
1049
                      SWP_NOZORDER | SWP_NOSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1050 1051 1052 1053 1054
    }


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

1058
	if (infoPtr->dwStyle & TBS_VERT) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1059 1060 1061 1062 1063 1064 1065 1066 1067
	    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;
	}
1068
	SetWindowPos (infoPtr->hwndBuddyRB, 0, x, y, 0, 0,
1069
                      SWP_NOZORDER | SWP_NOSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1070 1071 1072 1073 1074
    }
}


static LRESULT
1075
TRACKBAR_ClearSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
1076
{
1077 1078
    infoPtr->lSelMin = 0;
    infoPtr->lSelMax = 0;
1079
    infoPtr->flags |= TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1080

1081
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1082 1083 1084 1085 1086 1087

    return 0;
}


static LRESULT
1088
TRACKBAR_ClearTics (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
1089 1090
{
    if (infoPtr->tics) {
1091
        Free (infoPtr->tics);
1092 1093
        infoPtr->tics = NULL;
        infoPtr->uNumTics = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1094 1095
    }

1096
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1097 1098 1099 1100 1101

    return 0;
}


1102
static inline LRESULT
1103
TRACKBAR_GetChannelRect (const TRACKBAR_INFO *infoPtr, LPRECT lprc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1104
{
1105
    if (lprc == NULL) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1106 1107 1108 1109 1110 1111 1112 1113 1114 1115

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

    return 0;
}


1116
static inline LONG
1117
TRACKBAR_GetNumTics (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1118
{
1119
    if (infoPtr->dwStyle & TBS_NOTICKS) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1120

1121
    return infoPtr->uNumTics + 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1122 1123 1124
}


1125
static int __cdecl comp_tics (const void *ap, const void *bp)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1126
{
1127 1128
    const DWORD a = *(const DWORD *)ap;
    const DWORD b = *(const DWORD *)bp;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1129

1130
    TRACE("(a=%d, b=%d)\n", a, b);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1131 1132 1133 1134 1135
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1136

1137
static inline LONG
1138
TRACKBAR_GetTic (const TRACKBAR_INFO *infoPtr, INT iTic)
Alexandre Julliard's avatar
Alexandre Julliard committed
1139
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1140
    if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics)
Alexandre Julliard's avatar
Alexandre Julliard committed
1141 1142
	return -1;

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1143
    qsort(infoPtr->tics, infoPtr->uNumTics, sizeof(DWORD), comp_tics);
1144
    return infoPtr->tics[iTic];
Alexandre Julliard's avatar
Alexandre Julliard committed
1145 1146 1147
}


1148
static inline LONG
1149
TRACKBAR_GetTicPos (const TRACKBAR_INFO *infoPtr, INT iTic)
Alexandre Julliard's avatar
Alexandre Julliard committed
1150
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1151
    LONG range, width, pos, tic;
1152
    int offsetthumb;
Alexandre Julliard's avatar
Alexandre Julliard committed
1153

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1157
    tic   = TRACKBAR_GetTic (infoPtr, iTic);
1158
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
1159
    if (range <= 0) range = 1;
1160 1161 1162
    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
1163

1164
    return pos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1165 1166
}

1167

1168 1169
static HWND
TRACKBAR_SetBuddy (TRACKBAR_INFO *infoPtr, BOOL fLocation, HWND hwndBuddy)
Alexandre Julliard's avatar
Alexandre Julliard committed
1170
{
1171
    HWND hwndTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1172

1173
    if (fLocation) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1174 1175
	/* buddy is left or above */
	hwndTemp = infoPtr->hwndBuddyLA;
1176
	infoPtr->hwndBuddyLA = hwndBuddy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1177 1178
    }
    else {
1179 1180
        /* buddy is right or below */
        hwndTemp = infoPtr->hwndBuddyRB;
1181
        infoPtr->hwndBuddyRB = hwndBuddy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1182 1183
    }

1184
    TRACKBAR_AlignBuddies (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1185

1186
    return hwndTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1187 1188 1189
}


1190
static inline LONG
1191
TRACKBAR_SetLineSize (TRACKBAR_INFO *infoPtr, LONG lLineSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1192
{
1193
    LONG lTemp = infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1194

1195
    infoPtr->lLineSize = lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1196

1197
    return lTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1198 1199
}

1200 1201 1202 1203 1204 1205 1206 1207
static void TRACKBAR_UpdatePageSize(TRACKBAR_INFO *infoPtr)
{
    if (infoPtr->flags & TB_USER_PAGE)
        return;

    infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
    if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1208

1209
static inline LONG
1210
TRACKBAR_SetPageSize (TRACKBAR_INFO *infoPtr, LONG lPageSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1211
{
1212
    LONG lTemp = infoPtr->lPageSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1213

1214 1215 1216 1217 1218
    if (lPageSize == -1)
    {
        infoPtr->flags &= ~TB_USER_PAGE;
        TRACKBAR_UpdatePageSize(infoPtr);
    }
1219
    else
1220 1221 1222 1223
    {
        infoPtr->flags |= TB_USER_PAGE;
        infoPtr->lPageSize = lPageSize;
    }
1224

1225
    return lTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1226 1227 1228
}


1229
static inline LRESULT
1230
TRACKBAR_SetPos (TRACKBAR_INFO *infoPtr, BOOL fPosition, LONG lPosition)
Alexandre Julliard's avatar
Alexandre Julliard committed
1231
{
1232
    LONG oldPos = infoPtr->lPos;
1233
    infoPtr->lPos = lPosition;
Alexandre Julliard's avatar
Alexandre Julliard committed
1234

1235 1236
    if (infoPtr->lPos < infoPtr->lRangeMin)
	infoPtr->lPos = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1237

1238 1239
    if (infoPtr->lPos > infoPtr->lRangeMax)
	infoPtr->lPos = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1240

1241 1242 1243 1244 1245
    if (fPosition && oldPos != lPosition)
    {
        TRACKBAR_UpdateThumb(infoPtr);
        TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1246 1247 1248 1249

    return 0;
}

1250
static inline LRESULT
1251
TRACKBAR_SetRange (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG range)
Alexandre Julliard's avatar
Alexandre Julliard committed
1252
{
1253 1254 1255 1256 1257
    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
1258

1259 1260
    /* clip position to new min/max limit */
    if (infoPtr->lPos < infoPtr->lRangeMin)
1261
        infoPtr->lPos = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1262

1263
    if (infoPtr->lPos > infoPtr->lRangeMax)
1264
        infoPtr->lPos = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1265

1266
    TRACKBAR_UpdatePageSize(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1267

1268 1269 1270 1271 1272
    if (changed) {
        if (infoPtr->dwStyle & TBS_AUTOTICKS)
            TRACKBAR_RecalculateTics (infoPtr);
        infoPtr->flags |= TB_THUMBPOSCHANGED;
    }
1273 1274

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1275 1276 1277 1278 1279

    return 0;
}


1280
static inline LRESULT
1281
TRACKBAR_SetRangeMax (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG lMax)
Alexandre Julliard's avatar
Alexandre Julliard committed
1282
{
1283
    BOOL changed = infoPtr->lRangeMax != lMax;
1284
    LONG rightmost = max(lMax, infoPtr->lRangeMin);
1285

1286
    infoPtr->lRangeMax = lMax;
1287 1288
    if (infoPtr->lPos > rightmost) {
        infoPtr->lPos = rightmost;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1289
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1290
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1291

1292
    TRACKBAR_UpdatePageSize(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1293

1294 1295 1296 1297
    if (changed && (infoPtr->dwStyle & TBS_AUTOTICKS))
        TRACKBAR_RecalculateTics (infoPtr);

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1298 1299 1300 1301 1302

    return 0;
}


1303
static inline LRESULT
1304
TRACKBAR_SetRangeMin (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG lMin)
Alexandre Julliard's avatar
Alexandre Julliard committed
1305
{
1306 1307
    BOOL changed = infoPtr->lRangeMin != lMin;

1308 1309 1310
    infoPtr->lRangeMin = lMin;
    if (infoPtr->lPos < infoPtr->lRangeMin) {
        infoPtr->lPos = infoPtr->lRangeMin;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1311
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1312
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1313

1314
    TRACKBAR_UpdatePageSize(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1315

1316 1317 1318 1319
    if (changed && (infoPtr->dwStyle & TBS_AUTOTICKS))
        TRACKBAR_RecalculateTics (infoPtr);

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1320 1321 1322 1323

    return 0;
}

1324

1325
static inline LRESULT
1326
TRACKBAR_SetSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lSel)
Alexandre Julliard's avatar
Alexandre Julliard committed
1327
{
1328
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1329 1330
        infoPtr->lSelMin = 0;
        infoPtr->lSelMax = 0;
1331
        return 0;
1332
    }
1333

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1334 1335 1336
    infoPtr->lSelMin = (SHORT)LOWORD(lSel);
    infoPtr->lSelMax = (SHORT)HIWORD(lSel);
    infoPtr->flags |= TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1337

1338 1339 1340 1341
    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
1342

1343
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1344 1345 1346 1347 1348

    return 0;
}


1349
static inline LRESULT
1350
TRACKBAR_SetSelEnd (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lEnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
1351
{
1352
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1353
        infoPtr->lSelMax = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1354
	return 0;
1355
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1356

1357
    infoPtr->lSelMax = lEnd;
1358
    infoPtr->flags |= TB_SELECTIONCHANGED;
1359

1360 1361
    if (infoPtr->lSelMax > infoPtr->lRangeMax)
        infoPtr->lSelMax = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1362

1363
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1364 1365 1366 1367 1368

    return 0;
}


1369
static inline LRESULT
1370
TRACKBAR_SetSelStart (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lStart)
Alexandre Julliard's avatar
Alexandre Julliard committed
1371
{
1372
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1373
        infoPtr->lSelMin = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1374
	return 0;
1375
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1376

1377
    infoPtr->lSelMin = lStart;
1378
    infoPtr->flags  |=TB_SELECTIONCHANGED;
1379

1380 1381
    if (infoPtr->lSelMin < infoPtr->lRangeMin)
        infoPtr->lSelMin = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1382

1383
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1384 1385 1386 1387 1388

    return 0;
}


1389
static inline LRESULT
1390
TRACKBAR_SetThumbLength (TRACKBAR_INFO *infoPtr, UINT iLength)
Alexandre Julliard's avatar
Alexandre Julliard committed
1391
{
1392
    if (infoPtr->dwStyle & TBS_FIXEDLENGTH) {
1393 1394
        /* We're not supposed to check if it's really changed or not,
           just repaint in any case. */
1395
        infoPtr->uThumbLen = iLength;
1396
	infoPtr->flags |= TB_THUMBSIZECHANGED;
1397
	TRACKBAR_InvalidateAll(infoPtr);
1398
    }
1399

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


1404
static inline LRESULT
1405
TRACKBAR_SetTic (TRACKBAR_INFO *infoPtr, LONG lPos)
Alexandre Julliard's avatar
Alexandre Julliard committed
1406
{
1407
    if ((lPos < infoPtr->lRangeMin) || (lPos> infoPtr->lRangeMax))
1408
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1409

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

1412
    infoPtr->uNumTics++;
1413
    infoPtr->tics=ReAlloc( infoPtr->tics,
1414
                                    (infoPtr->uNumTics)*sizeof (DWORD));
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1415 1416
    if (!infoPtr->tics) {
	infoPtr->uNumTics = 0;
1417
	notify(infoPtr, NM_OUTOFMEMORY);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1418 1419 1420
	return FALSE;
    }
    infoPtr->tics[infoPtr->uNumTics-1] = lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1421

1422
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1423 1424 1425 1426 1427

    return TRUE;
}


1428
static inline LRESULT
1429 1430
TRACKBAR_SetTicFreq (TRACKBAR_INFO *infoPtr, WORD wFreq)
{
1431
    if (infoPtr->dwStyle & TBS_AUTOTICKS) {
1432
        infoPtr->uTicFreq = wFreq;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1433
	TRACKBAR_RecalculateTics (infoPtr);
1434
	TRACKBAR_InvalidateAll(infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1435
    }
1436

1437
    TRACKBAR_UpdateThumb (infoPtr);
1438 1439 1440 1441
    return 0;
}


1442
static inline INT
1443
TRACKBAR_SetTipSide (TRACKBAR_INFO *infoPtr, INT fLocation)
Alexandre Julliard's avatar
Alexandre Julliard committed
1444
{
1445
    INT fTemp = infoPtr->fLocation;
Alexandre Julliard's avatar
Alexandre Julliard committed
1446

1447
    infoPtr->fLocation = fLocation;
1448

Alexandre Julliard's avatar
Alexandre Julliard committed
1449 1450 1451 1452
    return fTemp;
}


1453
static inline LRESULT
1454
TRACKBAR_SetToolTips (TRACKBAR_INFO *infoPtr, HWND hwndTT)
Alexandre Julliard's avatar
Alexandre Julliard committed
1455
{
1456
    infoPtr->hwndToolTip = hwndTT;
Alexandre Julliard's avatar
Alexandre Julliard committed
1457 1458 1459 1460 1461

    return 0;
}


1462
static inline BOOL
1463 1464 1465 1466 1467 1468 1469 1470
TRACKBAR_SetUnicodeFormat (TRACKBAR_INFO *infoPtr, BOOL fUnicode)
{
    BOOL bTemp = infoPtr->bUnicode;

    infoPtr->bUnicode = fUnicode;

    return bTemp;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1471

1472 1473 1474 1475
static int get_scaled_metric(const TRACKBAR_INFO *infoPtr, int value)
{
    return MulDiv(value, GetDpiForWindow(infoPtr->hwndSelf), 96);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1476

Alexandre Julliard's avatar
Alexandre Julliard committed
1477
static LRESULT
1478
TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1479
{
1480
    int client_size;
1481
    RECT rect;
1482

1483 1484
    infoPtr->uThumbLen = get_scaled_metric(infoPtr, infoPtr->dwStyle & TBS_ENABLESELRANGE ? 23 : 21);

1485 1486 1487 1488 1489 1490 1491
    if (!(infoPtr->dwStyle & TBS_FIXEDLENGTH))
    {
        GetClientRect(infoPtr->hwndSelf, &rect);
        if (infoPtr->dwStyle & TBS_VERT)
            client_size = rect.right - rect.left;
        else
            client_size = rect.bottom - rect.top;
1492

1493 1494 1495 1496
        if (client_size < infoPtr->uThumbLen)
            infoPtr->uThumbLen = client_size > get_scaled_metric(infoPtr, 9) ?
                client_size - get_scaled_metric(infoPtr, 5) : get_scaled_metric(infoPtr, 4);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1497

1498
    TRACKBAR_CalcChannel (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1499
    TRACKBAR_UpdateThumb (infoPtr);
1500
    infoPtr->flags &= ~TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1501

1502
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1503
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1504

1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517
static void TRACKBAR_RecalculateAll (TRACKBAR_INFO *infoPtr)
{
    if (infoPtr->dwStyle & TBS_FIXEDLENGTH)
    {
        TRACKBAR_CalcChannel(infoPtr);
        TRACKBAR_UpdateThumb(infoPtr);
    }
    else
    {
        TRACKBAR_InitializeThumb(infoPtr);
    }
    TRACKBAR_AlignBuddies(infoPtr);
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1518 1519

static LRESULT
1520
TRACKBAR_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
1521 1522 1523
{
    TRACKBAR_INFO *infoPtr;

1524
    infoPtr = Alloc (sizeof(TRACKBAR_INFO));
1525
    if (!infoPtr) return -1;
1526
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1527

1528
    /* set default values */
1529
    infoPtr->hwndSelf  = hwnd;
1530
    infoPtr->dwStyle   = lpcs->style;
1531 1532 1533
    infoPtr->lRangeMin = 0;
    infoPtr->lRangeMax = 100;
    infoPtr->lLineSize = 1;
1534
    infoPtr->lPageSize = TB_DEFAULTPAGESIZE;
1535 1536 1537
    infoPtr->lSelMin   = 0;
    infoPtr->lSelMax   = 0;
    infoPtr->lPos      = 0;
1538
    infoPtr->fLocation = TBTS_TOP;
Alexandre Julliard's avatar
Alexandre Julliard committed
1539
    infoPtr->uNumTics  = 0;    /* start and end tic are not included in count*/
1540
    infoPtr->uTicFreq  = 1;
1541
    infoPtr->tics      = NULL;
1542
    infoPtr->hwndNotify= lpcs->hwndParent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1543

1544
    TRACKBAR_InitializeThumb (infoPtr);
Alex Priem's avatar
Alex Priem committed
1545

1546
    /* Create tooltip control */
1547
    if (infoPtr->dwStyle & TBS_TOOLTIPS) {
Alex Priem's avatar
Alex Priem committed
1548 1549

    	infoPtr->hwndToolTip =
1550
            CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1551 1552 1553
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             hwnd, 0, 0, 0);
Alex Priem's avatar
Alex Priem committed
1554

1555
    	if (infoPtr->hwndToolTip) {
1556
            TTTOOLINFOW ti;
1557
            WCHAR wEmpty[] = L"";
1558 1559 1560 1561
            ZeroMemory (&ti, sizeof(ti));
            ti.cbSize   = sizeof(ti);
     	    ti.uFlags   = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
	    ti.hwnd     = hwnd;
1562
            ti.lpszText = wEmpty;
Alex Priem's avatar
Alex Priem committed
1563

1564 1565
            SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
	 }
1566
    }
1567 1568
    
    OpenThemeData (hwnd, themeClass);
1569

Alexandre Julliard's avatar
Alexandre Julliard committed
1570 1571 1572 1573 1574
    return 0;
}


static LRESULT
1575
TRACKBAR_Destroy (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1576
{
1577
    /* delete tooltip control */
Alex Priem's avatar
Alex Priem committed
1578
    if (infoPtr->hwndToolTip)
1579
    	DestroyWindow (infoPtr->hwndToolTip);
Alex Priem's avatar
Alex Priem committed
1580

1581 1582 1583
    Free (infoPtr->tics);
    infoPtr->tics = NULL;

1584
    SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
1585
    CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
1586 1587
    Free (infoPtr);

Alexandre Julliard's avatar
Alexandre Julliard committed
1588 1589 1590 1591 1592
    return 0;
}


static LRESULT
1593
TRACKBAR_KillFocus (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1594
{
1595
    TRACE("\n");
1596
    infoPtr->flags &= ~TB_IS_FOCUSED;
1597
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1598 1599 1600 1601 1602

    return 0;
}

static LRESULT
1603
TRACKBAR_LButtonDown (TRACKBAR_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1604
{
1605 1606 1607 1608
    POINT clickPoint;

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

1610 1611
    SetFocus(infoPtr->hwndSelf);

1612
    if (PtInRect(&infoPtr->rcThumb, clickPoint)) {
1613
        infoPtr->flags |= TB_DRAG_MODE;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1614
        SetCapture (infoPtr->hwndSelf);
1615 1616
	TRACKBAR_UpdateToolTip (infoPtr);
	TRACKBAR_ActivateToolTip (infoPtr, TRUE);
1617
	TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1618
    } else {
1619 1620 1621 1622 1623 1624
	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);
1625
    }
1626

Alexandre Julliard's avatar
Alexandre Julliard committed
1627 1628 1629
    return 0;
}

1630

Alexandre Julliard's avatar
Alexandre Julliard committed
1631
static LRESULT
1632
TRACKBAR_LButtonUp (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1633
{
1634
    if (infoPtr->flags & TB_DRAG_MODE) {
1635 1636
        notify_with_scroll (infoPtr, TB_THUMBPOSITION | (infoPtr->lPos<<16));
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1637 1638
        infoPtr->flags &= ~TB_DRAG_MODE;
        ReleaseCapture ();
1639
	notify(infoPtr, NM_RELEASEDCAPTURE);
1640
        TRACKBAR_ActivateToolTip(infoPtr, FALSE);
1641
	TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
1642 1643 1644 1645
    }
    if (infoPtr->flags & TB_AUTO_PAGE) {
	KillTimer (infoPtr->hwndSelf, TB_REFRESH_TIMER);
        infoPtr->flags &= ~TB_AUTO_PAGE;
1646
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1647
        ReleaseCapture ();
1648
	notify(infoPtr, NM_RELEASEDCAPTURE);
1649
    }
1650

Alexandre Julliard's avatar
Alexandre Julliard committed
1651 1652 1653
    return 0;
}

1654

Alexandre Julliard's avatar
Alexandre Julliard committed
1655
static LRESULT
1656
TRACKBAR_CaptureChanged (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1657
{
1658
    notify_with_scroll (infoPtr, TB_ENDTRACK);
1659
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1660
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1661

1662

Alexandre Julliard's avatar
Alexandre Julliard committed
1663
static LRESULT
1664
TRACKBAR_Paint (TRACKBAR_INFO *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1665
{
1666 1667 1668 1669 1670 1671 1672 1673
    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
1674 1675 1676 1677 1678 1679

    return 0;
}


static LRESULT
1680
TRACKBAR_SetFocus (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1681
{
1682
    TRACE("\n");
1683
    infoPtr->flags |= TB_IS_FOCUSED;
1684
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1685 1686 1687 1688 1689 1690

    return 0;
}


static LRESULT
1691
TRACKBAR_Size (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1692
{
1693
    TRACKBAR_RecalculateAll(infoPtr);
1694
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1695 1696 1697 1698

    return 0;
}

1699 1700 1701 1702 1703 1704 1705
static LRESULT
TRACKBAR_StyleChanged (TRACKBAR_INFO *infoPtr, WPARAM wStyleType,
                       const STYLESTRUCT *lpss)
{
    if (wStyleType != GWL_STYLE) return 0;

    infoPtr->dwStyle = lpss->styleNew;
1706 1707
    TRACKBAR_RecalculateAll(infoPtr);
    TRACKBAR_InvalidateAll(infoPtr);
1708 1709
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1710

1711
static LRESULT
1712
TRACKBAR_Timer (TRACKBAR_INFO *infoPtr)
1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723
{
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
	if (GetCursorPos(&pt))
	    if (ScreenToClient(infoPtr->hwndSelf, &pt))
		TRACKBAR_AutoPage(infoPtr, pt);
    }
    return 0;
}


1724
/* update theme after a WM_THEMECHANGED message */
1725
static LRESULT theme_changed (const TRACKBAR_INFO* infoPtr)
1726 1727 1728
{
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
    CloseThemeData (theme);
1729
    OpenThemeData (infoPtr->hwndSelf, themeClass);
1730
    InvalidateRect (infoPtr->hwndSelf, NULL, FALSE);
1731 1732 1733 1734
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1735
static LRESULT
1736
TRACKBAR_MouseMove (TRACKBAR_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1737
{
1738
    INT clickPlace = (infoPtr->dwStyle & TBS_VERT) ? y : x;
1739
    LONG dragPos, oldPos = infoPtr->lPos;
1740

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

1743 1744
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
1745 1746
	pt.x = x;
	pt.y = y;
1747
	TRACKBAR_AutoPage (infoPtr, pt);
1748
	return TRUE;
1749 1750
    }

1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780
    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
1781

1782 1783
    dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace);

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1786
    infoPtr->lPos = dragPos;
1787
    TRACKBAR_UpdateThumb (infoPtr);
1788

1789
    notify_with_scroll (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16));
1790

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1791
    TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos);
1792
    UpdateWindow (infoPtr->hwndSelf);
Alex Priem's avatar
Alex Priem committed
1793

1794
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1795 1796
}

1797
static BOOL
1798
TRACKBAR_KeyDown (TRACKBAR_INFO *infoPtr, INT nVirtKey)
Alexandre Julliard's avatar
Alexandre Julliard committed
1799
{
1800 1801
    BOOL downIsLeft = infoPtr->dwStyle & TBS_DOWNISLEFT;
    BOOL vert = infoPtr->dwStyle & TBS_VERT;
1802
    LONG pos = infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1803

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

1806
    switch (nVirtKey) {
1807
    case VK_UP:
1808 1809 1810
	if (!vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
        else TRACKBAR_LineUp(infoPtr);
        break;
1811
    case VK_LEFT:
1812 1813
        if (vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
        else TRACKBAR_LineUp(infoPtr);
1814
        break;
1815
    case VK_DOWN:
1816 1817 1818
	if (!vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
        else TRACKBAR_LineDown(infoPtr);
        break;
1819
    case VK_RIGHT:
1820 1821
	if (vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
        else TRACKBAR_LineDown(infoPtr);
1822 1823
        break;
    case VK_NEXT:
1824 1825
	if (!vert && downIsLeft) TRACKBAR_PageUp(infoPtr);
        else TRACKBAR_PageDown(infoPtr);
1826 1827
        break;
    case VK_PRIOR:
1828 1829
	if (!vert && downIsLeft) TRACKBAR_PageDown(infoPtr);
        else TRACKBAR_PageUp(infoPtr);
1830
        break;
1831
    case VK_HOME:
1832 1833
        if (infoPtr->lPos == infoPtr->lRangeMin) return FALSE;
        infoPtr->lPos = infoPtr->lRangeMin;
1834
        notify_with_scroll (infoPtr, TB_TOP);
1835
        break;
1836
    case VK_END:
1837 1838
        if (infoPtr->lPos == infoPtr->lRangeMax) return FALSE;
        infoPtr->lPos = infoPtr->lRangeMax;
1839
        notify_with_scroll (infoPtr, TB_BOTTOM);
1840 1841
        break;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1842

1843
    if (pos != infoPtr->lPos) {
1844
	TRACKBAR_UpdateThumb (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1845
	TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos);
1846
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1847

1848
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1849 1850
}

1851

1852
static inline BOOL
1853
TRACKBAR_KeyUp (const TRACKBAR_INFO *infoPtr, INT nVirtKey)
Alexandre Julliard's avatar
Alexandre Julliard committed
1854
{
1855
    switch (nVirtKey) {
1856
    case VK_LEFT:
1857
    case VK_UP:
1858
    case VK_RIGHT:
1859
    case VK_DOWN:
1860 1861
    case VK_NEXT:
    case VK_PRIOR:
1862
    case VK_HOME:
1863
    case VK_END:
1864
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1865 1866
    }
    return TRUE;
Alex Priem's avatar
Alex Priem committed
1867 1868 1869
}


1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882
static LRESULT
TRACKBAR_Enable (TRACKBAR_INFO *infoPtr, BOOL enable)
{
    if (enable)
        infoPtr->dwStyle &= ~WS_DISABLED;
    else
        infoPtr->dwStyle |= WS_DISABLED;

    InvalidateRect(infoPtr->hwndSelf, &infoPtr->rcThumb, TRUE);

    return 1;
}

1883
static LRESULT WINAPI
1884
TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1885
{
1886
    TRACKBAR_INFO *infoPtr = (TRACKBAR_INFO *)GetWindowLongPtrW (hwnd, 0);
1887

1888
    TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, uMsg, wParam, lParam);
1889 1890 1891 1892

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1893 1894
    switch (uMsg)
    {
1895
    case TBM_CLEARSEL:
1896
        return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1897

1898
    case TBM_CLEARTICS:
1899
        return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1900

1901
    case TBM_GETBUDDY:
1902
        return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB);
Alexandre Julliard's avatar
Alexandre Julliard committed
1903

1904
    case TBM_GETCHANNELRECT:
1905
        return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1906

1907
    case TBM_GETLINESIZE:
1908
        return infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1909

1910
    case TBM_GETNUMTICS:
1911
        return TRACKBAR_GetNumTics (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1912

1913
    case TBM_GETPAGESIZE:
1914
        return infoPtr->lPageSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1915

1916
    case TBM_GETPOS:
1917
        return infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1918

1919
    case TBM_GETPTICS:
1920
        return (LRESULT)infoPtr->tics;
Alexandre Julliard's avatar
Alexandre Julliard committed
1921

1922
    case TBM_GETRANGEMAX:
1923
        return infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1924

1925
    case TBM_GETRANGEMIN:
1926
        return infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1927

1928
    case TBM_GETSELEND:
1929
        return infoPtr->lSelMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1930

1931
    case TBM_GETSELSTART:
1932
        return infoPtr->lSelMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1933

1934
    case TBM_GETTHUMBLENGTH:
1935
        return infoPtr->uThumbLen;
Alexandre Julliard's avatar
Alexandre Julliard committed
1936

1937
    case TBM_GETTHUMBRECT:
1938
	return CopyRect((LPRECT)lParam, &infoPtr->rcThumb);
Alexandre Julliard's avatar
Alexandre Julliard committed
1939

Alexandre Julliard's avatar
Alexandre Julliard committed
1940
    case TBM_GETTIC:
1941
        return TRACKBAR_GetTic (infoPtr, (INT)wParam);
1942

Alexandre Julliard's avatar
Alexandre Julliard committed
1943
    case TBM_GETTICPOS:
1944
        return TRACKBAR_GetTicPos (infoPtr, (INT)wParam);
1945

1946
    case TBM_GETTOOLTIPS:
1947
        return (LRESULT)infoPtr->hwndToolTip;
Alexandre Julliard's avatar
Alexandre Julliard committed
1948

1949
    case TBM_GETUNICODEFORMAT:
1950
        return infoPtr->bUnicode;
Alexandre Julliard's avatar
Alexandre Julliard committed
1951

1952
    case TBM_SETBUDDY:
1953
        return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1954

1955
    case TBM_SETLINESIZE:
1956
        return TRACKBAR_SetLineSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1957

1958
    case TBM_SETPAGESIZE:
1959
        return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1960

1961
    case TBM_SETPOS:
1962
        return TRACKBAR_SetPos (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1963

1964
    case TBM_SETRANGE:
1965
        return TRACKBAR_SetRange (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1966

1967
    case TBM_SETRANGEMAX:
1968
        return TRACKBAR_SetRangeMax (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1969

1970
    case TBM_SETRANGEMIN:
1971
        return TRACKBAR_SetRangeMin (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1972

1973
    case TBM_SETSEL:
1974
        return TRACKBAR_SetSel (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1975

1976
    case TBM_SETSELEND:
1977
        return TRACKBAR_SetSelEnd (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1978

1979
    case TBM_SETSELSTART:
1980
        return TRACKBAR_SetSelStart (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1981

1982
    case TBM_SETTHUMBLENGTH:
1983
        return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1984

1985
    case TBM_SETTIC:
1986
        return TRACKBAR_SetTic (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1987

Alexandre Julliard's avatar
Alexandre Julliard committed
1988
    case TBM_SETTICFREQ:
1989
        return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1990

1991
    case TBM_SETTIPSIDE:
1992
        return TRACKBAR_SetTipSide (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1993

1994
    case TBM_SETTOOLTIPS:
1995
        return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1996

1997 1998
    case TBM_SETUNICODEFORMAT:
	return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1999 2000


2001
    case WM_CAPTURECHANGED:
2002
        if (hwnd == (HWND)lParam) return 0;
2003
        return TRACKBAR_CaptureChanged (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2004

2005
    case WM_CREATE:
2006
        return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2007

2008
    case WM_DESTROY:
2009
        return TRACKBAR_Destroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2010

2011 2012
    case WM_ENABLE:
        return TRACKBAR_Enable (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2013

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
2014
    case WM_ERASEBKGND:
2015
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2016

2017 2018
    case WM_GETDLGCODE:
        return DLGC_WANTARROWS;
Alexandre Julliard's avatar
Alexandre Julliard committed
2019

2020
    case WM_KEYDOWN:
2021
        return TRACKBAR_KeyDown (infoPtr, (INT)wParam);
2022

2023
    case WM_KEYUP:
2024
        return TRACKBAR_KeyUp (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2025

2026
    case WM_KILLFOCUS:
2027
        return TRACKBAR_KillFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2028

2029
    case WM_LBUTTONDOWN:
2030
        return TRACKBAR_LButtonDown (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2031

2032
    case WM_LBUTTONUP:
2033
        return TRACKBAR_LButtonUp (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2034

2035 2036 2037 2038 2039
    case WM_MOUSELEAVE:
        infoPtr->flags &= ~TB_THUMB_HOT; 
        InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
        return 0;
    
2040
    case WM_MOUSEMOVE:
2041
        return TRACKBAR_MouseMove (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2042

2043
    case WM_PRINTCLIENT:
2044
    case WM_PAINT:
2045
        return TRACKBAR_Paint (infoPtr, (HDC)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2046

2047
    case WM_SETFOCUS:
2048
        return TRACKBAR_SetFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2049

2050
    case WM_SIZE:
2051
        return TRACKBAR_Size (infoPtr);
2052 2053 2054

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

2056 2057 2058
    case WM_THEMECHANGED:
        return theme_changed (infoPtr);

2059
    case WM_TIMER:
2060
	return TRACKBAR_Timer (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2061

2062
    case WM_WININICHANGE:
2063
        return TRACKBAR_InitializeThumb (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2064

2065
    default:
2066
        if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
2067
            ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);
2068
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2069 2070 2071 2072
    }
}


2073
void TRACKBAR_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2074
{
2075
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
2076

2077
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
2078
    wndClass.style         = CS_GLOBALCLASS;
2079
    wndClass.lpfnWndProc   = TRACKBAR_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
2080 2081
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(TRACKBAR_INFO *);
2082
    wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
2083
    wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2084
    wndClass.lpszClassName = TRACKBAR_CLASSW;
2085

2086
    RegisterClassW (&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
2087
}
2088 2089


2090
void TRACKBAR_Unregister (void)
2091
{
2092
    UnregisterClassW (TRACKBAR_CLASSW, NULL);
2093
}