trackbar.c 53 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * Trackbar control
 *
4 5 6
 * Copyright 1998, 1999 Eric Kohl
 * Copyright 1998, 1999 Alex Priem
 * Copyright 2002 Dimitrie O. Paun
Alexandre Julliard's avatar
Alexandre Julliard committed
7
 *
8 9 10 11 12 13 14 15 16 17 18 19
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
21
 *
22 23 24 25 26 27 28 29 30
 * NOTE
 * 
 * This code was audited for completeness against the documented features
 * of Comctl32.dll version 6.0 on Sep. 12, 2002, by Dimitrie O. Paun.
 * 
 * Unless otherwise noted, we believe this code to be complete, as per
 * the specification mentioned above.
 * If you discover missing features, or bugs, please note them below.
 * 
Alexandre Julliard's avatar
Alexandre Julliard committed
31 32
 */

33
#include <stdarg.h>
34
#include <stdio.h>
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
35
#include <stdlib.h>
36
#include <string.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
37

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

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

50
WINE_DEFAULT_DEBUG_CHANNEL(trackbar);
51

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

79 80
#define TB_REFRESH_TIMER	1
#define TB_REFRESH_DELAY	500
Alexandre Julliard's avatar
Alexandre Julliard committed
81

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

84
/* Used by TRACKBAR_Refresh to find out which parts of the control
85
   need to be recalculated */
Alexandre Julliard's avatar
Alexandre Julliard committed
86

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

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

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

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

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

    pnmh->hwndFrom = infoPtr->hwndSelf;
120
    pnmh->idFrom = GetWindowLongPtrW(infoPtr->hwndSelf, GWLP_ID);
121 122 123 124 125 126 127 128 129
    pnmh->code = code;
    result = SendMessageW(infoPtr->hwndNotify, WM_NOTIFY,
			  (WPARAM)pnmh->idFrom, (LPARAM)pnmh);

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

    return result;
}

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

static BOOL
137
notify_with_scroll (const TRACKBAR_INFO *infoPtr, UINT code)
138 139 140 141 142 143 144 145 146 147
{
    BOOL bVert = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_VERT;

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

    return (BOOL) SendMessageW (infoPtr->hwndNotify,
                                bVert ? WM_VSCROLL : WM_HSCROLL,
				(WPARAM)code, (LPARAM)infoPtr->hwndSelf);
}
    
148
static void TRACKBAR_RecalculateTics (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
149
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
150
    int i, tic, nrTics;
Alexandre Julliard's avatar
Alexandre Julliard committed
151

152 153
    if (infoPtr->uTicFreq && infoPtr->lRangeMax >= infoPtr->lRangeMin)
    	nrTics=(infoPtr->lRangeMax - infoPtr->lRangeMin)/infoPtr->uTicFreq;
154
    else {
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
155
        nrTics = 0;
156
        Free (infoPtr->tics);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
157 158
        infoPtr->tics = NULL;
        infoPtr->uNumTics = 0;
159 160
        return;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
161

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
173 174 175 176
    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
177

178
/* converts from physical (mouse) position to logical position
Alex Priem's avatar
Alex Priem committed
179
   (in range of trackbar) */
Alexandre Julliard's avatar
Alexandre Julliard committed
180

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

186
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
Alex Priem's avatar
Alex Priem committed
187
    if (vertical) {
188 189
        offsetthumb = (infoPtr->rcThumb.bottom - infoPtr->rcThumb.top)/2;
        width = infoPtr->rcChannel.bottom - infoPtr->rcChannel.top - (offsetthumb * 2) - 1;
190
        pos = (range*(place - infoPtr->rcChannel.top - offsetthumb)) / width;
191
    } else {
192 193
        offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2;
        width = infoPtr->rcChannel.right - infoPtr->rcChannel.left - (offsetthumb * 2) - 1;
194
        pos = (range*(place - infoPtr->rcChannel.left - offsetthumb)) / width;
195
    }
196 197 198 199 200
    pos += infoPtr->lRangeMin;
    if (pos > infoPtr->lRangeMax)
        pos = infoPtr->lRangeMax;
    else if (pos < infoPtr->lRangeMin)
        pos = infoPtr->lRangeMin;
201

202
    TRACE("%.2f\n", pos);
203 204 205 206 207 208
    return (LONG)(pos + 0.5);
}


/* return: 0> prev, 0 none, >0 next */
static LONG
209
TRACKBAR_GetAutoPageDirection (const TRACKBAR_INFO *infoPtr, POINT clickPoint)
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238
{
    DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
    RECT pageRect;

    if (dwStyle & TBS_VERT) {
	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))
    {
	int clickPlace = (dwStyle & TBS_VERT) ? clickPoint.y : clickPoint.x;

        LONG clickPos = TRACKBAR_ConvertPlaceToPosition(infoPtr, clickPlace,
                                                        dwStyle & TBS_VERT);
	return clickPos - infoPtr->lPos;
    }

    return 0;
}

239
static inline void
240
TRACKBAR_PageDown (TRACKBAR_INFO *infoPtr)
241 242 243 244 245 246
{
    if (infoPtr->lPos == infoPtr->lRangeMax) return;

    infoPtr->lPos += infoPtr->lPageSize;
    if (infoPtr->lPos > infoPtr->lRangeMax)
	infoPtr->lPos = infoPtr->lRangeMax;
247
    notify_with_scroll (infoPtr, TB_PAGEDOWN);
Alexandre Julliard's avatar
Alexandre Julliard committed
248 249
}

Alex Priem's avatar
Alex Priem committed
250

251
static inline void
252
TRACKBAR_PageUp (TRACKBAR_INFO *infoPtr)
253 254 255 256 257 258
{
    if (infoPtr->lPos == infoPtr->lRangeMin) return;

    infoPtr->lPos -= infoPtr->lPageSize;
    if (infoPtr->lPos < infoPtr->lRangeMin)
        infoPtr->lPos = infoPtr->lRangeMin;
259 260 261
    notify_with_scroll (infoPtr, TB_PAGEUP);
}

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

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

280 281
static void
TRACKBAR_CalcChannel (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
282
{
283
    DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
284 285
    INT cyChannel, offsetthumb, offsetedge;
    RECT lpRect, *channel = & infoPtr->rcChannel;
Alexandre Julliard's avatar
Alexandre Julliard committed
286

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

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

335
static void
336
TRACKBAR_CalcThumb (const TRACKBAR_INFO *infoPtr, LONG lPos, RECT *thumb)
Alexandre Julliard's avatar
Alexandre Julliard committed
337
{
338
    int range, width, height, thumbwidth;
339
    DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
340
    RECT lpRect;
341

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

345
    if (!range) range = 1;
346

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

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

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

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

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

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

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

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

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

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

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

443
    TRACE("selection[left=%d, top=%d, right=%d, bottom=%d]\n",
444
	   selection->left, selection->top, selection->right, selection->bottom);
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 461 462 463 464 465 466
    else return FALSE;

    infoPtr->flags |= TB_THUMBPOSCHANGED;
    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, DWORD dwStyle)
471 472
{
    RECT rcChannel = infoPtr->rcChannel;
473
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
474

475 476 477 478 479 480 481 482 483 484 485 486 487 488
    if (theme)
    {
        DrawThemeBackground (theme, hdc, 
            (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_VERT) ? 
                TKP_TRACKVERT : TKP_TRACK, TKS_NORMAL, &rcChannel, 0);
    }
    else
    {
        DrawEdge (hdc, &rcChannel, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
        if (dwStyle & TBS_ENABLESELRANGE) {		 /* fill the channel */
            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
	rcTics.left = infoPtr->rcThumb.left - 2;
	rcTics.right = infoPtr->rcThumb.right + 2;
503
	rcTics.top    = infoPtr->rcChannel.top + offsetthumb + 1;
504
	rcTics.bottom = infoPtr->rcChannel.bottom - offsetthumb;
505
    } else {
506 507
        offsetthumb = (infoPtr->rcThumb.right - infoPtr->rcThumb.left)/2;
	rcTics.left   = infoPtr->rcChannel.left + offsetthumb + 1;
508 509 510
	rcTics.right  = infoPtr->rcChannel.right - offsetthumb;
	rcTics.top = infoPtr->rcThumb.top - 2;
	rcTics.bottom = infoPtr->rcThumb.bottom + 2;
511
    }
Alex Priem's avatar
Alex Priem committed
512

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

523
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
524
    if (range <= 0)
525
      range = 1; /* to avoid division by zero */
Alex Priem's avatar
Alex Priem committed
526

527
    if (flags & TIC_SELECTIONMARK) {
528 529 530
  	indent = (flags & TIC_SELECTIONMARKMIN) ? -1 : 1;
    } else if (flags & TIC_EDGE) {
	len++;
531
    }
Alex Priem's avatar
Alex Priem committed
532

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

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


567
static inline void
568
TRACKBAR_DrawTic (const TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, int flags)
Alex Priem's avatar
Alex Priem committed
569
{
570
    if ((flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH))
571
        TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags | TBS_LEFT);
Alex Priem's avatar
Alex Priem committed
572

573
    if (!(flags & (TBS_LEFT | TBS_TOP)) || (flags & TBS_BOTH))
574
        TRACKBAR_DrawOneTic (infoPtr, hdc, ticPos, flags & ~TBS_LEFT);
575 576 577
}

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

    if ((dwStyle & TBS_ENABLESELRANGE) && TRACKBAR_HasSelection(infoPtr)) {
        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
614 615
}

616
static void
617
TRACKBAR_DrawThumb (const TRACKBAR_INFO *infoPtr, HDC hdc, DWORD dwStyle)
618
{
619 620
    HBRUSH oldbr;
    HPEN  oldpen;
621
    RECT thumb = infoPtr->rcThumb;
622 623
    int BlackUntil = 3;
    int PointCount = 6;
624
    POINT points[6];
625
    int fillClr;
626
    int PointDepth;
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
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
    
    if (theme)
    {
        int partId;
        int stateId;
        if (dwStyle & TBS_BOTH)
            partId = (dwStyle & TBS_VERT) ? TKP_THUMBVERT : TKP_THUMB;
        else if (dwStyle & TBS_LEFT)
            partId = (dwStyle & TBS_VERT) ? TKP_THUMBLEFT : TKP_THUMBTOP;
        else
            partId = (dwStyle & TBS_VERT) ? TKP_THUMBRIGHT : TKP_THUMBBOTTOM;
            
        if (dwStyle & WS_DISABLED)
            stateId = TUS_DISABLED;
        else if (infoPtr->flags & TB_DRAG_MODE)
            stateId = TUS_PRESSED;
        else if (infoPtr->flags & TB_THUMB_HOT)
            stateId = TUS_HOT;
        else
            stateId = TUS_NORMAL;
        
        DrawThemeBackground (theme, hdc, partId, stateId, &thumb, 0);
        
        return;
    }
653

654 655
    fillClr = infoPtr->flags & TB_DRAG_MODE ? COLOR_BTNHILIGHT : COLOR_BTNFACE;
    oldbr = SelectObject (hdc, GetSysColorBrush(fillClr));
656
    SetPolyFillMode (hdc, WINDING);
657 658

    if (dwStyle & TBS_BOTH)
659 660 661 662 663 664 665 666 667 668 669 670 671
    {
       points[0].x=thumb.right;
       points[0].y=thumb.top;
       points[1].x=thumb.right;
       points[1].y=thumb.bottom;
       points[2].x=thumb.left;
       points[2].y=thumb.bottom;
       points[3].x=thumb.left;
       points[3].y=thumb.top;
       points[4].x=points[0].x;
       points[4].y=points[0].y;
       PointCount = 5;
       BlackUntil = 3;
672 673
    }
    else
674 675 676
    {
        if (dwStyle & TBS_VERT)
        {
677
          PointDepth = (thumb.bottom - thumb.top) / 2;
678 679 680 681 682 683 684 685 686
          if (dwStyle & TBS_LEFT)
          {
            points[0].x=thumb.right;
            points[0].y=thumb.top;
            points[1].x=thumb.right;
            points[1].y=thumb.bottom;
            points[2].x=thumb.left + PointDepth;
            points[2].y=thumb.bottom;
            points[3].x=thumb.left;
687
            points[3].y=(thumb.bottom - thumb.top) / 2 + thumb.top + 1;
688 689 690 691 692 693 694 695 696
            points[4].x=thumb.left + PointDepth;
            points[4].y=thumb.top;
            points[5].x=points[0].x;
            points[5].y=points[0].y;
            BlackUntil = 4;
          }
          else
          {
            points[0].x=thumb.right;
697
            points[0].y=(thumb.bottom - thumb.top) / 2 + thumb.top + 1;
698 699 700 701 702 703 704 705 706 707 708 709 710 711
            points[1].x=thumb.right - PointDepth;
            points[1].y=thumb.bottom;
            points[2].x=thumb.left;
            points[2].y=thumb.bottom;
            points[3].x=thumb.left;
            points[3].y=thumb.top;
            points[4].x=thumb.right - PointDepth;
            points[4].y=thumb.top;
            points[5].x=points[0].x;
            points[5].y=points[0].y;
          }
        }
        else
        {
712
          PointDepth = (thumb.right - thumb.left) / 2;
713 714
          if (dwStyle & TBS_TOP)
          {
715
            points[0].x=(thumb.right - thumb.left) / 2 + thumb.left + 1;
716 717 718 719
            points[0].y=thumb.top;
            points[1].x=thumb.right;
            points[1].y=thumb.top + PointDepth;
            points[2].x=thumb.right;
720
            points[2].y=thumb.bottom;
721 722 723 724 725 726 727 728 729 730 731 732 733 734
            points[3].x=thumb.left;
            points[3].y=thumb.bottom;
            points[4].x=thumb.left;
            points[4].y=thumb.top + PointDepth;
            points[5].x=points[0].x;
            points[5].y=points[0].y;
            BlackUntil = 4;
          }
          else
          {
            points[0].x=thumb.right;
            points[0].y=thumb.top;
            points[1].x=thumb.right;
            points[1].y=thumb.bottom - PointDepth;
735
            points[2].x=(thumb.right - thumb.left) / 2 + thumb.left + 1;
736 737 738 739 740 741 742 743 744
            points[2].y=thumb.bottom;
            points[3].x=thumb.left;
            points[3].y=thumb.bottom - PointDepth;
            points[4].x=thumb.left;
            points[4].y=thumb.top;
            points[5].x=points[0].x;
            points[5].y=points[0].y;
          }
        }
745

746 747
    }

748
    /* Draw the thumb now */
749
    Polygon (hdc, points, PointCount);
750 751 752
    oldpen = SelectObject(hdc, GetStockObject(BLACK_PEN));
    Polyline(hdc,points, BlackUntil);
    SelectObject(hdc, GetStockObject(WHITE_PEN));
753
    Polyline(hdc, &points[BlackUntil-1], PointCount+1-BlackUntil);
754 755
    SelectObject(hdc, oldpen);
    SelectObject(hdc, oldbr);
756
}
Alex Priem's avatar
Alex Priem committed
757

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

759
static inline void
760
TRACKBAR_ActivateToolTip (const TRACKBAR_INFO *infoPtr, BOOL fShow)
761 762 763 764 765 766 767 768 769 770 771 772 773
{
    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);
}


774
static void
775
TRACKBAR_UpdateToolTip (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
776
{
777
    DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
778 779
    WCHAR buf[80];
    static const WCHAR fmt[] = { '%', 'l', 'd', 0 };
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
780 781
    TTTOOLINFOW ti;
    POINT pt;
782
    RECT rcClient;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
783
    LRESULT size;
Alexandre Julliard's avatar
Alexandre Julliard committed
784

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
787 788 789 790 791 792 793 794 795
    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);

796
    GetClientRect (infoPtr->hwndSelf, &rcClient);
797
    size = SendMessageW (infoPtr->hwndToolTip, TTM_GETBUBBLESIZE, 0, (LPARAM)&ti);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
798
    if (dwStyle & TBS_VERT) {
799
	if (infoPtr->fLocation == TBTS_LEFT)
800
	    pt.x = 0 - LOWORD(size) - TOOLTIP_OFFSET;
801
	else
802
	    pt.x = rcClient.right + TOOLTIP_OFFSET;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
803 804
    	pt.y = (infoPtr->rcThumb.top + infoPtr->rcThumb.bottom - HIWORD(size))/2;
    } else {
805
	if (infoPtr->fLocation == TBTS_TOP)
806
	    pt.y = 0 - HIWORD(size) - TOOLTIP_OFFSET;
807
	else
808
            pt.y = rcClient.bottom + TOOLTIP_OFFSET;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
809
        pt.x = (infoPtr->rcThumb.left + infoPtr->rcThumb.right - LOWORD(size))/2;
Alex Priem's avatar
Alex Priem committed
810
    }
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
811 812 813 814 815 816 817 818
    ClientToScreen(infoPtr->hwndSelf, &pt);

    SendMessageW (infoPtr->hwndToolTip, TTM_TRACKPOSITION,
                  0, (LPARAM)MAKELPARAM(pt.x, pt.y));
}


static void
819
TRACKBAR_Refresh (TRACKBAR_INFO *infoPtr, HDC hdcDst)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
820 821
{
    DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
822
    RECT rcClient;
823 824
    HDC hdc;
    HBITMAP hOldBmp = 0, hOffScreenBmp = 0;
825 826
    NMCUSTOMDRAW nmcd;
    int gcdrf, icdrf;
827

828
    if (infoPtr->flags & TB_THUMBCHANGED) {
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
829
        TRACKBAR_UpdateThumb (infoPtr);
830
        if (infoPtr->flags & TB_THUMBSIZECHANGED)
831
            TRACKBAR_CalcChannel (infoPtr);
832 833
    }
    if (infoPtr->flags & TB_SELECTIONCHANGED)
834
        TRACKBAR_CalcSelection (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
835

836
    if (infoPtr->flags & TB_DRAG_MODE)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
837 838
        TRACKBAR_UpdateToolTip (infoPtr);

839 840
    infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED);

841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856
    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;
    }

857 858
    ZeroMemory(&nmcd, sizeof(nmcd));
    nmcd.hdr.hwndFrom = infoPtr->hwndSelf;
859
    nmcd.hdr.idFrom = GetWindowLongPtrW (infoPtr->hwndSelf, GWLP_ID);
860 861
    nmcd.hdr.code = NM_CUSTOMDRAW;
    nmcd.hdc = hdc;
Alexandre Julliard's avatar
Alexandre Julliard committed
862

863 864
    /* start the paint cycle */
    nmcd.rc = rcClient;
865
    gcdrf = notify_customdraw(infoPtr, &nmcd, CDDS_PREPAINT);
866 867
    if (gcdrf & CDRF_SKIPDEFAULT) goto cleanup;
    
868
    /* Erase backbround */
869
    if (gcdrf == CDRF_DODEFAULT ||
870
        notify_customdraw(infoPtr, &nmcd, CDDS_PREERASE) != CDRF_SKIPDEFAULT) {
871 872 873 874
        if (GetWindowTheme (infoPtr->hwndSelf))
            DrawThemeParentBackground (infoPtr->hwndSelf, hdc, &rcClient);
        else
	    FillRect (hdc, &rcClient, GetSysColorBrush(COLOR_BTNFACE));
875
        if (gcdrf != CDRF_DODEFAULT)
876
	    notify_customdraw(infoPtr, &nmcd, CDDS_POSTERASE);
877
    }
878
    
Alexandre Julliard's avatar
Alexandre Julliard committed
879
    /* draw channel */
880 881 882 883
    if (gcdrf & CDRF_NOTIFYITEMDRAW) {
        nmcd.dwItemSpec = TBCD_CHANNEL;
	nmcd.uItemState = CDIS_DEFAULT;
	nmcd.rc = infoPtr->rcChannel;
884
	icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
885 886 887 888
    } else icdrf = CDRF_DODEFAULT;
    if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
	TRACKBAR_DrawChannel (infoPtr, hdc, dwStyle);
	if (icdrf & CDRF_NOTIFYPOSTPAINT)
889
	    notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
Alexandre Julliard's avatar
Alexandre Julliard committed
890 891
    }

Alexandre Julliard's avatar
Alexandre Julliard committed
892 893

    /* draw tics */
894
    if (!(dwStyle & TBS_NOTICKS)) {
895 896 897 898
    	if (gcdrf & CDRF_NOTIFYITEMDRAW) {
            nmcd.dwItemSpec = TBCD_TICS;
	    nmcd.uItemState = CDIS_DEFAULT;
	    nmcd.rc = rcClient;
899
	    icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
900 901 902 903
        } else icdrf = CDRF_DODEFAULT;
	if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
	    TRACKBAR_DrawTics (infoPtr, hdc, dwStyle);
	    if (icdrf & CDRF_NOTIFYPOSTPAINT)
904
		notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
905
	}
Alexandre Julliard's avatar
Alexandre Julliard committed
906
    }
907
    
908
    /* draw thumb */
909 910 911 912 913
    if (!(dwStyle & TBS_NOTHUMB)) {
	if (gcdrf & CDRF_NOTIFYITEMDRAW) {
	    nmcd.dwItemSpec = TBCD_THUMB;
	    nmcd.uItemState = infoPtr->flags & TB_DRAG_MODE ? CDIS_HOT : CDIS_DEFAULT;
	    nmcd.rc = infoPtr->rcThumb;
914
	    icdrf = notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPREPAINT);
915 916 917 918
	} else icdrf = CDRF_DODEFAULT;
	if ( !(icdrf & CDRF_SKIPDEFAULT) ) {
            TRACKBAR_DrawThumb(infoPtr, hdc, dwStyle);
	    if (icdrf & CDRF_NOTIFYPOSTPAINT)
919
		notify_customdraw(infoPtr, &nmcd, CDDS_ITEMPOSTPAINT);
920 921
	}
    }
922

923 924 925 926 927
    /* draw focus rectangle */
    if (infoPtr->bFocussed) {
	DrawFocusRect(hdc, &rcClient);
    }

928 929
    /* finish up the painting */
    if (gcdrf & CDRF_NOTIFYPOSTPAINT)
930
	notify_customdraw(infoPtr, &nmcd, CDDS_POSTPAINT);
931 932
    
cleanup:
933 934 935 936 937 938 939
    /* 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
940 941 942
}


943
static void
944
TRACKBAR_AlignBuddies (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
945
{
946 947
    DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
    HWND hwndParent = GetParent (infoPtr->hwndSelf);
948 949
    RECT rcSelf, rcBuddy;
    INT x, y;
Alexandre Julliard's avatar
Alexandre Julliard committed
950

951
    GetWindowRect (infoPtr->hwndSelf, &rcSelf);
952
    MapWindowPoints (HWND_DESKTOP, hwndParent, (LPPOINT)&rcSelf, 2);
Alexandre Julliard's avatar
Alexandre Julliard committed
953 954 955

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

959
	if (dwStyle & TBS_VERT) {
Alexandre Julliard's avatar
Alexandre Julliard committed
960 961 962 963 964 965 966 967 968 969
	    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;
	}

970
	SetWindowPos (infoPtr->hwndBuddyLA, 0, x, y, 0, 0,
971
                      SWP_NOZORDER | SWP_NOSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
972 973 974 975 976
    }


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

980
	if (dwStyle & TBS_VERT) {
Alexandre Julliard's avatar
Alexandre Julliard committed
981 982 983 984 985 986 987 988 989
	    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;
	}
990
	SetWindowPos (infoPtr->hwndBuddyRB, 0, x, y, 0, 0,
991
                      SWP_NOZORDER | SWP_NOSIZE);
Alexandre Julliard's avatar
Alexandre Julliard committed
992 993 994 995 996
    }
}


static LRESULT
997
TRACKBAR_ClearSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
998
{
999 1000
    infoPtr->lSelMin = 0;
    infoPtr->lSelMax = 0;
1001
    infoPtr->flags |= TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1002

1003
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1004 1005 1006 1007 1008 1009

    return 0;
}


static LRESULT
1010
TRACKBAR_ClearTics (TRACKBAR_INFO *infoPtr, BOOL fRedraw)
Alexandre Julliard's avatar
Alexandre Julliard committed
1011 1012
{
    if (infoPtr->tics) {
1013
        Free (infoPtr->tics);
1014 1015
        infoPtr->tics = NULL;
        infoPtr->uNumTics = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1016 1017
    }

1018
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1019 1020 1021 1022 1023

    return 0;
}


1024
static inline LRESULT
1025
TRACKBAR_GetChannelRect (const TRACKBAR_INFO *infoPtr, LPRECT lprc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1026
{
1027
    if (lprc == NULL) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1028 1029 1030 1031 1032 1033 1034 1035 1036 1037

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

    return 0;
}


1038
static inline LONG
1039
TRACKBAR_GetNumTics (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1040
{
1041
    if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_NOTICKS)
1042
        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1043

1044 1045 1046 1047
    if(infoPtr->uNumTics == 0)
        return 2;
    else
        return infoPtr->uNumTics + 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1048 1049 1050
}


1051
static int comp_tics (const void *ap, const void *bp)
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1052
{
1053 1054
    const DWORD a = *(const DWORD *)ap;
    const DWORD b = *(const DWORD *)bp;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1055

1056
    TRACE("(a=%d, b=%d)\n", a, b);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1057 1058 1059 1060 1061
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
1062

1063
static inline LONG
1064
TRACKBAR_GetTic (const TRACKBAR_INFO *infoPtr, INT iTic)
Alexandre Julliard's avatar
Alexandre Julliard committed
1065
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1066
    if ((iTic < 0) || (iTic >= infoPtr->uNumTics) || !infoPtr->tics)
Alexandre Julliard's avatar
Alexandre Julliard committed
1067 1068
	return -1;

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1069
    qsort(infoPtr->tics, infoPtr->uNumTics, sizeof(DWORD), comp_tics);
1070
    return infoPtr->tics[iTic];
Alexandre Julliard's avatar
Alexandre Julliard committed
1071 1072 1073
}


1074
static inline LONG
1075
TRACKBAR_GetTicPos (const TRACKBAR_INFO *infoPtr, INT iTic)
Alexandre Julliard's avatar
Alexandre Julliard committed
1076
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1077
    LONG range, width, pos, tic;
1078
    int offsetthumb;
Alexandre Julliard's avatar
Alexandre Julliard committed
1079

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

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1083
    tic   = TRACKBAR_GetTic (infoPtr, iTic);
1084
    range = infoPtr->lRangeMax - infoPtr->lRangeMin;
1085
    if (range <= 0) range = 1;
1086 1087 1088
    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
1089

1090
    return pos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1091 1092
}

1093

1094 1095
static HWND
TRACKBAR_SetBuddy (TRACKBAR_INFO *infoPtr, BOOL fLocation, HWND hwndBuddy)
Alexandre Julliard's avatar
Alexandre Julliard committed
1096
{
1097
    HWND hwndTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1098

1099
    if (fLocation) {
Alexandre Julliard's avatar
Alexandre Julliard committed
1100 1101
	/* buddy is left or above */
	hwndTemp = infoPtr->hwndBuddyLA;
1102
	infoPtr->hwndBuddyLA = hwndBuddy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1103 1104
    }
    else {
1105 1106
        /* buddy is right or below */
        hwndTemp = infoPtr->hwndBuddyRB;
1107
        infoPtr->hwndBuddyRB = hwndBuddy;
Alexandre Julliard's avatar
Alexandre Julliard committed
1108 1109
    }

1110
    TRACKBAR_AlignBuddies (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1111

1112
    return hwndTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1113 1114 1115
}


1116
static inline LONG
1117
TRACKBAR_SetLineSize (TRACKBAR_INFO *infoPtr, LONG lLineSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1118
{
1119
    LONG lTemp = infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1120

1121
    infoPtr->lLineSize = lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1122

1123
    return lTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1124 1125 1126
}


1127
static inline LONG
1128
TRACKBAR_SetPageSize (TRACKBAR_INFO *infoPtr, LONG lPageSize)
Alexandre Julliard's avatar
Alexandre Julliard committed
1129
{
1130
    LONG lTemp = infoPtr->lPageSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1131

1132
    infoPtr->lPageSize = lPageSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1133

1134
    return lTemp;
Alexandre Julliard's avatar
Alexandre Julliard committed
1135 1136 1137
}


1138
static inline LRESULT
1139
TRACKBAR_SetPos (TRACKBAR_INFO *infoPtr, BOOL fPosition, LONG lPosition)
Alexandre Julliard's avatar
Alexandre Julliard committed
1140
{
1141
    LONG oldPos = infoPtr->lPos;
1142
    infoPtr->lPos = lPosition;
Alexandre Julliard's avatar
Alexandre Julliard committed
1143

1144 1145
    if (infoPtr->lPos < infoPtr->lRangeMin)
	infoPtr->lPos = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1146

1147 1148
    if (infoPtr->lPos > infoPtr->lRangeMax)
	infoPtr->lPos = infoPtr->lRangeMax;
1149
    infoPtr->flags |= TB_THUMBPOSCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1150

1151
    if (fPosition) TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, lPosition);
Alexandre Julliard's avatar
Alexandre Julliard committed
1152 1153 1154 1155 1156

    return 0;
}


1157
static inline LRESULT
1158
TRACKBAR_SetRange (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lRange)
Alexandre Julliard's avatar
Alexandre Julliard committed
1159
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1160 1161
    infoPtr->lRangeMin = (SHORT)LOWORD(lRange);
    infoPtr->lRangeMax = (SHORT)HIWORD(lRange);
Alexandre Julliard's avatar
Alexandre Julliard committed
1162

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

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

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

1176
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1177 1178 1179 1180 1181

    return 0;
}


1182
static inline LRESULT
1183
TRACKBAR_SetRangeMax (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMax)
Alexandre Julliard's avatar
Alexandre Julliard committed
1184
{
1185 1186 1187
    infoPtr->lRangeMax = lMax;
    if (infoPtr->lPos > infoPtr->lRangeMax) {
        infoPtr->lPos = infoPtr->lRangeMax;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1188
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1189
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1190

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

1194
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1195 1196 1197 1198 1199

    return 0;
}


1200
static inline LRESULT
1201
TRACKBAR_SetRangeMin (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lMin)
Alexandre Julliard's avatar
Alexandre Julliard committed
1202
{
1203 1204 1205
    infoPtr->lRangeMin = lMin;
    if (infoPtr->lPos < infoPtr->lRangeMin) {
        infoPtr->lPos = infoPtr->lRangeMin;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1206
        infoPtr->flags |= TB_THUMBPOSCHANGED;
1207
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1208

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

1212
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1213 1214 1215 1216

    return 0;
}

1217

1218
static inline LRESULT
1219
TRACKBAR_SetSel (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lSel)
Alexandre Julliard's avatar
Alexandre Julliard committed
1220
{
1221 1222 1223
    if (!(GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE)){
        infoPtr->lSelMin = 0;
        infoPtr->lSelMax = 0;
1224
        return 0;
1225
    }
1226

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1227 1228 1229
    infoPtr->lSelMin = (SHORT)LOWORD(lSel);
    infoPtr->lSelMax = (SHORT)HIWORD(lSel);
    infoPtr->flags |= TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1230

1231 1232 1233 1234
    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
1235

1236
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1237 1238 1239 1240 1241

    return 0;
}


1242
static inline LRESULT
1243
TRACKBAR_SetSelEnd (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lEnd)
Alexandre Julliard's avatar
Alexandre Julliard committed
1244
{
1245 1246
    if (!(GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE)){
        infoPtr->lSelMax = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1247
	return 0;
1248
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1249

1250
    infoPtr->lSelMax = lEnd;
1251
    infoPtr->flags |= TB_SELECTIONCHANGED;
1252

1253 1254
    if (infoPtr->lSelMax > infoPtr->lRangeMax)
        infoPtr->lSelMax = infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1255

1256
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1257 1258 1259 1260 1261

    return 0;
}


1262
static inline LRESULT
1263
TRACKBAR_SetSelStart (TRACKBAR_INFO *infoPtr, BOOL fRedraw, LONG lStart)
Alexandre Julliard's avatar
Alexandre Julliard committed
1264
{
1265 1266
    if (!(GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_ENABLESELRANGE)){
        infoPtr->lSelMin = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1267
	return 0;
1268
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1269

1270
    infoPtr->lSelMin = lStart;
1271
    infoPtr->flags  |=TB_SELECTIONCHANGED;
1272

1273 1274
    if (infoPtr->lSelMin < infoPtr->lRangeMin)
        infoPtr->lSelMin = infoPtr->lRangeMin;
Alexandre Julliard's avatar
Alexandre Julliard committed
1275

1276
    if (fRedraw) TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1277 1278 1279 1280 1281

    return 0;
}


1282
static inline LRESULT
1283
TRACKBAR_SetThumbLength (TRACKBAR_INFO *infoPtr, UINT iLength)
Alexandre Julliard's avatar
Alexandre Julliard committed
1284
{
1285
    if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_FIXEDLENGTH) {
1286
        infoPtr->uThumbLen = iLength;
1287 1288 1289
	infoPtr->flags |= TB_THUMBSIZECHANGED;
	InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
    }
1290

Alexandre Julliard's avatar
Alexandre Julliard committed
1291 1292 1293 1294
    return 0;
}


1295
static inline LRESULT
1296
TRACKBAR_SetTic (TRACKBAR_INFO *infoPtr, LONG lPos)
Alexandre Julliard's avatar
Alexandre Julliard committed
1297
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1298 1299 1300
    if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS)
	return FALSE;

1301
    if ((lPos < infoPtr->lRangeMin) || (lPos> infoPtr->lRangeMax))
1302
        return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1303

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

1306
    infoPtr->uNumTics++;
1307
    infoPtr->tics=ReAlloc( infoPtr->tics,
1308
                                    (infoPtr->uNumTics)*sizeof (DWORD));
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1309 1310
    if (!infoPtr->tics) {
	infoPtr->uNumTics = 0;
1311
	notify(infoPtr, NM_OUTOFMEMORY);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1312 1313 1314
	return FALSE;
    }
    infoPtr->tics[infoPtr->uNumTics-1] = lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1315

1316
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1317 1318 1319 1320 1321

    return TRUE;
}


1322
static inline LRESULT
1323 1324
TRACKBAR_SetTicFreq (TRACKBAR_INFO *infoPtr, WORD wFreq)
{
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1325
    if (GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE) & TBS_AUTOTICKS) {
1326
        infoPtr->uTicFreq = wFreq;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1327
	TRACKBAR_RecalculateTics (infoPtr);
1328
	TRACKBAR_InvalidateAll(infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1329
    }
1330 1331 1332 1333 1334

    return 0;
}


1335
static inline INT
1336
TRACKBAR_SetTipSide (TRACKBAR_INFO *infoPtr, INT fLocation)
Alexandre Julliard's avatar
Alexandre Julliard committed
1337
{
1338
    INT fTemp = infoPtr->fLocation;
Alexandre Julliard's avatar
Alexandre Julliard committed
1339

1340
    infoPtr->fLocation = fLocation;
1341

Alexandre Julliard's avatar
Alexandre Julliard committed
1342 1343 1344 1345
    return fTemp;
}


1346
static inline LRESULT
1347
TRACKBAR_SetToolTips (TRACKBAR_INFO *infoPtr, HWND hwndTT)
Alexandre Julliard's avatar
Alexandre Julliard committed
1348
{
1349
    infoPtr->hwndToolTip = hwndTT;
Alexandre Julliard's avatar
Alexandre Julliard committed
1350 1351 1352 1353 1354

    return 0;
}


1355
static inline BOOL
1356 1357 1358 1359 1360 1361 1362 1363
TRACKBAR_SetUnicodeFormat (TRACKBAR_INFO *infoPtr, BOOL fUnicode)
{
    BOOL bTemp = infoPtr->bUnicode;

    infoPtr->bUnicode = fUnicode;

    return bTemp;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1364 1365


Alexandre Julliard's avatar
Alexandre Julliard committed
1366
static LRESULT
1367
TRACKBAR_InitializeThumb (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1368
{
1369
    DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
1370
    RECT rect;
1371
    int clientWidth, clientMetric;
1372 1373

    /* initial thumb length */
1374
    clientMetric = (dwStyle & TBS_ENABLESELRANGE) ? 23 : 21;
1375
    GetClientRect(infoPtr->hwndSelf,&rect);
1376
    if (dwStyle & TBS_VERT) {
1377
	clientWidth = rect.right - rect.left;
1378
    } else {
1379
	clientWidth = rect.bottom - rect.top;
1380
    }
1381 1382
    if (clientWidth >= clientMetric)
        infoPtr->uThumbLen = clientMetric;
1383 1384
    else
        infoPtr->uThumbLen = clientWidth > 9 ? clientWidth - 6 : 4;
Alexandre Julliard's avatar
Alexandre Julliard committed
1385

1386
    TRACKBAR_CalcChannel (infoPtr);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1387
    TRACKBAR_UpdateThumb (infoPtr);
1388
    infoPtr->flags &= ~TB_SELECTIONCHANGED;
Alexandre Julliard's avatar
Alexandre Julliard committed
1389

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


static LRESULT
1395
TRACKBAR_Create (HWND hwnd, const CREATESTRUCTW *lpcs)
Alexandre Julliard's avatar
Alexandre Julliard committed
1396 1397
{
    TRACKBAR_INFO *infoPtr;
1398
    DWORD dwStyle;
Alexandre Julliard's avatar
Alexandre Julliard committed
1399

1400
    infoPtr = (TRACKBAR_INFO *)Alloc (sizeof(TRACKBAR_INFO));
1401
    if (!infoPtr) return -1;
1402
    SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1403

1404
    /* set default values */
1405 1406 1407 1408 1409 1410 1411 1412
    infoPtr->hwndSelf  = hwnd;
    infoPtr->lRangeMin = 0;
    infoPtr->lRangeMax = 100;
    infoPtr->lLineSize = 1;
    infoPtr->lPageSize = 20;
    infoPtr->lSelMin   = 0;
    infoPtr->lSelMax   = 0;
    infoPtr->lPos      = 0;
1413
    infoPtr->fLocation = -1;
Alexandre Julliard's avatar
Alexandre Julliard committed
1414
    infoPtr->uNumTics  = 0;    /* start and end tic are not included in count*/
1415
    infoPtr->uTicFreq  = 1;
1416
    infoPtr->tics      = NULL;
1417
    infoPtr->hwndNotify= lpcs->hwndParent;
Alexandre Julliard's avatar
Alexandre Julliard committed
1418

1419
    TRACKBAR_InitializeThumb (infoPtr);
Alex Priem's avatar
Alex Priem committed
1420

1421
    dwStyle = GetWindowLongW (hwnd, GWL_STYLE);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1422

1423
    /* Create tooltip control */
1424
    if (dwStyle & TBS_TOOLTIPS) {
Alex Priem's avatar
Alex Priem committed
1425 1426

    	infoPtr->hwndToolTip =
1427
            CreateWindowExW (0, TOOLTIPS_CLASSW, NULL, WS_POPUP,
1428 1429 1430
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             CW_USEDEFAULT, CW_USEDEFAULT,
                             hwnd, 0, 0, 0);
Alex Priem's avatar
Alex Priem committed
1431

1432
    	if (infoPtr->hwndToolTip) {
1433
            TTTOOLINFOW ti;	    
1434 1435 1436 1437
            ZeroMemory (&ti, sizeof(ti));
            ti.cbSize   = sizeof(ti);
     	    ti.uFlags   = TTF_IDISHWND | TTF_TRACK | TTF_ABSOLUTE;
	    ti.hwnd     = hwnd;
Alex Priem's avatar
Alex Priem committed
1438

1439 1440
            SendMessageW (infoPtr->hwndToolTip, TTM_ADDTOOLW, 0, (LPARAM)&ti);
	 }
1441
    }
1442 1443
    
    OpenThemeData (hwnd, themeClass);
1444

Alexandre Julliard's avatar
Alexandre Julliard committed
1445 1446 1447 1448 1449
    return 0;
}


static LRESULT
1450
TRACKBAR_Destroy (TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1451
{
1452
    /* delete tooltip control */
Alex Priem's avatar
Alex Priem committed
1453
    if (infoPtr->hwndToolTip)
1454
    	DestroyWindow (infoPtr->hwndToolTip);
Alex Priem's avatar
Alex Priem committed
1455

1456
    Free (infoPtr);
1457
    SetWindowLongPtrW (infoPtr->hwndSelf, 0, 0);
1458
    CloseThemeData (GetWindowTheme (infoPtr->hwndSelf));
Alexandre Julliard's avatar
Alexandre Julliard committed
1459 1460 1461 1462 1463
    return 0;
}


static LRESULT
1464
TRACKBAR_KillFocus (TRACKBAR_INFO *infoPtr, HWND hwndGetFocus)
Alexandre Julliard's avatar
Alexandre Julliard committed
1465
{
1466
    TRACE("\n");
1467
    infoPtr->bFocussed = FALSE;
1468
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1469 1470 1471 1472 1473

    return 0;
}

static LRESULT
1474
TRACKBAR_LButtonDown (TRACKBAR_INFO *infoPtr, DWORD fwKeys, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1475
{
1476 1477 1478 1479
    POINT clickPoint;

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

1481 1482
    SetFocus(infoPtr->hwndSelf);

1483
    if (PtInRect(&infoPtr->rcThumb, clickPoint)) {
1484
        infoPtr->flags |= TB_DRAG_MODE;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1485
        SetCapture (infoPtr->hwndSelf);
1486 1487
	TRACKBAR_UpdateToolTip (infoPtr);
	TRACKBAR_ActivateToolTip (infoPtr, TRUE);
1488
	TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1489
    } else {
1490 1491 1492 1493 1494 1495
	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);
1496
    }
1497

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

1501

Alexandre Julliard's avatar
Alexandre Julliard committed
1502
static LRESULT
1503
TRACKBAR_LButtonUp (TRACKBAR_INFO *infoPtr, DWORD fwKeys, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1504
{
1505
    if (infoPtr->flags & TB_DRAG_MODE) {
1506 1507
        notify_with_scroll (infoPtr, TB_THUMBPOSITION | (infoPtr->lPos<<16));
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1508 1509
        infoPtr->flags &= ~TB_DRAG_MODE;
        ReleaseCapture ();
1510
	notify(infoPtr, NM_RELEASEDCAPTURE);
1511
        TRACKBAR_ActivateToolTip(infoPtr, FALSE);
1512
	TRACKBAR_InvalidateThumb(infoPtr, infoPtr->lPos);
1513 1514 1515 1516
    }
    if (infoPtr->flags & TB_AUTO_PAGE) {
	KillTimer (infoPtr->hwndSelf, TB_REFRESH_TIMER);
        infoPtr->flags &= ~TB_AUTO_PAGE;
1517
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1518
        ReleaseCapture ();
1519
	notify(infoPtr, NM_RELEASEDCAPTURE);
1520
    }
1521

Alexandre Julliard's avatar
Alexandre Julliard committed
1522 1523 1524
    return 0;
}

1525

Alexandre Julliard's avatar
Alexandre Julliard committed
1526
static LRESULT
1527
TRACKBAR_CaptureChanged (const TRACKBAR_INFO *infoPtr)
Alexandre Julliard's avatar
Alexandre Julliard committed
1528
{
1529
    notify_with_scroll (infoPtr, TB_ENDTRACK);
1530
    return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1531
}
Alexandre Julliard's avatar
Alexandre Julliard committed
1532

1533

Alexandre Julliard's avatar
Alexandre Julliard committed
1534
static LRESULT
1535
TRACKBAR_Paint (TRACKBAR_INFO *infoPtr, HDC hdc)
Alexandre Julliard's avatar
Alexandre Julliard committed
1536
{
1537 1538 1539 1540 1541 1542 1543 1544
    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
1545 1546 1547 1548 1549 1550

    return 0;
}


static LRESULT
1551
TRACKBAR_SetFocus (TRACKBAR_INFO *infoPtr, HWND hwndLoseFocus)
Alexandre Julliard's avatar
Alexandre Julliard committed
1552
{
1553
    TRACE("\n");
1554
    infoPtr->bFocussed = TRUE;
1555
    TRACKBAR_InvalidateAll(infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1556 1557 1558 1559 1560 1561

    return 0;
}


static LRESULT
1562
TRACKBAR_Size (TRACKBAR_INFO *infoPtr, DWORD fwSizeType, INT nWidth, INT nHeight)
Alexandre Julliard's avatar
Alexandre Julliard committed
1563
{
1564
    TRACKBAR_InitializeThumb (infoPtr);
1565
    TRACKBAR_AlignBuddies (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1566 1567 1568 1569 1570

    return 0;
}


1571
static LRESULT
1572
TRACKBAR_Timer (TRACKBAR_INFO *infoPtr, INT wTimerID, const TIMERPROC *tmrpc)
1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583
{
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
	if (GetCursorPos(&pt))
	    if (ScreenToClient(infoPtr->hwndSelf, &pt))
		TRACKBAR_AutoPage(infoPtr, pt);
    }
    return 0;
}


1584
/* update theme after a WM_THEMECHANGED message */
1585
static LRESULT theme_changed (const TRACKBAR_INFO* infoPtr)
1586 1587 1588 1589 1590 1591 1592 1593
{
    HTHEME theme = GetWindowTheme (infoPtr->hwndSelf);
    CloseThemeData (theme);
    theme = OpenThemeData (infoPtr->hwndSelf, themeClass);
    return 0;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
1594
static LRESULT
1595
TRACKBAR_MouseMove (TRACKBAR_INFO *infoPtr, DWORD fwKeys, INT x, INT y)
Alexandre Julliard's avatar
Alexandre Julliard committed
1596
{
1597
    DWORD dwStyle = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
1598
    INT clickPlace = (dwStyle & TBS_VERT) ? y : x;
1599
    LONG dragPos, oldPos = infoPtr->lPos;
1600

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

1603 1604
    if (infoPtr->flags & TB_AUTO_PAGE) {
	POINT pt;
1605 1606
	pt.x = x;
	pt.y = y;
1607
	TRACKBAR_AutoPage (infoPtr, pt);
1608
	return TRUE;
1609 1610
    }

1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640
    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
1641

1642
    dragPos = TRACKBAR_ConvertPlaceToPosition (infoPtr, clickPlace,
1643
                                               dwStyle & TBS_VERT);
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1644
    if (dragPos == oldPos) return TRUE;
Alex Priem's avatar
Alex Priem committed
1645

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1646
    infoPtr->lPos = dragPos;
1647

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1648
    infoPtr->flags |= TB_THUMBPOSCHANGED;
1649
    notify_with_scroll (infoPtr, TB_THUMBTRACK | (infoPtr->lPos<<16));
1650

Alex Priem's avatar
Alex Priem committed
1651

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1652
    TRACKBAR_InvalidateThumbMove(infoPtr, oldPos, dragPos);
1653
    UpdateWindow (infoPtr->hwndSelf);
Alex Priem's avatar
Alex Priem committed
1654

1655
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1656 1657
}

1658 1659
static BOOL
TRACKBAR_KeyDown (TRACKBAR_INFO *infoPtr, INT nVirtKey, DWORD lKeyData)
Alexandre Julliard's avatar
Alexandre Julliard committed
1660
{
1661 1662 1663
    DWORD style = GetWindowLongW (infoPtr->hwndSelf, GWL_STYLE);
    BOOL downIsLeft = style & TBS_DOWNISLEFT;
    BOOL vert = style & TBS_VERT;
1664
    LONG pos = infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1665

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

1668
    switch (nVirtKey) {
1669
    case VK_UP:
1670 1671 1672
	if (!vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
        else TRACKBAR_LineUp(infoPtr);
        break;
1673
    case VK_LEFT:
1674 1675
        if (vert && downIsLeft) TRACKBAR_LineDown(infoPtr);
        else TRACKBAR_LineUp(infoPtr);
1676
        break;
1677
    case VK_DOWN:
1678 1679 1680
	if (!vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
        else TRACKBAR_LineDown(infoPtr);
        break;
1681
    case VK_RIGHT:
1682 1683
	if (vert && downIsLeft) TRACKBAR_LineUp(infoPtr);
        else TRACKBAR_LineDown(infoPtr);
1684 1685
        break;
    case VK_NEXT:
1686 1687
	if (!vert && downIsLeft) TRACKBAR_PageUp(infoPtr);
        else TRACKBAR_PageDown(infoPtr);
1688 1689
        break;
    case VK_PRIOR:
1690 1691
	if (!vert && downIsLeft) TRACKBAR_PageDown(infoPtr);
        else TRACKBAR_PageUp(infoPtr);
1692
        break;
1693
    case VK_HOME:
1694 1695
        if (infoPtr->lPos == infoPtr->lRangeMin) return FALSE;
        infoPtr->lPos = infoPtr->lRangeMin;
1696
        notify_with_scroll (infoPtr, TB_TOP);
1697
        break;
1698
    case VK_END:
1699 1700
        if (infoPtr->lPos == infoPtr->lRangeMax) return FALSE;
        infoPtr->lPos = infoPtr->lRangeMax;
1701
        notify_with_scroll (infoPtr, TB_BOTTOM);
1702 1703
        break;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1704

1705
    if (pos != infoPtr->lPos) {
Alex Priem's avatar
Alex Priem committed
1706
	infoPtr->flags |=TB_THUMBPOSCHANGED;
Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1707
	TRACKBAR_InvalidateThumbMove (infoPtr, pos, infoPtr->lPos);
1708
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
1709

1710
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
1711 1712
}

1713

1714
static inline BOOL
1715
TRACKBAR_KeyUp (const TRACKBAR_INFO *infoPtr, INT nVirtKey, DWORD lKeyData)
Alexandre Julliard's avatar
Alexandre Julliard committed
1716
{
1717
    switch (nVirtKey) {
1718
    case VK_LEFT:
1719
    case VK_UP:
1720
    case VK_RIGHT:
1721
    case VK_DOWN:
1722 1723
    case VK_NEXT:
    case VK_PRIOR:
1724
    case VK_HOME:
1725
    case VK_END:
1726
        notify_with_scroll (infoPtr, TB_ENDTRACK);
1727 1728
    }
    return TRUE;
Alex Priem's avatar
Alex Priem committed
1729 1730 1731
}


1732
static LRESULT WINAPI
1733
TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
1734
{
1735
    TRACKBAR_INFO *infoPtr = (TRACKBAR_INFO *)GetWindowLongPtrW (hwnd, 0);
1736

1737
    TRACE("hwnd=%p msg=%x wparam=%lx lparam=%lx\n", hwnd, uMsg, wParam, lParam);
1738 1739 1740 1741

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

Alexandre Julliard's avatar
Alexandre Julliard committed
1742 1743
    switch (uMsg)
    {
1744
    case TBM_CLEARSEL:
1745
        return TRACKBAR_ClearSel (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1746

1747
    case TBM_CLEARTICS:
1748
        return TRACKBAR_ClearTics (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1749

1750
    case TBM_GETBUDDY:
1751
        return (LRESULT)(wParam ? infoPtr->hwndBuddyLA : infoPtr->hwndBuddyRB);
Alexandre Julliard's avatar
Alexandre Julliard committed
1752

1753
    case TBM_GETCHANNELRECT:
1754
        return TRACKBAR_GetChannelRect (infoPtr, (LPRECT)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1755

1756
    case TBM_GETLINESIZE:
1757
        return infoPtr->lLineSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1758

1759
    case TBM_GETNUMTICS:
1760
        return TRACKBAR_GetNumTics (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1761

1762
    case TBM_GETPAGESIZE:
1763
        return infoPtr->lPageSize;
Alexandre Julliard's avatar
Alexandre Julliard committed
1764

1765
    case TBM_GETPOS:
1766
        return infoPtr->lPos;
Alexandre Julliard's avatar
Alexandre Julliard committed
1767

1768
    case TBM_GETPTICS:
1769
        return (LRESULT)infoPtr->tics;
Alexandre Julliard's avatar
Alexandre Julliard committed
1770

1771
    case TBM_GETRANGEMAX:
1772
        return infoPtr->lRangeMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1773

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

1777
    case TBM_GETSELEND:
1778
        return infoPtr->lSelMax;
Alexandre Julliard's avatar
Alexandre Julliard committed
1779

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

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

1786
    case TBM_GETTHUMBRECT:
1787
	return CopyRect((LPRECT)lParam, &infoPtr->rcThumb);
Alexandre Julliard's avatar
Alexandre Julliard committed
1788

Alexandre Julliard's avatar
Alexandre Julliard committed
1789
    case TBM_GETTIC:
1790
        return TRACKBAR_GetTic (infoPtr, (INT)wParam);
1791

Alexandre Julliard's avatar
Alexandre Julliard committed
1792
    case TBM_GETTICPOS:
1793
        return TRACKBAR_GetTicPos (infoPtr, (INT)wParam);
1794

1795
    case TBM_GETTOOLTIPS:
1796
        return (LRESULT)infoPtr->hwndToolTip;
Alexandre Julliard's avatar
Alexandre Julliard committed
1797

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

1801
    case TBM_SETBUDDY:
1802
        return (LRESULT) TRACKBAR_SetBuddy(infoPtr, (BOOL)wParam, (HWND)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1803

1804
    case TBM_SETLINESIZE:
1805
        return TRACKBAR_SetLineSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1806

1807
    case TBM_SETPAGESIZE:
1808
        return TRACKBAR_SetPageSize (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1809

1810
    case TBM_SETPOS:
1811
        return TRACKBAR_SetPos (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1812

1813
    case TBM_SETRANGE:
1814
        return TRACKBAR_SetRange (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1815

1816
    case TBM_SETRANGEMAX:
1817
        return TRACKBAR_SetRangeMax (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1818

1819
    case TBM_SETRANGEMIN:
1820
        return TRACKBAR_SetRangeMin (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1821

1822
    case TBM_SETSEL:
1823
        return TRACKBAR_SetSel (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1824

1825
    case TBM_SETSELEND:
1826
        return TRACKBAR_SetSelEnd (infoPtr, (BOOL)wParam, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1827

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

1831
    case TBM_SETTHUMBLENGTH:
1832
        return TRACKBAR_SetThumbLength (infoPtr, (UINT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1833

1834
    case TBM_SETTIC:
1835
        return TRACKBAR_SetTic (infoPtr, (LONG)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1836

Alexandre Julliard's avatar
Alexandre Julliard committed
1837
    case TBM_SETTICFREQ:
1838
        return TRACKBAR_SetTicFreq (infoPtr, (WORD)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1839

1840
    case TBM_SETTIPSIDE:
1841
        return TRACKBAR_SetTipSide (infoPtr, (INT)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1842

1843
    case TBM_SETTOOLTIPS:
1844
        return TRACKBAR_SetToolTips (infoPtr, (HWND)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1845

1846 1847
    case TBM_SETUNICODEFORMAT:
	return TRACKBAR_SetUnicodeFormat (infoPtr, (BOOL)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1848 1849


1850
    case WM_CAPTURECHANGED:
1851
        return TRACKBAR_CaptureChanged (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1852

1853
    case WM_CREATE:
1854
        return TRACKBAR_Create (hwnd, (LPCREATESTRUCTW)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1855

1856
    case WM_DESTROY:
1857
        return TRACKBAR_Destroy (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1858

1859
/*	case WM_ENABLE: */
Alexandre Julliard's avatar
Alexandre Julliard committed
1860

Dimitrie O. Paun's avatar
Dimitrie O. Paun committed
1861
    case WM_ERASEBKGND:
1862
	return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
1863

1864 1865
    case WM_GETDLGCODE:
        return DLGC_WANTARROWS;
Alexandre Julliard's avatar
Alexandre Julliard committed
1866

1867
    case WM_KEYDOWN:
1868
        return TRACKBAR_KeyDown (infoPtr, (INT)wParam, (DWORD)lParam);
1869

1870
    case WM_KEYUP:
1871
        return TRACKBAR_KeyUp (infoPtr, (INT)wParam, (DWORD)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1872

1873
    case WM_KILLFOCUS:
1874
        return TRACKBAR_KillFocus (infoPtr, (HWND)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1875

1876
    case WM_LBUTTONDOWN:
1877
        return TRACKBAR_LButtonDown (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
1878

1879
    case WM_LBUTTONUP:
1880
        return TRACKBAR_LButtonUp (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
1881

1882 1883 1884 1885 1886
    case WM_MOUSELEAVE:
        infoPtr->flags &= ~TB_THUMB_HOT; 
        InvalidateRect (infoPtr->hwndSelf, &infoPtr->rcThumb, FALSE);
        return 0;
    
1887
    case WM_MOUSEMOVE:
1888
        return TRACKBAR_MouseMove (infoPtr, wParam, (SHORT)LOWORD(lParam), (SHORT)HIWORD(lParam));
Alexandre Julliard's avatar
Alexandre Julliard committed
1889

1890
    case WM_PRINTCLIENT:
1891
    case WM_PAINT:
1892
        return TRACKBAR_Paint (infoPtr, (HDC)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1893

1894
    case WM_SETFOCUS:
1895
        return TRACKBAR_SetFocus (infoPtr, (HWND)wParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1896

1897
    case WM_SIZE:
1898 1899
        return TRACKBAR_Size (infoPtr, wParam, LOWORD(lParam), HIWORD(lParam));

1900 1901 1902
    case WM_THEMECHANGED:
        return theme_changed (infoPtr);

1903 1904
    case WM_TIMER:
	return TRACKBAR_Timer (infoPtr, (INT)wParam, (TIMERPROC *)lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1905

1906
    case WM_WININICHANGE:
1907
        return TRACKBAR_InitializeThumb (infoPtr);
Alexandre Julliard's avatar
Alexandre Julliard committed
1908

1909
    default:
1910
        if ((uMsg >= WM_USER) && (uMsg < WM_APP))
1911
            ERR("unknown msg %04x wp=%08lx lp=%08lx\n", uMsg, wParam, lParam);
1912
        return DefWindowProcW (hwnd, uMsg, wParam, lParam);
Alexandre Julliard's avatar
Alexandre Julliard committed
1913 1914 1915 1916
    }
}


1917
void TRACKBAR_Register (void)
Alexandre Julliard's avatar
Alexandre Julliard committed
1918
{
1919
    WNDCLASSW wndClass;
Alexandre Julliard's avatar
Alexandre Julliard committed
1920

1921
    ZeroMemory (&wndClass, sizeof(WNDCLASSW));
Alexandre Julliard's avatar
Alexandre Julliard committed
1922
    wndClass.style         = CS_GLOBALCLASS;
1923
    wndClass.lpfnWndProc   = TRACKBAR_WindowProc;
Alexandre Julliard's avatar
Alexandre Julliard committed
1924 1925
    wndClass.cbClsExtra    = 0;
    wndClass.cbWndExtra    = sizeof(TRACKBAR_INFO *);
1926
    wndClass.hCursor       = LoadCursorW (0, (LPWSTR)IDC_ARROW);
1927
    wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
1928
    wndClass.lpszClassName = TRACKBAR_CLASSW;
1929

1930
    RegisterClassW (&wndClass);
Alexandre Julliard's avatar
Alexandre Julliard committed
1931
}
1932 1933


1934
void TRACKBAR_Unregister (void)
1935
{
1936
    UnregisterClassW (TRACKBAR_CLASSW, NULL);
1937
}