trackbar.c 57 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
    TRACE("  <= %Id\n", result);
122 123 124 125

    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=%ld\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
    HBRUSH brush;
903

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

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

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

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

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

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

Alexandre Julliard's avatar
Alexandre Julliard committed
967 968

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

998
    /* draw focus rectangle */
999
    if (infoPtr->flags & TB_IS_FOCUSED) {
1000 1001 1002
	DrawFocusRect(hdc, &rcClient);
    }

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


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

1025
    GetWindowRect (infoPtr->hwndSelf, &rcSelf);
1026
    MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcSelf, 2);
Alexandre Julliard's avatar
Alexandre Julliard committed
1027 1028 1029

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

1033
	if (infoPtr->dwStyle & TBS_VERT) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
	    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;
	}

1044
	SetWindowPos (infoPtr->hwndBuddyLA, 0, x, y, 0, 0,
1045
                      SWP_NOZORDER | SWP_NOSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
1046 1047 1048 1049 1050
    }


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

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


static LRESULT
1071
TRACKBAR_ClearSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
1072
{
1073 1074
    infoPtr->lSelMin = 0;
    infoPtr->lSelMax = 0;
1075
    infoPtr->flags |= TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1076

1077
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1078 1079 1080 1081 1082 1083

    return 0;
}


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

1092
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1093 1094 1095 1096 1097

    return 0;
}


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

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

    return 0;
}


1112
static inline LONG
1113
TRACKBAR_GetNumTics (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1114
{
1115
    if (infoPtr->dwStyle & TBS_NOTICKS) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1116

1117
    return infoPtr->uNumTics + 2;
Alexandre Julliard's avatar
Alexandre Julliard committed
1118 1119 1120
}


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

    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1131

1132
static inline LONG
1133
TRACKBAR_GetTic (const TRACKBAR_INFO *infoPtr, INT iTic)
Alexandre Julliard's avatar
Alexandre Julliard committed
1134
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1135
    if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics)
Alexandre Julliard's avatar
Alexandre Julliard committed
1136 1137
	return -1;

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1138
    qsort(infoPtr->tics, infoPtr->uNumTics, sizeof(DWORD), comp_tics);
1139
    return infoPtr->tics[iTic];
Alexandre Julliard's avatar
Alexandre Julliard committed
1140 1141 1142
}


1143
static inline LONG
1144
TRACKBAR_GetTicPos (const TRACKBAR_INFO *infoPtr, INT iTic)
Alexandre Julliard's avatar
Alexandre Julliard committed
1145
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1146
    LONG range, width, pos, tic;
1147
    int offsetthumb;
Alexandre Julliard's avatar
Alexandre Julliard committed
1148

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1152
    tic   = TRACKBAR_GetTic (infoPtr, iTic);
1153
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
1154
    if (range <= 0) range = 1;
1155 1156 1157
    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
1158

1159
    return pos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1160 1161
}

1162

1163 1164
static HWND
TRACKBAR_SetBuddy (TRACKBAR_INFO *infoPtr, BOOL fLocation, HWND hwndBuddy)
Alexandre Julliard's avatar
Alexandre Julliard committed
1165
{
1166
    HWND hwndTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1167

1168
    if (fLocation) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1169 1170
	/* buddy is left or above */
	hwndTemp = infoPtr->hwndBuddyLA;
1171
	infoPtr->hwndBuddyLA = hwndBuddy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1172 1173
    }
    else {
1174 1175
        /* buddy is right or below */
        hwndTemp = infoPtr->hwndBuddyRB;
1176
        infoPtr->hwndBuddyRB = hwndBuddy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1177 1178
    }

1179
    TRACKBAR_AlignBuddies (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1180

1181
    return hwndTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1182 1183 1184
}


1185
static inline LONG
1186
TRACKBAR_SetLineSize (TRACKBAR_INFO *infoPtr, LONG lLineSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1187
{
1188
    LONG lTemp = infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1189

1190
    infoPtr->lLineSize = lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1191

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

1195 1196 1197 1198 1199 1200 1201 1202
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
1203

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

1209 1210 1211 1212 1213
    if (lPageSize == -1)
    {
        infoPtr->flags &= ~TB_USER_PAGE;
        TRACKBAR_UpdatePageSize(infoPtr);
    }
1214
    else
1215 1216 1217 1218
    {
        infoPtr->flags |= TB_USER_PAGE;
        infoPtr->lPageSize = lPageSize;
    }
1219

1220
    return lTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1221 1222 1223
}


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

1230 1231
    if (infoPtr->lPos < infoPtr->lRangeMin)
	infoPtr->lPos = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1232

1233 1234
    if (infoPtr->lPos > infoPtr->lRangeMax)
	infoPtr->lPos = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1235

1236 1237 1238 1239 1240
    if (fPosition && oldPos != lPosition)
    {
        TRACKBAR_UpdateThumb(infoPtr);
        TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition);
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1241 1242 1243 1244

    return 0;
}

1245
static inline LRESULT
1246
TRACKBAR_SetRange (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG range)
Alexandre Julliard's avatar
Alexandre Julliard committed
1247
{
1248 1249 1250 1251 1252
    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
1253

1254 1255
    /* clip position to new min/max limit */
    if (infoPtr->lPos < infoPtr->lRangeMin)
1256
        infoPtr->lPos = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1257

1258
    if (infoPtr->lPos > infoPtr->lRangeMax)
1259
        infoPtr->lPos = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1260

1261
    TRACKBAR_UpdatePageSize(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1262

1263 1264 1265 1266 1267
    if (changed) {
        if (infoPtr->dwStyle & TBS_AUTOTICKS)
            TRACKBAR_RecalculateTics (infoPtr);
        infoPtr->flags |= TB_THUMBPOSCHANGED;
    }
1268 1269

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1270 1271 1272 1273 1274

    return 0;
}


1275
static inline LRESULT
1276
TRACKBAR_SetRangeMax (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG lMax)
Alexandre Julliard's avatar
Alexandre Julliard committed
1277
{
1278
    BOOL changed = infoPtr->lRangeMax != lMax;
1279
    LONG rightmost = max(lMax, infoPtr->lRangeMin);
1280

1281
    infoPtr->lRangeMax = lMax;
1282 1283
    if (infoPtr->lPos > rightmost) {
        infoPtr->lPos = rightmost;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1284
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1285
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1286

1287
    TRACKBAR_UpdatePageSize(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1288

1289 1290 1291 1292
    if (changed && (infoPtr->dwStyle & TBS_AUTOTICKS))
        TRACKBAR_RecalculateTics (infoPtr);

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1293 1294 1295 1296 1297

    return 0;
}


1298
static inline LRESULT
1299
TRACKBAR_SetRangeMin (TRACKBAR_INFO *infoPtr, BOOL redraw, LONG lMin)
Alexandre Julliard's avatar
Alexandre Julliard committed
1300
{
1301 1302
    BOOL changed = infoPtr->lRangeMin != lMin;

1303 1304 1305
    infoPtr->lRangeMin = lMin;
    if (infoPtr->lPos < infoPtr->lRangeMin) {
        infoPtr->lPos = infoPtr->lRangeMin;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1306
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1307
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1308

1309
    TRACKBAR_UpdatePageSize(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1310

1311 1312 1313 1314
    if (changed && (infoPtr->dwStyle & TBS_AUTOTICKS))
        TRACKBAR_RecalculateTics (infoPtr);

    if (redraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1315 1316 1317 1318

    return 0;
}

1319

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

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

1333 1334 1335 1336
    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
1337

1338
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1339 1340 1341 1342 1343

    return 0;
}


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

1352
    infoPtr->lSelMax = lEnd;
1353
    infoPtr->flags |= TB_SELECTIONCHANGED;
1354

1355 1356
    if (infoPtr->lSelMax > infoPtr->lRangeMax)
        infoPtr->lSelMax = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1357

1358
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1359 1360 1361 1362 1363

    return 0;
}


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

1372
    infoPtr->lSelMin = lStart;
1373
    infoPtr->flags  |=TB_SELECTIONCHANGED;
1374

1375 1376
    if (infoPtr->lSelMin < infoPtr->lRangeMin)
        infoPtr->lSelMin = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1377

1378
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1379 1380 1381 1382 1383

    return 0;
}


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

Alexandre Julliard's avatar
Alexandre Julliard committed
1395 1396 1397 1398
    return 0;
}


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

1405
    TRACE("position %ld\n", lPos);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1406

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

1417
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1418 1419 1420 1421 1422

    return TRUE;
}


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

1432
    TRACKBAR_UpdateThumb (infoPtr);
1433 1434 1435 1436
    return 0;
}


1437
static inline INT
1438
TRACKBAR_SetTipSide (TRACKBAR_INFO *infoPtr, INT fLocation)
Alexandre Julliard's avatar
Alexandre Julliard committed
1439
{
1440
    INT fTemp = infoPtr->fLocation;
Alexandre Julliard's avatar
Alexandre Julliard committed
1441

1442
    infoPtr->fLocation = fLocation;
1443

Alexandre Julliard's avatar
Alexandre Julliard committed
1444 1445 1446 1447
    return fTemp;
}


1448
static inline LRESULT
1449
TRACKBAR_SetToolTips (TRACKBAR_INFO *infoPtr, HWND hwndTT)
Alexandre Julliard's avatar
Alexandre Julliard committed
1450
{
1451
    infoPtr->hwndToolTip = hwndTT;
Alexandre Julliard's avatar
Alexandre Julliard committed
1452 1453 1454 1455 1456

    return 0;
}


1457
static inline BOOL
1458 1459 1460 1461 1462 1463 1464 1465
TRACKBAR_SetUnicodeFormat (TRACKBAR_INFO *infoPtr, BOOL fUnicode)
{
    BOOL bTemp = infoPtr->bUnicode;

    infoPtr->bUnicode = fUnicode;

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

1467 1468 1469 1470
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
1471

Alexandre Julliard's avatar
Alexandre Julliard committed
1472
static LRESULT
1473
TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1474
{
1475
    int client_size;
1476
    RECT rect;
1477

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

1480 1481 1482 1483 1484 1485 1486
    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;
1487

1488 1489 1490 1491
        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
1492

1493
    TRACKBAR_CalcChannel (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1494
    TRACKBAR_UpdateThumb (infoPtr);
1495
    infoPtr->flags &= ~TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1496

1497
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1498
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1499

1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512
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
1513 1514

static LRESULT
1515
TRACKBAR_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
1516 1517 1518
{
    TRACKBAR_INFO *infoPtr;

1519
    infoPtr = Alloc (sizeof(TRACKBAR_INFO));
1520
    if (!infoPtr) return -1;
1521
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1522

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

1539
    TRACKBAR_InitializeThumb (infoPtr);
Alex Priem's avatar
Alex Priem committed
1540

1541
    /* Create tooltip control */
1542
    if (infoPtr->dwStyle & TBS_TOOLTIPS) {
Alex Priem's avatar
Alex Priem committed
1543 1544

    	infoPtr->hwndToolTip =
1545
            CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1546 1547 1548
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             hwnd, 0, 0, 0);
Alex Priem's avatar
Alex Priem committed
1549

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

1559 1560
            SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
	 }
1561
    }
1562 1563
    
    OpenThemeData (hwnd, themeClass);
1564

Alexandre Julliard's avatar
Alexandre Julliard committed
1565 1566 1567 1568 1569
    return 0;
}


static LRESULT
1570
TRACKBAR_Destroy (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1571
{
1572
    /* delete tooltip control */
Alex Priem's avatar
Alex Priem committed
1573
    if (infoPtr->hwndToolTip)
1574
    	DestroyWindow (infoPtr->hwndToolTip);
Alex Priem's avatar
Alex Priem committed
1575

1576 1577 1578
    Free (infoPtr->tics);
    infoPtr->tics = NULL;

1579
    SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
1580
    CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
1581 1582
    Free (infoPtr);

Alexandre Julliard's avatar
Alexandre Julliard committed
1583 1584 1585 1586 1587
    return 0;
}


static LRESULT
1588
TRACKBAR_KillFocus (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1589
{
1590
    TRACE("\n");
1591
    infoPtr->flags &= ~TB_IS_FOCUSED;
1592
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1593 1594 1595 1596 1597

    return 0;
}

static LRESULT
1598
TRACKBAR_LButtonDown (TRACKBAR_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1599
{
1600 1601 1602 1603
    POINT clickPoint;

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

1605 1606
    SetFocus(infoPtr->hwndSelf);

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

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

1625

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1646 1647 1648
    return 0;
}

1649

Alexandre Julliard's avatar
Alexandre Julliard committed
1650
static LRESULT
1651
TRACKBAR_CaptureChanged (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1652
{
1653
    notify_with_scroll (infoPtr, TB_ENDTRACK);
1654
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1655
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1656

1657

Alexandre Julliard's avatar
Alexandre Julliard committed
1658
static LRESULT
1659
TRACKBAR_Paint (TRACKBAR_INFO *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1660
{
1661 1662 1663 1664 1665 1666 1667 1668
    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
1669 1670 1671 1672 1673 1674

    return 0;
}


static LRESULT
1675
TRACKBAR_SetFocus (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1676
{
1677
    TRACE("\n");
1678
    infoPtr->flags |= TB_IS_FOCUSED;
1679
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1680 1681 1682 1683 1684 1685

    return 0;
}


static LRESULT
1686
TRACKBAR_Size (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1687
{
1688
    TRACKBAR_RecalculateAll(infoPtr);
1689
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1690 1691 1692 1693

    return 0;
}

1694 1695 1696 1697 1698 1699 1700
static LRESULT
TRACKBAR_StyleChanged (TRACKBAR_INFO *infoPtr, WPARAM wStyleType,
                       const STYLESTRUCT *lpss)
{
    if (wStyleType != GWL_STYLE) return 0;

    infoPtr->dwStyle = lpss->styleNew;
1701 1702
    TRACKBAR_RecalculateAll(infoPtr);
    TRACKBAR_InvalidateAll(infoPtr);
1703 1704
    return 0;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1705

1706
static LRESULT
1707
TRACKBAR_Timer (TRACKBAR_INFO *infoPtr)
1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718
{
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
	if (GetCursorPos(&pt))
	    if (ScreenToClient(infoPtr->hwndSelf, &pt))
		TRACKBAR_AutoPage(infoPtr, pt);
    }
    return 0;
}


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


Alexandre Julliard's avatar
Alexandre Julliard committed
1730
static LRESULT
1731
TRACKBAR_MouseMove (TRACKBAR_INFO *infoPtr, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1732
{
1733
    INT clickPlace = (infoPtr->dwStyle & TBS_VERT) ? y : x;
1734
    LONG dragPos, oldPos = infoPtr->lPos;
1735

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

1738 1739
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
1740 1741
	pt.x = x;
	pt.y = y;
1742
	TRACKBAR_AutoPage (infoPtr, pt);
1743
	return TRUE;
1744 1745
    }

1746 1747 1748 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
    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
1776

1777 1778
    dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace);

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1781
    infoPtr->lPos = dragPos;
1782
    TRACKBAR_UpdateThumb (infoPtr);
1783

1784
    notify_with_scroll (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16));
1785

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1786
    TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos);
1787
    UpdateWindow (infoPtr->hwndSelf);
Alex Priem's avatar
Alex Priem committed
1788

1789
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1790 1791
}

1792
static BOOL
1793
TRACKBAR_KeyDown (TRACKBAR_INFO *infoPtr, INT nVirtKey)
Alexandre Julliard's avatar
Alexandre Julliard committed
1794
{
1795 1796
    BOOL downIsLeft = infoPtr->dwStyle & TBS_DOWNISLEFT;
    BOOL vert = infoPtr->dwStyle & TBS_VERT;
1797
    LONG pos = infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1798

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

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

1838
    if (pos != infoPtr->lPos) {
1839
	TRACKBAR_UpdateThumb (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1840
	TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos);
1841
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1842

1843
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1844 1845
}

1846

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


1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877
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;
}

1878
static LRESULT WINAPI
1879
TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1880
{
1881
    TRACKBAR_INFO *infoPtr = (TRACKBAR_INFO *)GetWindowLongPtrW (hwnd, 0);
1882

1883
    TRACE("hwnd %p, msg %x, wparam %Ix, lparam %Ix\n", hwnd, uMsg, wParam, lParam);
1884 1885 1886 1887

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1888 1889
    switch (uMsg)
    {
1890
    case TBM_CLEARSEL:
1891
        return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1892

1893
    case TBM_CLEARTICS:
1894
        return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1895

1896
    case TBM_GETBUDDY:
1897
        return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB);
Alexandre Julliard's avatar
Alexandre Julliard committed
1898

1899
    case TBM_GETCHANNELRECT:
1900
        return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1901

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

1905
    case TBM_GETNUMTICS:
1906
        return TRACKBAR_GetNumTics (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1907

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

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

1914
    case TBM_GETPTICS:
1915
        return (LRESULT)infoPtr->tics;
Alexandre Julliard's avatar
Alexandre Julliard committed
1916

1917
    case TBM_GETRANGEMAX:
1918
        return infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1919

1920
    case TBM_GETRANGEMIN:
1921
        return infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1922

1923
    case TBM_GETSELEND:
1924
        return infoPtr->lSelMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1925

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

1929
    case TBM_GETTHUMBLENGTH:
1930
        return infoPtr->uThumbLen;
Alexandre Julliard's avatar
Alexandre Julliard committed
1931

1932
    case TBM_GETTHUMBRECT:
1933
	return CopyRect((LPRECT)lParam, &infoPtr->rcThumb);
Alexandre Julliard's avatar
Alexandre Julliard committed
1934

Alexandre Julliard's avatar
Alexandre Julliard committed
1935
    case TBM_GETTIC:
1936
        return TRACKBAR_GetTic (infoPtr, (INT)wParam);
1937

Alexandre Julliard's avatar
Alexandre Julliard committed
1938
    case TBM_GETTICPOS:
1939
        return TRACKBAR_GetTicPos (infoPtr, (INT)wParam);
1940

1941
    case TBM_GETTOOLTIPS:
1942
        return (LRESULT)infoPtr->hwndToolTip;
Alexandre Julliard's avatar
Alexandre Julliard committed
1943

1944
    case TBM_GETUNICODEFORMAT:
1945
        return infoPtr->bUnicode;
Alexandre Julliard's avatar
Alexandre Julliard committed
1946

1947
    case TBM_SETBUDDY:
1948
        return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1949

1950
    case TBM_SETLINESIZE:
1951
        return TRACKBAR_SetLineSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1952

1953
    case TBM_SETPAGESIZE:
1954
        return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1955

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

1959
    case TBM_SETRANGE:
1960
        return TRACKBAR_SetRange (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1961

1962
    case TBM_SETRANGEMAX:
1963
        return TRACKBAR_SetRangeMax (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1964

1965
    case TBM_SETRANGEMIN:
1966
        return TRACKBAR_SetRangeMin (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1967

1968
    case TBM_SETSEL:
1969
        return TRACKBAR_SetSel (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1970

1971
    case TBM_SETSELEND:
1972
        return TRACKBAR_SetSelEnd (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1973

1974
    case TBM_SETSELSTART:
1975
        return TRACKBAR_SetSelStart (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1976

1977
    case TBM_SETTHUMBLENGTH:
1978
        return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1979

1980
    case TBM_SETTIC:
1981
        return TRACKBAR_SetTic (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1982

Alexandre Julliard's avatar
Alexandre Julliard committed
1983
    case TBM_SETTICFREQ:
1984
        return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1985

1986
    case TBM_SETTIPSIDE:
1987
        return TRACKBAR_SetTipSide (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1988

1989
    case TBM_SETTOOLTIPS:
1990
        return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1991

1992 1993
    case TBM_SETUNICODEFORMAT:
	return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1994 1995


1996
    case WM_CAPTURECHANGED:
1997
        if (hwnd == (HWND)lParam) return 0;
1998
        return TRACKBAR_CaptureChanged (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1999

2000
    case WM_CREATE:
2001
        return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2002

2003
    case WM_DESTROY:
2004
        return TRACKBAR_Destroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2005

2006 2007
    case WM_ENABLE:
        return TRACKBAR_Enable (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2008

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
2009
    case WM_ERASEBKGND:
2010
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
2011

2012 2013
    case WM_GETDLGCODE:
        return DLGC_WANTARROWS;
Alexandre Julliard's avatar
Alexandre Julliard committed
2014

2015
    case WM_KEYDOWN:
2016
        return TRACKBAR_KeyDown (infoPtr, (INT)wParam);
2017

2018
    case WM_KEYUP:
2019
        return TRACKBAR_KeyUp (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2020

2021
    case WM_KILLFOCUS:
2022
        return TRACKBAR_KillFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2023

2024
    case WM_LBUTTONDOWN:
2025
        return TRACKBAR_LButtonDown (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2026

2027
    case WM_LBUTTONUP:
2028
        return TRACKBAR_LButtonUp (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2029

2030 2031 2032 2033 2034
    case WM_MOUSELEAVE:
        infoPtr->flags &= ~TB_THUMB_HOT; 
        InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
        return 0;
    
2035
    case WM_MOUSEMOVE:
2036
        return TRACKBAR_MouseMove (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2037

2038
    case WM_PRINTCLIENT:
2039
    case WM_PAINT:
2040
        return TRACKBAR_Paint (infoPtr, (HDC)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2041

2042
    case WM_SETFOCUS:
2043
        return TRACKBAR_SetFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2044

2045
    case WM_SIZE:
2046
        return TRACKBAR_Size (infoPtr);
2047 2048 2049

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

2051 2052 2053
    case WM_THEMECHANGED:
        return theme_changed (infoPtr);

2054
    case WM_TIMER:
2055
	return TRACKBAR_Timer (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2056

2057
    case WM_WININICHANGE:
2058
        return TRACKBAR_InitializeThumb (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2059

2060
    default:
2061
        if ((uMsg >= WM_USER) && (uMsg < WM_APP) && !COMCTL32_IsReflectedMessage(uMsg))
2062
            ERR("unknown msg %04x, wp %Ix, lp %Ix\n", uMsg, wParam, lParam);
2063
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2064 2065 2066 2067
    }
}


2068
void TRACKBAR_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2069
{
2070
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
2071

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

2081
    RegisterClassW (&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
2082
}
2083 2084


2085
void TRACKBAR_Unregister (void)
2086
{
2087
    UnregisterClassW (TRACKBAR_CLASSW, NULL);
2088
}