trackbar.c 56.4 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 503
	rcTics.top    = infoPtr->rcChannel.top + offsetthumb;
	rcTics.bottom = infoPtr->rcChannel.bottom - offsetthumb - 1;
504
    } else {
505
        offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2;
506 507
	rcTics.left   = infoPtr->rcChannel.left + offsetthumb;
	rcTics.right  = infoPtr->rcChannel.right - offsetthumb - 1;
508 509
	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 616 617 618
static int
TRACKBAR_FillThumb (const TRACKBAR_INFO *infoPtr, HDC hdc, HBRUSH hbrush)
{
    const RECT *thumb = &infoPtr->rcThumb;
619
    POINT points[6];
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 690 691 692 693 694 695 696 697 698 699
    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);
700
    Polygon(hdc, points, sizeof(points) / sizeof(points[0]));
701 702 703 704 705
    SelectObject(hdc, oldbr);

    return PointDepth;
}

706
static void
707
TRACKBAR_DrawThumb (TRACKBAR_INFO *infoPtr, HDC hdc)
708
{
709
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
710
    int PointDepth;
711 712
    HBRUSH brush;

713 714 715 716
    if (theme)
    {
        int partId;
        int stateId;
717 718 719 720
        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;
721
        else
722
            partId = (infoPtr->dwStyle & TBS_VERT) ? TKP_THUMBRIGHT : TKP_THUMBBOTTOM;
723
            
724
        if (infoPtr->dwStyle & WS_DISABLED)
725 726 727 728 729 730 731 732
            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;
        
733
        DrawThemeBackground (theme, hdc, partId, stateId, &infoPtr->rcThumb, NULL);
734 735 736
        
        return;
    }
737

738
    if (infoPtr->dwStyle & WS_DISABLED || infoPtr->flags & TB_DRAG_MODE)
739 740 741 742 743 744 745 746 747 748
    {
        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
749 750 751
        brush = GetSysColorBrush(COLOR_BTNFACE);

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

753
    if (infoPtr->dwStyle & TBS_BOTH)
754
    {
755 756
       DrawEdge(hdc, &infoPtr->rcThumb, EDGE_RAISED, BF_RECT | BF_SOFT);
       return;
757 758
    }
    else
759
    {
760 761
        RECT thumb = infoPtr->rcThumb;

762
        if (infoPtr->dwStyle & TBS_VERT)
763
        {
764
          if (infoPtr->dwStyle & TBS_LEFT)
765
          {
766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781
            /* 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;
782 783 784
          }
          else
          {
785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
            /* 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);
800 801 802 803
          }
        }
        else
        {
804
          if (infoPtr->dwStyle & TBS_TOP)
805
          {
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820
            /* 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);
821 822 823
          }
          else
          {
824 825 826 827 828 829 830 831 832 833 834 835 836 837 838
            /* 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);
839 840 841 842
          }
        }
    }
}
Alex Priem's avatar
Alex Priem committed
843

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

845
static inline void
846
TRACKBAR_ActivateToolTip (const TRACKBAR_INFO *infoPtr, BOOL fShow)
847 848 849 850 851 852 853 854 855 856 857 858 859
{
    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);
}


860
static void
861
TRACKBAR_UpdateToolTip (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
862
{
863 864
    WCHAR buf[80];
    static const WCHAR fmt[] = { '%', 'l', 'd', 0 };
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
865 866
    TTTOOLINFOW ti;
    POINT pt;
867
    RECT rcClient;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
868
    LRESULT size;
Alexandre Julliard's avatar
Alexandre Julliard committed
869

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
872 873 874 875 876 877 878 879 880
    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);

881
    GetClientRect (infoPtr->hwndSelf, &rcClient);
882
    size = SendMessageW (infoPtr->hwndToolTip, TTM_GETBUBBLESIZE, 0, (LPARAM)&ti);
883
    if (infoPtr->dwStyle & TBS_VERT) {
884
	if (infoPtr->fLocation == TBTS_LEFT)
885
	    pt.x = 0 - LOWORD(size) - TOOLTIP_OFFSET;
886
	else
887
	    pt.x = rcClient.right + TOOLTIP_OFFSET;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
888 889
    	pt.y = (infoPtr->rcThumb.top + infoPtr->rcThumb.bottom - HIWORD(size))/2;
    } else {
890
	if (infoPtr->fLocation == TBTS_TOP)
891
	    pt.y = 0 - HIWORD(size) - TOOLTIP_OFFSET;
892
	else
893
            pt.y = rcClient.bottom + TOOLTIP_OFFSET;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
894
        pt.x = (infoPtr->rcThumb.left + infoPtr->rcThumb.right - LOWORD(size))/2;
Alex Priem's avatar
Alex Priem committed
895
    }
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
896 897 898
    ClientToScreen(infoPtr->hwndSelf, &pt);

    SendMessageW (infoPtr->hwndToolTip, TTM_TRACKPOSITION,
899
                  0, MAKELPARAM(pt.x, pt.y));
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
900 901 902 903
}


static void
904
TRACKBAR_Refresh (TRACKBAR_INFO *infoPtr, HDC hdcDst)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
905
{
906
    RECT rcClient;
907 908
    HDC hdc;
    HBITMAP hOldBmp = 0, hOffScreenBmp = 0;
909 910
    NMCUSTOMDRAW nmcd;
    int gcdrf, icdrf;
911

912
    if (infoPtr->flags & TB_THUMBCHANGED) {
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
913
        TRACKBAR_UpdateThumb (infoPtr);
914
        if (infoPtr->flags & TB_THUMBSIZECHANGED)
915
            TRACKBAR_CalcChannel (infoPtr);
916 917
    }
    if (infoPtr->flags & TB_SELECTIONCHANGED)
918
        TRACKBAR_CalcSelection (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
919

920
    if (infoPtr->flags & TB_DRAG_MODE)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
921 922
        TRACKBAR_UpdateToolTip (infoPtr);

923 924
    infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED);

925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940
    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;
    }

941 942
    ZeroMemory(&nmcd, sizeof(nmcd));
    nmcd.hdr.hwndFrom = infoPtr->hwndSelf;
943
    nmcd.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
944 945
    nmcd.hdr.code = NM_CUSTOMDRAW;
    nmcd.hdc = hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
946

947 948
    /* start the paint cycle */
    nmcd.rc = rcClient;
949
    gcdrf = notify_customdraw(infoPtr, &nmcd, CDDS_PREPAINT);
950 951
    if (gcdrf & CDRF_SKIPDEFAULT) goto cleanup;
    
952
    /* Erase background */
953
    if (gcdrf == CDRF_DODEFAULT ||
954
        notify_customdraw(infoPtr, &nmcd, CDDS_PREERASE) != CDRF_SKIPDEFAULT) {
955
        if (GetWindowTheme (infoPtr->hwndSelf)) {
956
            DrawThemeParentBackground (infoPtr->hwndSelf, hdc, 0);
957
        }
958 959
        else
	    FillRect (hdc, &rcClient, GetSysColorBrush(COLOR_BTNFACE));
960
        if (gcdrf != CDRF_DODEFAULT)
961
	    notify_customdraw(infoPtr, &nmcd, CDDS_POSTERASE);
962
    }
963
    
Alexandre Julliard's avatar
Alexandre Julliard committed
964
    /* draw channel */
965 966 967 968
    if (gcdrf & CDRF_NOTIFYITEMDRAW) {
        nmcd.dwItemSpec = TBCD_CHANNEL;
	nmcd.uItemState = CDIS_DEFAULT;
	nmcd.rc = infoPtr->rcChannel;
969
	icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
970 971
    } else icdrf = CDRF_DODEFAULT;
    if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
972
	TRACKBAR_DrawChannel (infoPtr, hdc);
973
	if (icdrf & CDRF_NOTIFYPOSTPAINT)
974
	    notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
Alexandre Julliard's avatar
Alexandre Julliard committed
975 976
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
977 978

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

1008 1009 1010 1011 1012
    /* draw focus rectangle */
    if (infoPtr->bFocussed) {
	DrawFocusRect(hdc, &rcClient);
    }

1013 1014
    /* finish up the painting */
    if (gcdrf & CDRF_NOTIFYPOSTPAINT)
1015
	notify_customdraw(infoPtr, &nmcd, CDDS_POSTPAINT);
1016 1017
    
cleanup:
1018 1019 1020 1021 1022 1023 1024
    /* 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
1025 1026 1027
}


1028
static void
1029
TRACKBAR_AlignBuddies (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1030
{
1031
    HWND hwndParent = GetParent (infoPtr->hwndSelf);
1032 1033
    RECT rcSelf, rcBuddy;
    INT x, y;
Alexandre Julliard's avatar
Alexandre Julliard committed
1034

1035
    GetWindowRect (infoPtr->hwndSelf, &rcSelf);
1036
    MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcSelf, 2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1037 1038 1039

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

1043
	if (infoPtr->dwStyle & TBS_VERT) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1044 1045 1046 1047 1048 1049 1050 1051 1052 1053
	    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;
	}

1054
	SetWindowPos (infoPtr->hwndBuddyLA, 0, x, y, 0, 0,
1055
                      SWP_NOZORDER | SWP_NOSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1056 1057 1058 1059 1060
    }


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

1064
	if (infoPtr->dwStyle & TBS_VERT) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1065 1066 1067 1068 1069 1070 1071 1072 1073
	    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;
	}
1074
	SetWindowPos (infoPtr->hwndBuddyRB, 0, x, y, 0, 0,
1075
                      SWP_NOZORDER | SWP_NOSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1076 1077 1078 1079 1080
    }
}


static LRESULT
1081
TRACKBAR_ClearSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
1082
{
1083 1084
    infoPtr->lSelMin = 0;
    infoPtr->lSelMax = 0;
1085
    infoPtr->flags |= TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1086

1087
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1088 1089 1090 1091 1092 1093

    return 0;
}


static LRESULT
1094
TRACKBAR_ClearTics (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
1095 1096
{
    if (infoPtr->tics) {
1097
        Free (infoPtr->tics);
1098 1099
        infoPtr->tics = NULL;
        infoPtr->uNumTics = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1100 1101
    }

1102
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1103 1104 1105 1106 1107

    return 0;
}


1108
static inline LRESULT
1109
TRACKBAR_GetChannelRect (const TRACKBAR_INFO *infoPtr, LPRECT lprc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1110
{
1111
    if (lprc == NULL) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121

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

    return 0;
}


1122
static inline LONG
1123
TRACKBAR_GetNumTics (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1124
{
1125
    if (infoPtr->dwStyle & TBS_NOTICKS) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1126

1127
    return infoPtr->uNumTics + 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1128 1129 1130
}


1131
static int comp_tics (const void *ap, const void *bp)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1132
{
1133 1134
    const DWORD a = *(const DWORD *)ap;
    const DWORD b = *(const DWORD *)bp;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1135

1136
    TRACE("(a=%d, b=%d)\n", a, b);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1137 1138 1139 1140 1141
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1142

1143
static inline LONG
1144
TRACKBAR_GetTic (const TRACKBAR_INFO *infoPtr, INT iTic)
Alexandre Julliard's avatar
Alexandre Julliard committed
1145
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1146
    if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics)
Alexandre Julliard's avatar
Alexandre Julliard committed
1147 1148
	return -1;

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1149
    qsort(infoPtr->tics, infoPtr->uNumTics, sizeof(DWORD), comp_tics);
1150
    return infoPtr->tics[iTic];
Alexandre Julliard's avatar
Alexandre Julliard committed
1151 1152 1153
}


1154
static inline LONG
1155
TRACKBAR_GetTicPos (const TRACKBAR_INFO *infoPtr, INT iTic)
Alexandre Julliard's avatar
Alexandre Julliard committed
1156
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1157
    LONG range, width, pos, tic;
1158
    int offsetthumb;
Alexandre Julliard's avatar
Alexandre Julliard committed
1159

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1163
    tic   = TRACKBAR_GetTic (infoPtr, iTic);
1164
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
1165
    if (range <= 0) range = 1;
1166 1167 1168
    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
1169

1170
    return pos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1171 1172
}

1173

1174 1175
static HWND
TRACKBAR_SetBuddy (TRACKBAR_INFO *infoPtr, BOOL fLocation, HWND hwndBuddy)
Alexandre Julliard's avatar
Alexandre Julliard committed
1176
{
1177
    HWND hwndTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1178

1179
    if (fLocation) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1180 1181
	/* buddy is left or above */
	hwndTemp = infoPtr->hwndBuddyLA;
1182
	infoPtr->hwndBuddyLA = hwndBuddy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1183 1184
    }
    else {
1185 1186
        /* buddy is right or below */
        hwndTemp = infoPtr->hwndBuddyRB;
1187
        infoPtr->hwndBuddyRB = hwndBuddy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1188 1189
    }

1190
    TRACKBAR_AlignBuddies (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1191

1192
    return hwndTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1193 1194 1195
}


1196
static inline LONG
1197
TRACKBAR_SetLineSize (TRACKBAR_INFO *infoPtr, LONG lLineSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1198
{
1199
    LONG lTemp = infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1200

1201
    infoPtr->lLineSize = lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1202

1203
    return lTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1204 1205 1206
}


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

1212 1213 1214 1215
    if (lPageSize != -1)
        infoPtr->lPageSize = lPageSize;
    else
        infoPtr->lPageSize = TB_DEFAULTPAGESIZE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1216

1217
    return lTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1218 1219 1220
}


1221
static inline LRESULT
1222
TRACKBAR_SetPos (TRACKBAR_INFO *infoPtr, BOOL fPosition, LONG lPosition)
Alexandre Julliard's avatar
Alexandre Julliard committed
1223
{
1224
    LONG oldPos = infoPtr->lPos;
1225
    infoPtr->lPos = lPosition;
Alexandre Julliard's avatar
Alexandre Julliard committed
1226

1227 1228
    if (infoPtr->lPos < infoPtr->lRangeMin)
	infoPtr->lPos = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1229

1230 1231
    if (infoPtr->lPos > infoPtr->lRangeMax)
	infoPtr->lPos = infoPtr->lRangeMax;
1232
    infoPtr->flags |= TB_THUMBPOSCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1233

1234
    if (fPosition && oldPos != lPosition) TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition);
Alexandre Julliard's avatar
Alexandre Julliard committed
1235 1236 1237 1238 1239

    return 0;
}


1240
static inline LRESULT
1241
TRACKBAR_SetRange (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG range)
Alexandre Julliard's avatar
Alexandre Julliard committed
1242
{
1243 1244 1245 1246 1247
    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
1248

1249 1250
    if (infoPtr->lPos < infoPtr->lRangeMin) {
        infoPtr->lPos = infoPtr->lRangeMin;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1251
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1252
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1253

1254 1255
    if (infoPtr->lPos > infoPtr->lRangeMax) {
        infoPtr->lPos = infoPtr->lRangeMax;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1256
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1257
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1258

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

1262 1263 1264 1265
    if (changed && (infoPtr->dwStyle & TBS_AUTOTICKS))
        TRACKBAR_RecalculateTics (infoPtr);

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1266 1267 1268 1269 1270

    return 0;
}


1271
static inline LRESULT
1272
TRACKBAR_SetRangeMax (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG lMax)
Alexandre Julliard's avatar
Alexandre Julliard committed
1273
{
1274 1275
    BOOL changed = infoPtr->lRangeMax != lMax;

1276 1277 1278
    infoPtr->lRangeMax = lMax;
    if (infoPtr->lPos > infoPtr->lRangeMax) {
        infoPtr->lPos = infoPtr->lRangeMax;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1279
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1280
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1281

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

1285 1286 1287 1288
    if (changed && (infoPtr->dwStyle & TBS_AUTOTICKS))
        TRACKBAR_RecalculateTics (infoPtr);

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

    return 0;
}


1294
static inline LRESULT
1295
TRACKBAR_SetRangeMin (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG lMin)
Alexandre Julliard's avatar
Alexandre Julliard committed
1296
{
1297 1298
    BOOL changed = infoPtr->lRangeMin != lMin;

1299 1300 1301
    infoPtr->lRangeMin = lMin;
    if (infoPtr->lPos < infoPtr->lRangeMin) {
        infoPtr->lPos = infoPtr->lRangeMin;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1302
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1303
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1304

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

1308 1309 1310 1311
    if (changed && (infoPtr->dwStyle & TBS_AUTOTICKS))
        TRACKBAR_RecalculateTics (infoPtr);

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1312 1313 1314 1315

    return 0;
}

1316

1317
static inline LRESULT
1318
TRACKBAR_SetSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lSel)
Alexandre Julliard's avatar
Alexandre Julliard committed
1319
{
1320
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1321 1322
        infoPtr->lSelMin = 0;
        infoPtr->lSelMax = 0;
1323
        return 0;
1324
    }
1325

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1326 1327 1328
    infoPtr->lSelMin = (SHORT)LOWORD(lSel);
    infoPtr->lSelMax = (SHORT)HIWORD(lSel);
    infoPtr->flags |= TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1329

1330 1331 1332 1333
    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
1334

1335
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1336 1337 1338 1339 1340

    return 0;
}


1341
static inline LRESULT
1342
TRACKBAR_SetSelEnd (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lEnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
1343
{
1344
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1345
        infoPtr->lSelMax = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1346
	return 0;
1347
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1348

1349
    infoPtr->lSelMax = lEnd;
1350
    infoPtr->flags |= TB_SELECTIONCHANGED;
1351

1352 1353
    if (infoPtr->lSelMax > infoPtr->lRangeMax)
        infoPtr->lSelMax = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1354

1355
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1356 1357 1358 1359 1360

    return 0;
}


1361
static inline LRESULT
1362
TRACKBAR_SetSelStart (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lStart)
Alexandre Julliard's avatar
Alexandre Julliard committed
1363
{
1364
    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)){
1365
        infoPtr->lSelMin = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1366
	return 0;
1367
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1368

1369
    infoPtr->lSelMin = lStart;
1370
    infoPtr->flags  |=TB_SELECTIONCHANGED;
1371

1372 1373
    if (infoPtr->lSelMin < infoPtr->lRangeMin)
        infoPtr->lSelMin = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1374

1375
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1376 1377 1378 1379 1380

    return 0;
}


1381
static inline LRESULT
1382
TRACKBAR_SetThumbLength (TRACKBAR_INFO *infoPtr, UINT iLength)
Alexandre Julliard's avatar
Alexandre Julliard committed
1383
{
1384
    if (infoPtr->dwStyle & TBS_FIXEDLENGTH) {
1385 1386
        /* We're not supposed to check if it's really changed or not,
           just repaint in any case. */
1387
        infoPtr->uThumbLen = iLength;
1388
	infoPtr->flags |= TB_THUMBSIZECHANGED;
1389
	TRACKBAR_InvalidateAll(infoPtr);
1390
    }
1391

Alexandre Julliard's avatar
Alexandre Julliard committed
1392 1393 1394 1395
    return 0;
}


1396
static inline LRESULT
1397
TRACKBAR_SetTic (TRACKBAR_INFO *infoPtr, LONG lPos)
Alexandre Julliard's avatar
Alexandre Julliard committed
1398
{
1399
    if ((lPos < infoPtr->lRangeMin) || (lPos> infoPtr->lRangeMax))
1400
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1401

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

1404
    infoPtr->uNumTics++;
1405
    infoPtr->tics=ReAlloc( infoPtr->tics,
1406
                                    (infoPtr->uNumTics)*sizeof (DWORD));
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1407 1408
    if (!infoPtr->tics) {
	infoPtr->uNumTics = 0;
1409
	notify(infoPtr, NM_OUTOFMEMORY);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1410 1411 1412
	return FALSE;
    }
    infoPtr->tics[infoPtr->uNumTics-1] = lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1413

1414
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1415 1416 1417 1418 1419

    return TRUE;
}


1420
static inline LRESULT
1421 1422
TRACKBAR_SetTicFreq (TRACKBAR_INFO *infoPtr, WORD wFreq)
{
1423
    if (infoPtr->dwStyle & TBS_AUTOTICKS) {
1424
        infoPtr->uTicFreq = wFreq;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1425
	TRACKBAR_RecalculateTics (infoPtr);
1426
	TRACKBAR_InvalidateAll(infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1427
    }
1428 1429 1430 1431 1432

    return 0;
}


1433
static inline INT
1434
TRACKBAR_SetTipSide (TRACKBAR_INFO *infoPtr, INT fLocation)
Alexandre Julliard's avatar
Alexandre Julliard committed
1435
{
1436
    INT fTemp = infoPtr->fLocation;
Alexandre Julliard's avatar
Alexandre Julliard committed
1437

1438
    infoPtr->fLocation = fLocation;
1439

Alexandre Julliard's avatar
Alexandre Julliard committed
1440 1441 1442 1443
    return fTemp;
}


1444
static inline LRESULT
1445
TRACKBAR_SetToolTips (TRACKBAR_INFO *infoPtr, HWND hwndTT)
Alexandre Julliard's avatar
Alexandre Julliard committed
1446
{
1447
    infoPtr->hwndToolTip = hwndTT;
Alexandre Julliard's avatar
Alexandre Julliard committed
1448 1449 1450 1451 1452

    return 0;
}


1453
static inline BOOL
1454 1455 1456 1457 1458 1459 1460 1461
TRACKBAR_SetUnicodeFormat (TRACKBAR_INFO *infoPtr, BOOL fUnicode)
{
    BOOL bTemp = infoPtr->bUnicode;

    infoPtr->bUnicode = fUnicode;

    return bTemp;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1462 1463


Alexandre Julliard's avatar
Alexandre Julliard committed
1464
static LRESULT
1465
TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1466
{
1467
    RECT rect;
1468
    int clientWidth, clientMetric;
1469 1470

    /* initial thumb length */
1471
    clientMetric = (infoPtr->dwStyle & TBS_ENABLESELRANGE) ? 23 : 21;
1472
    GetClientRect(infoPtr->hwndSelf,&rect);
1473
    if (infoPtr->dwStyle & TBS_VERT) {
1474
	clientWidth = rect.right - rect.left;
1475
    } else {
1476
	clientWidth = rect.bottom - rect.top;
1477
    }
1478 1479
    if (clientWidth >= clientMetric)
        infoPtr->uThumbLen = clientMetric;
1480 1481
    else
        infoPtr->uThumbLen = clientWidth > 9 ? clientWidth - 6 : 4;
Alexandre Julliard's avatar
Alexandre Julliard committed
1482

1483
    TRACKBAR_CalcChannel (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1484
    TRACKBAR_UpdateThumb (infoPtr);
1485
    infoPtr->flags &= ~TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1486

1487
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1488
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1489 1490 1491


static LRESULT
1492
TRACKBAR_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
1493 1494 1495
{
    TRACKBAR_INFO *infoPtr;

1496
    infoPtr = Alloc (sizeof(TRACKBAR_INFO));
1497
    if (!infoPtr) return -1;
1498
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1499

1500
    /* set default values */
1501
    infoPtr->hwndSelf  = hwnd;
1502
    infoPtr->dwStyle   = lpcs->style;
1503 1504 1505
    infoPtr->lRangeMin = 0;
    infoPtr->lRangeMax = 100;
    infoPtr->lLineSize = 1;
1506
    infoPtr->lPageSize = TB_DEFAULTPAGESIZE;
1507 1508 1509
    infoPtr->lSelMin   = 0;
    infoPtr->lSelMax   = 0;
    infoPtr->lPos      = 0;
1510
    infoPtr->fLocation = TBTS_TOP;
Alexandre Julliard's avatar
Alexandre Julliard committed
1511
    infoPtr->uNumTics  = 0;    /* start and end tic are not included in count*/
1512
    infoPtr->uTicFreq  = 1;
1513
    infoPtr->tics      = NULL;
1514
    infoPtr->hwndNotify= lpcs->hwndParent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1515

1516
    TRACKBAR_InitializeThumb (infoPtr);
Alex Priem's avatar
Alex Priem committed
1517

1518
    /* Create tooltip control */
1519
    if (infoPtr->dwStyle & TBS_TOOLTIPS) {
Alex Priem's avatar
Alex Priem committed
1520 1521

    	infoPtr->hwndToolTip =
1522
            CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1523 1524 1525
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             hwnd, 0, 0, 0);
Alex Priem's avatar
Alex Priem committed
1526

1527
    	if (infoPtr->hwndToolTip) {
1528 1529
            TTTOOLINFOW ti;
            WCHAR wEmpty = 0;
1530 1531 1532 1533
            ZeroMemory (&ti, sizeof(ti));
            ti.cbSize   = sizeof(ti);
     	    ti.uFlags   = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
	    ti.hwnd     = hwnd;
1534
            ti.lpszText = &wEmpty;
Alex Priem's avatar
Alex Priem committed
1535

1536 1537
            SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
	 }
1538
    }
1539 1540
    
    OpenThemeData (hwnd, themeClass);
1541

Alexandre Julliard's avatar
Alexandre Julliard committed
1542 1543 1544 1545 1546
    return 0;
}


static LRESULT
1547
TRACKBAR_Destroy (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1548
{
1549
    /* delete tooltip control */
Alex Priem's avatar
Alex Priem committed
1550
    if (infoPtr->hwndToolTip)
1551
    	DestroyWindow (infoPtr->hwndToolTip);
Alex Priem's avatar
Alex Priem committed
1552

1553 1554 1555
    Free (infoPtr->tics);
    infoPtr->tics = NULL;

1556
    SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
1557
    CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
1558 1559
    Free (infoPtr);

Alexandre Julliard's avatar
Alexandre Julliard committed
1560 1561 1562 1563 1564
    return 0;
}


static LRESULT
1565
TRACKBAR_KillFocus (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1566
{
1567
    TRACE("\n");
1568
    infoPtr->bFocussed = FALSE;
1569
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1570 1571 1572 1573 1574

    return 0;
}

static LRESULT
1575
TRACKBAR_LButtonDown (TRACKBAR_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1576
{
1577 1578 1579 1580
    POINT clickPoint;

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

1582 1583
    SetFocus(infoPtr->hwndSelf);

1584
    if (PtInRect(&infoPtr->rcThumb, clickPoint)) {
1585
        infoPtr->flags |= TB_DRAG_MODE;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1586
        SetCapture (infoPtr->hwndSelf);
1587 1588
	TRACKBAR_UpdateToolTip (infoPtr);
	TRACKBAR_ActivateToolTip (infoPtr, TRUE);
1589
	TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1590
    } else {
1591 1592 1593 1594 1595 1596
	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);
1597
    }
1598

Alexandre Julliard's avatar
Alexandre Julliard committed
1599 1600 1601
    return 0;
}

1602

Alexandre Julliard's avatar
Alexandre Julliard committed
1603
static LRESULT
1604
TRACKBAR_LButtonUp (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1605
{
1606
    if (infoPtr->flags & TB_DRAG_MODE) {
1607 1608
        notify_with_scroll (infoPtr, TB_THUMBPOSITION | (infoPtr->lPos<<16));
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1609 1610
        infoPtr->flags &= ~TB_DRAG_MODE;
        ReleaseCapture ();
1611
	notify(infoPtr, NM_RELEASEDCAPTURE);
1612
        TRACKBAR_ActivateToolTip(infoPtr, FALSE);
1613
	TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
1614 1615 1616 1617
    }
    if (infoPtr->flags & TB_AUTO_PAGE) {
	KillTimer (infoPtr->hwndSelf, TB_REFRESH_TIMER);
        infoPtr->flags &= ~TB_AUTO_PAGE;
1618
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1619
        ReleaseCapture ();
1620
	notify(infoPtr, NM_RELEASEDCAPTURE);
1621
    }
1622

Alexandre Julliard's avatar
Alexandre Julliard committed
1623 1624 1625
    return 0;
}

1626

Alexandre Julliard's avatar
Alexandre Julliard committed
1627
static LRESULT
1628
TRACKBAR_CaptureChanged (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1629
{
1630
    notify_with_scroll (infoPtr, TB_ENDTRACK);
1631
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1632
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1633

1634

Alexandre Julliard's avatar
Alexandre Julliard committed
1635
static LRESULT
1636
TRACKBAR_Paint (TRACKBAR_INFO *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1637
{
1638 1639 1640 1641 1642 1643 1644 1645
    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
1646 1647 1648 1649 1650 1651

    return 0;
}


static LRESULT
1652
TRACKBAR_SetFocus (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1653
{
1654
    TRACE("\n");
1655
    infoPtr->bFocussed = TRUE;
1656
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1657 1658 1659 1660 1661 1662

    return 0;
}


static LRESULT
1663
TRACKBAR_Size (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1664
{
1665 1666 1667 1668 1669 1670 1671
    if (infoPtr->dwStyle & TBS_FIXEDLENGTH)
    {
        TRACKBAR_CalcChannel(infoPtr);
        TRACKBAR_UpdateThumb(infoPtr);
    }
    else
        TRACKBAR_InitializeThumb(infoPtr);
1672
    TRACKBAR_AlignBuddies (infoPtr);
1673
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1674 1675 1676 1677

    return 0;
}

1678 1679 1680 1681 1682 1683 1684 1685 1686 1687
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
1688

1689
static LRESULT
1690
TRACKBAR_Timer (TRACKBAR_INFO *infoPtr)
1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701
{
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
	if (GetCursorPos(&pt))
	    if (ScreenToClient(infoPtr->hwndSelf, &pt))
		TRACKBAR_AutoPage(infoPtr, pt);
    }
    return 0;
}


1702
/* update theme after a WM_THEMECHANGED message */
1703
static LRESULT theme_changed (const TRACKBAR_INFO* infoPtr)
1704 1705 1706
{
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
    CloseThemeData (theme);
1707
    OpenThemeData (infoPtr->hwndSelf, themeClass);
1708 1709 1710 1711
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1712
static LRESULT
1713
TRACKBAR_MouseMove (TRACKBAR_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1714
{
1715
    INT clickPlace = (infoPtr->dwStyle & TBS_VERT) ? y : x;
1716
    LONG dragPos, oldPos = infoPtr->lPos;
1717

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

1720 1721
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
1722 1723
	pt.x = x;
	pt.y = y;
1724
	TRACKBAR_AutoPage (infoPtr, pt);
1725
	return TRUE;
1726 1727
    }

1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757
    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
1758

1759 1760
    dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace);

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1763
    infoPtr->lPos = dragPos;
1764
    TRACKBAR_UpdateThumb (infoPtr);
1765

1766
    notify_with_scroll (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16));
1767

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1768
    TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos);
1769
    UpdateWindow (infoPtr->hwndSelf);
Alex Priem's avatar
Alex Priem committed
1770

1771
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1772 1773
}

1774
static BOOL
1775
TRACKBAR_KeyDown (TRACKBAR_INFO *infoPtr, INT nVirtKey)
Alexandre Julliard's avatar
Alexandre Julliard committed
1776
{
1777 1778
    BOOL downIsLeft = infoPtr->dwStyle & TBS_DOWNISLEFT;
    BOOL vert = infoPtr->dwStyle & TBS_VERT;
1779
    LONG pos = infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1780

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

1783
    switch (nVirtKey) {
1784
    case VK_UP:
1785 1786 1787
	if (!vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
        else TRACKBAR_LineUp(infoPtr);
        break;
1788
    case VK_LEFT:
1789 1790
        if (vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
        else TRACKBAR_LineUp(infoPtr);
1791
        break;
1792
    case VK_DOWN:
1793 1794 1795
	if (!vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
        else TRACKBAR_LineDown(infoPtr);
        break;
1796
    case VK_RIGHT:
1797 1798
	if (vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
        else TRACKBAR_LineDown(infoPtr);
1799 1800
        break;
    case VK_NEXT:
1801 1802
	if (!vert && downIsLeft) TRACKBAR_PageUp(infoPtr);
        else TRACKBAR_PageDown(infoPtr);
1803 1804
        break;
    case VK_PRIOR:
1805 1806
	if (!vert && downIsLeft) TRACKBAR_PageDown(infoPtr);
        else TRACKBAR_PageUp(infoPtr);
1807
        break;
1808
    case VK_HOME:
1809 1810
        if (infoPtr->lPos == infoPtr->lRangeMin) return FALSE;
        infoPtr->lPos = infoPtr->lRangeMin;
1811
        notify_with_scroll (infoPtr, TB_TOP);
1812
        break;
1813
    case VK_END:
1814 1815
        if (infoPtr->lPos == infoPtr->lRangeMax) return FALSE;
        infoPtr->lPos = infoPtr->lRangeMax;
1816
        notify_with_scroll (infoPtr, TB_BOTTOM);
1817 1818
        break;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1819

1820
    if (pos != infoPtr->lPos) {
Alex Priem's avatar
Alex Priem committed
1821
	infoPtr->flags |=TB_THUMBPOSCHANGED;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1822
	TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos);
1823
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1824

1825
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1826 1827
}

1828

1829
static inline BOOL
1830
TRACKBAR_KeyUp (const TRACKBAR_INFO *infoPtr, INT nVirtKey)
Alexandre Julliard's avatar
Alexandre Julliard committed
1831
{
1832
    switch (nVirtKey) {
1833
    case VK_LEFT:
1834
    case VK_UP:
1835
    case VK_RIGHT:
1836
    case VK_DOWN:
1837 1838
    case VK_NEXT:
    case VK_PRIOR:
1839
    case VK_HOME:
1840
    case VK_END:
1841
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1842 1843
    }
    return TRUE;
Alex Priem's avatar
Alex Priem committed
1844 1845 1846
}


1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859
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;
}

1860
static LRESULT WINAPI
1861
TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1862
{
1863
    TRACKBAR_INFO *infoPtr = (TRACKBAR_INFO *)GetWindowLongPtrW (hwnd, 0);
1864

1865
    TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, uMsg, wParam, lParam);
1866 1867 1868 1869

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1870 1871
    switch (uMsg)
    {
1872
    case TBM_CLEARSEL:
1873
        return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1874

1875
    case TBM_CLEARTICS:
1876
        return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1877

1878
    case TBM_GETBUDDY:
1879
        return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB);
Alexandre Julliard's avatar
Alexandre Julliard committed
1880

1881
    case TBM_GETCHANNELRECT:
1882
        return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1883

1884
    case TBM_GETLINESIZE:
1885
        return infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1886

1887
    case TBM_GETNUMTICS:
1888
        return TRACKBAR_GetNumTics (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1889

1890
    case TBM_GETPAGESIZE:
1891
        return infoPtr->lPageSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1892

1893
    case TBM_GETPOS:
1894
        return infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1895

1896
    case TBM_GETPTICS:
1897
        return (LRESULT)infoPtr->tics;
Alexandre Julliard's avatar
Alexandre Julliard committed
1898

1899
    case TBM_GETRANGEMAX:
1900
        return infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1901

1902
    case TBM_GETRANGEMIN:
1903
        return infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1904

1905
    case TBM_GETSELEND:
1906
        return infoPtr->lSelMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1907

1908
    case TBM_GETSELSTART:
1909
        return infoPtr->lSelMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1910

1911
    case TBM_GETTHUMBLENGTH:
1912
        return infoPtr->uThumbLen;
Alexandre Julliard's avatar
Alexandre Julliard committed
1913

1914
    case TBM_GETTHUMBRECT:
1915
	return CopyRect((LPRECT)lParam, &infoPtr->rcThumb);
Alexandre Julliard's avatar
Alexandre Julliard committed
1916

Alexandre Julliard's avatar
Alexandre Julliard committed
1917
    case TBM_GETTIC:
1918
        return TRACKBAR_GetTic (infoPtr, (INT)wParam);
1919

Alexandre Julliard's avatar
Alexandre Julliard committed
1920
    case TBM_GETTICPOS:
1921
        return TRACKBAR_GetTicPos (infoPtr, (INT)wParam);
1922

1923
    case TBM_GETTOOLTIPS:
1924
        return (LRESULT)infoPtr->hwndToolTip;
Alexandre Julliard's avatar
Alexandre Julliard committed
1925

1926
    case TBM_GETUNICODEFORMAT:
1927
        return infoPtr->bUnicode;
Alexandre Julliard's avatar
Alexandre Julliard committed
1928

1929
    case TBM_SETBUDDY:
1930
        return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1931

1932
    case TBM_SETLINESIZE:
1933
        return TRACKBAR_SetLineSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1934

1935
    case TBM_SETPAGESIZE:
1936
        return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1937

1938
    case TBM_SETPOS:
1939
        return TRACKBAR_SetPos (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1940

1941
    case TBM_SETRANGE:
1942
        return TRACKBAR_SetRange (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1943

1944
    case TBM_SETRANGEMAX:
1945
        return TRACKBAR_SetRangeMax (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1946

1947
    case TBM_SETRANGEMIN:
1948
        return TRACKBAR_SetRangeMin (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1949

1950
    case TBM_SETSEL:
1951
        return TRACKBAR_SetSel (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1952

1953
    case TBM_SETSELEND:
1954
        return TRACKBAR_SetSelEnd (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1955

1956
    case TBM_SETSELSTART:
1957
        return TRACKBAR_SetSelStart (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1958

1959
    case TBM_SETTHUMBLENGTH:
1960
        return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1961

1962
    case TBM_SETTIC:
1963
        return TRACKBAR_SetTic (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1964

Alexandre Julliard's avatar
Alexandre Julliard committed
1965
    case TBM_SETTICFREQ:
1966
        return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1967

1968
    case TBM_SETTIPSIDE:
1969
        return TRACKBAR_SetTipSide (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1970

1971
    case TBM_SETTOOLTIPS:
1972
        return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1973

1974 1975
    case TBM_SETUNICODEFORMAT:
	return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1976 1977


1978
    case WM_CAPTURECHANGED:
1979
        return TRACKBAR_CaptureChanged (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1980

1981
    case WM_CREATE:
1982
        return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1983

1984
    case WM_DESTROY:
1985
        return TRACKBAR_Destroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1986

1987 1988
    case WM_ENABLE:
        return TRACKBAR_Enable (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1989

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1990
    case WM_ERASEBKGND:
1991
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1992

1993 1994
    case WM_GETDLGCODE:
        return DLGC_WANTARROWS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1995

1996
    case WM_KEYDOWN:
1997
        return TRACKBAR_KeyDown (infoPtr, (INT)wParam);
1998

1999
    case WM_KEYUP:
2000
        return TRACKBAR_KeyUp (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2001

2002
    case WM_KILLFOCUS:
2003
        return TRACKBAR_KillFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2004

2005
    case WM_LBUTTONDOWN:
2006
        return TRACKBAR_LButtonDown (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2007

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

2011 2012 2013 2014 2015
    case WM_MOUSELEAVE:
        infoPtr->flags &= ~TB_THUMB_HOT; 
        InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
        return 0;
    
2016
    case WM_MOUSEMOVE:
2017
        return TRACKBAR_MouseMove (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2018

2019
    case WM_PRINTCLIENT:
2020
    case WM_PAINT:
2021
        return TRACKBAR_Paint (infoPtr, (HDC)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2022

2023
    case WM_SETFOCUS:
2024
        return TRACKBAR_SetFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2025

2026
    case WM_SIZE:
2027
        return TRACKBAR_Size (infoPtr);
2028 2029 2030

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

2032 2033 2034
    case WM_THEMECHANGED:
        return theme_changed (infoPtr);

2035
    case WM_TIMER:
2036
	return TRACKBAR_Timer (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2037

2038
    case WM_WININICHANGE:
2039
        return TRACKBAR_InitializeThumb (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2040

2041
    default:
2042
        if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
2043
            ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);
2044
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2045 2046 2047 2048
    }
}


2049
void TRACKBAR_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2050
{
2051
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
2052

2053
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
2054
    wndClass.style         = CS_GLOBALCLASS;
2055
    wndClass.lpfnWndProc   = TRACKBAR_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
2056 2057
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(TRACKBAR_INFO *);
2058
    wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
2059
    wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
2060
    wndClass.lpszClassName = TRACKBAR_CLASSW;
2061

2062
    RegisterClassW (&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
2063
}
2064 2065


2066
void TRACKBAR_Unregister (void)
2067
{
2068
    UnregisterClassW (TRACKBAR_CLASSW, NULL);
2069
}