trackbar.c 56.7 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>
37
#include <math.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
38

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

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

51
WINE_DEFAULT_DEBUG_CHANNEL(trackbar);
52

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

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

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

86 87
#define TB_DEFAULTPAGESIZE	20

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

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

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

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

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

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

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

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

    return result;
}

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

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

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

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

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

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

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
177 178 179 180
    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
181

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

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

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

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


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

217
    if (infoPtr->dwStyle & TBS_VERT) {
218 219 220 221 222 223 224 225 226 227 228 229 230 231
	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))
    {
232
	int clickPlace = (infoPtr->dwStyle & TBS_VERT) ? clickPoint.y : clickPoint.x;
233

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

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

    return 0;
}

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

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

Alex Priem's avatar
Alex Priem committed
253

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

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

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

274
static inline void TRACKBAR_LineDown(TRACKBAR_INFO *infoPtr)
275 276 277 278 279 280
{
    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);
281 282
}

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

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

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

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

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

346
    if (!range) range = 1;
347

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    if (dir > 0 && (infoPtr->flags & TB_AUTO_PAGE_RIGHT))
	TRACKBAR_PageDown(infoPtr);
457 458
    else if (dir < 0 && (infoPtr->flags & TB_AUTO_PAGE_LEFT))
	TRACKBAR_PageUp(infoPtr);
459 460
    else return FALSE;

461
    TRACKBAR_UpdateThumb (infoPtr);
462 463 464 465 466
    TRACKBAR_InvalidateThumbMove (infoPtr, prevPos, infoPtr->lPos);

    return TRUE;
}

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

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

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

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

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

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

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

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

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

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


563
static inline void
564
TRACKBAR_DrawTic (const TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags)
Alex Priem's avatar
Alex Priem committed
565
{
566
    if ((flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH))
567
        TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags | TBS_LEFT);
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);
571 572 573
}

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

598
    if ((infoPtr->dwStyle & TBS_ENABLESELRANGE) && TRACKBAR_HasSelection(infoPtr)) {
599 600 601 602 603 604 605 606 607 608 609
        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
610 611
}

612 613 614 615
static int
TRACKBAR_FillThumb (const TRACKBAR_INFO *infoPtr, HDC hdc, HBRUSH hbrush)
{
    const RECT *thumb = &infoPtr->rcThumb;
616
    POINT points[6];
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 690 691 692 693 694 695 696
    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);
697
    Polygon(hdc, points, sizeof(points) / sizeof(points[0]));
698 699 700 701 702
    SelectObject(hdc, oldbr);

    return PointDepth;
}

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

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

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

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

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

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

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

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


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

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

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

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

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


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

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

917
    if (infoPtr->flags & TB_DRAG_MODE)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
918 919
        TRACKBAR_UpdateToolTip (infoPtr);

920 921
    infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED);

922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937
    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;
    }

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

944 945
    /* start the paint cycle */
    nmcd.rc = rcClient;
946
    gcdrf = notify_customdraw(infoPtr, &nmcd, CDDS_PREPAINT);
947 948
    if (gcdrf & CDRF_SKIPDEFAULT) goto cleanup;
    
949
    /* Erase background */
950
    if (gcdrf == CDRF_DODEFAULT ||
951
        notify_customdraw(infoPtr, &nmcd, CDDS_PREERASE) != CDRF_SKIPDEFAULT) {
952
        if (GetWindowTheme (infoPtr->hwndSelf)) {
953
            DrawThemeParentBackground (infoPtr->hwndSelf, hdc, 0);
954
        }
955 956 957 958 959
        else {
            HBRUSH brush = (HBRUSH)SendMessageW(infoPtr->hwndNotify, WM_CTLCOLORSTATIC,
                    (WPARAM)hdc, (LPARAM)infoPtr->hwndSelf);
            FillRect (hdc, &rcClient, brush ? brush : 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;
Alexandre Julliard's avatar
Alexandre Julliard committed
1232

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

    return 0;
}


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

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

1256
    if (infoPtr->lPos > infoPtr->lRangeMax)
1257
        infoPtr->lPos = infoPtr->lRangeMax;
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 1266
    if (changed) {
        if (infoPtr->dwStyle & TBS_AUTOTICKS)
            TRACKBAR_RecalculateTics (infoPtr);
        infoPtr->flags |= TB_THUMBPOSCHANGED;
    }
1267 1268

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

    return 0;
}


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

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

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

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

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

    return 0;
}


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

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1308 1309
    infoPtr->lPageSize = (infoPtr->lRangeMax - infoPtr->lRangeMin) / 5;
    if (infoPtr->lPageSize == 0) infoPtr->lPageSize = 1;
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("lPos=%d\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 1433 1434 1435

    return 0;
}


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

1441
    infoPtr->fLocation = fLocation;
1442

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


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

    return 0;
}


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

    infoPtr->bUnicode = fUnicode;

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


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

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

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

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


static LRESULT
1495
TRACKBAR_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
1496 1497 1498
{
    TRACKBAR_INFO *infoPtr;

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

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

1519
    TRACKBAR_InitializeThumb (infoPtr);
Alex Priem's avatar
Alex Priem committed
1520

1521
    /* Create tooltip control */
1522
    if (infoPtr->dwStyle & TBS_TOOLTIPS) {
Alex Priem's avatar
Alex Priem committed
1523 1524

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

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

1539 1540
            SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
	 }
1541
    }
1542 1543
    
    OpenThemeData (hwnd, themeClass);
1544

Alexandre Julliard's avatar
Alexandre Julliard committed
1545 1546 1547 1548 1549
    return 0;
}


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

1556 1557 1558
    Free (infoPtr->tics);
    infoPtr->tics = NULL;

1559
    SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
1560
    CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
1561 1562
    Free (infoPtr);

Alexandre Julliard's avatar
Alexandre Julliard committed
1563 1564 1565 1566 1567
    return 0;
}


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

    return 0;
}

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

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

1585 1586
    SetFocus(infoPtr->hwndSelf);

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1602 1603 1604
    return 0;
}

1605

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

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

1629

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

1637

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

    return 0;
}


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

    return 0;
}


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

    return 0;
}

1681 1682 1683 1684 1685 1686 1687 1688 1689 1690
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
1691

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


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


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

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

1723 1724
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
1725 1726
	pt.x = x;
	pt.y = y;
1727
	TRACKBAR_AutoPage (infoPtr, pt);
1728
	return TRUE;
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 1758 1759 1760
    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
1761

1762 1763
    dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace);

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1766
    infoPtr->lPos = dragPos;
1767
    TRACKBAR_UpdateThumb (infoPtr);
1768

1769
    notify_with_scroll (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16));
1770

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1771
    TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos);
1772
    UpdateWindow (infoPtr->hwndSelf);
Alex Priem's avatar
Alex Priem committed
1773

1774
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1775 1776
}

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

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

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

1823
    if (pos != infoPtr->lPos) {
1824
	TRACKBAR_UpdateThumb (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1825
	TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos);
1826
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1827

1828
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1829 1830
}

1831

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


1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862
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;
}

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

1868
    TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, uMsg, wParam, lParam);
1869 1870 1871 1872

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1873 1874
    switch (uMsg)
    {
1875
    case TBM_CLEARSEL:
1876
        return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1877

1878
    case TBM_CLEARTICS:
1879
        return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1880

1881
    case TBM_GETBUDDY:
1882
        return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB);
Alexandre Julliard's avatar
Alexandre Julliard committed
1883

1884
    case TBM_GETCHANNELRECT:
1885
        return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1886

1887
    case TBM_GETLINESIZE:
1888
        return infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1889

1890
    case TBM_GETNUMTICS:
1891
        return TRACKBAR_GetNumTics (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1892

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

1896
    case TBM_GETPOS:
1897
        return infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1898

1899
    case TBM_GETPTICS:
1900
        return (LRESULT)infoPtr->tics;
Alexandre Julliard's avatar
Alexandre Julliard committed
1901

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

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

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

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

1914
    case TBM_GETTHUMBLENGTH:
1915
        return infoPtr->uThumbLen;
Alexandre Julliard's avatar
Alexandre Julliard committed
1916

1917
    case TBM_GETTHUMBRECT:
1918
	return CopyRect((LPRECT)lParam, &infoPtr->rcThumb);
Alexandre Julliard's avatar
Alexandre Julliard committed
1919

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1923
    case TBM_GETTICPOS:
1924
        return TRACKBAR_GetTicPos (infoPtr, (INT)wParam);
1925

1926
    case TBM_GETTOOLTIPS:
1927
        return (LRESULT)infoPtr->hwndToolTip;
Alexandre Julliard's avatar
Alexandre Julliard committed
1928

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

1932
    case TBM_SETBUDDY:
1933
        return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1934

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

1938
    case TBM_SETPAGESIZE:
1939
        return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1940

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

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

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

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

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

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

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

1962
    case TBM_SETTHUMBLENGTH:
1963
        return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1964

1965
    case TBM_SETTIC:
1966
        return TRACKBAR_SetTic (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1967

Alexandre Julliard's avatar
Alexandre Julliard committed
1968
    case TBM_SETTICFREQ:
1969
        return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1970

1971
    case TBM_SETTIPSIDE:
1972
        return TRACKBAR_SetTipSide (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1973

1974
    case TBM_SETTOOLTIPS:
1975
        return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1976

1977 1978
    case TBM_SETUNICODEFORMAT:
	return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1979 1980


1981
    case WM_CAPTURECHANGED:
1982
        if (hwnd == (HWND)lParam) return 0;
1983
        return TRACKBAR_CaptureChanged (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1984

1985
    case WM_CREATE:
1986
        return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1987

1988
    case WM_DESTROY:
1989
        return TRACKBAR_Destroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1990

1991 1992
    case WM_ENABLE:
        return TRACKBAR_Enable (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1993

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1994
    case WM_ERASEBKGND:
1995
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1996

1997 1998
    case WM_GETDLGCODE:
        return DLGC_WANTARROWS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1999

2000
    case WM_KEYDOWN:
2001
        return TRACKBAR_KeyDown (infoPtr, (INT)wParam);
2002

2003
    case WM_KEYUP:
2004
        return TRACKBAR_KeyUp (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2005

2006
    case WM_KILLFOCUS:
2007
        return TRACKBAR_KillFocus (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2008

2009
    case WM_LBUTTONDOWN:
2010
        return TRACKBAR_LButtonDown (infoPtr, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
2011

2012
    case WM_LBUTTONUP:
2013
        return TRACKBAR_LButtonUp (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2014

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

2023
    case WM_PRINTCLIENT:
2024
    case WM_PAINT:
2025
        return TRACKBAR_Paint (infoPtr, (HDC)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
2026

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

2030
    case WM_SIZE:
2031
        return TRACKBAR_Size (infoPtr);
2032 2033 2034

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

2036 2037 2038
    case WM_THEMECHANGED:
        return theme_changed (infoPtr);

2039
    case WM_TIMER:
2040
	return TRACKBAR_Timer (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
2041

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

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


2053
void TRACKBAR_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
2054
{
2055
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
2056

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

2066
    RegisterClassW (&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
2067
}
2068 2069


2070
void TRACKBAR_Unregister (void)
2071
{
2072
    UnregisterClassW (TRACKBAR_CLASSW, NULL);
2073
}