1 /* 2 * Progress control 3 * 4 * Copyright 1997, 2002 Dimitrie O. Paun 5 * Copyright 1998, 1999 Eric Kohl 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 20 * 21 * TODO: 22 * 23 * Styles: 24 * -- PBS_SMOOTHREVERSE 25 * 26 */ 27 28 #include <stdarg.h> 29 #include <string.h> 30 #include "windef.h" 31 #include "winbase.h" 32 #include "wingdi.h" 33 #include "winuser.h" 34 #include "winnls.h" 35 #include "commctrl.h" 36 #include "comctl32.h" 37 #include "uxtheme.h" 38 #include "vssym32.h" 39 #include "wine/debug.h" 40 #include "wine/heap.h" 41 42 WINE_DEFAULT_DEBUG_CHANNEL(progress); 43 44 typedef struct 45 { 46 HWND Self; /* The window handle for this control */ 47 INT CurVal; /* Current progress value */ 48 INT MinVal; /* Minimum progress value */ 49 INT MaxVal; /* Maximum progress value */ 50 INT Step; /* Step to use on PMB_STEPIT */ 51 INT MarqueePos; /* Marquee animation position */ 52 BOOL Marquee; /* Whether the marquee animation is enabled */ 53 COLORREF ColorBar; /* Bar color */ 54 COLORREF ColorBk; /* Background color */ 55 HFONT Font; /* Handle to font (not unused) */ 56 } PROGRESS_INFO; 57 58 /* Control configuration constants */ 59 60 #define LED_GAP 2 61 #define MARQUEE_LEDS 5 62 #define ID_MARQUEE_TIMER 1 63 #define DEFAULT_MARQUEE_PERIOD 30 64 65 /* Helper to obtain size of a progress bar chunk ("led"). */ 66 static inline int get_led_size ( const PROGRESS_INFO *infoPtr, LONG style, 67 const RECT* rect ) 68 { 69 HTHEME theme = GetWindowTheme (infoPtr->Self); 70 if (theme) 71 { 72 int chunkSize; 73 if (SUCCEEDED( GetThemeInt( theme, 0, 0, TMT_PROGRESSCHUNKSIZE, &chunkSize ))) 74 return chunkSize; 75 } 76 77 if (style & PBS_VERTICAL) 78 return MulDiv (rect->right - rect->left, 2, 3); 79 else 80 return MulDiv (rect->bottom - rect->top, 2, 3); 81 } 82 83 /* Helper to obtain gap between progress bar chunks */ 84 static inline int get_led_gap ( const PROGRESS_INFO *infoPtr ) 85 { 86 HTHEME theme = GetWindowTheme (infoPtr->Self); 87 if (theme) 88 { 89 int spaceSize; 90 if (SUCCEEDED( GetThemeInt( theme, 0, 0, TMT_PROGRESSSPACESIZE, &spaceSize ))) 91 return spaceSize; 92 } 93 94 return LED_GAP; 95 } 96 97 /* Get client rect. Takes into account that theming needs no adjustment. */ 98 static inline void get_client_rect (HWND hwnd, RECT* rect) 99 { 100 HTHEME theme = GetWindowTheme (hwnd); 101 GetClientRect (hwnd, rect); 102 if (!theme) 103 InflateRect(rect, -1, -1); 104 else 105 { 106 DWORD dwStyle = GetWindowLongW (hwnd, GWL_STYLE); 107 int part = (dwStyle & PBS_VERTICAL) ? PP_BARVERT : PP_BAR; 108 GetThemeBackgroundContentRect (theme, 0, part, 0, rect, rect); 109 } 110 } 111 112 /* Compute the extend of the bar */ 113 static inline int get_bar_size( LONG style, const RECT* rect ) 114 { 115 if (style & PBS_VERTICAL) 116 return rect->bottom - rect->top; 117 else 118 return rect->right - rect->left; 119 } 120 121 /* Compute the pixel position of a progress value */ 122 static inline int get_bar_position( const PROGRESS_INFO *infoPtr, LONG style, 123 const RECT* rect, INT value ) 124 { 125 return MulDiv (value - infoPtr->MinVal, get_bar_size (style, rect), 126 infoPtr->MaxVal - infoPtr->MinVal); 127 } 128 129 /*********************************************************************** 130 * PROGRESS_Invalidate 131 * 132 * Don't be too clever about invalidating the progress bar. 133 * InstallShield depends on this simple behaviour. 134 */ 135 static void PROGRESS_Invalidate( const PROGRESS_INFO *infoPtr, INT old, INT new ) 136 { 137 InvalidateRect( infoPtr->Self, NULL, old > new ); 138 } 139 140 /* Information for a progress bar drawing helper */ 141 typedef struct tagProgressDrawInfo 142 { 143 HDC hdc; 144 RECT rect; 145 HBRUSH hbrBar; 146 HBRUSH hbrBk; 147 int ledW, ledGap; 148 HTHEME theme; 149 RECT bgRect; 150 } ProgressDrawInfo; 151 152 typedef void (*ProgressDrawProc)(const ProgressDrawInfo* di, int start, int end); 153 154 /* draw solid horizontal bar from 'start' to 'end' */ 155 static void draw_solid_bar_H (const ProgressDrawInfo* di, int start, int end) 156 { 157 RECT r; 158 SetRect(&r, di->rect.left + start, di->rect.top, di->rect.left + end, di->rect.bottom); 159 FillRect (di->hdc, &r, di->hbrBar); 160 } 161 162 /* draw solid horizontal background from 'start' to 'end' */ 163 static void draw_solid_bkg_H (const ProgressDrawInfo* di, int start, int end) 164 { 165 RECT r; 166 SetRect(&r, di->rect.left + start, di->rect.top, di->rect.left + end, di->rect.bottom); 167 FillRect (di->hdc, &r, di->hbrBk); 168 } 169 170 /* draw solid vertical bar from 'start' to 'end' */ 171 static void draw_solid_bar_V (const ProgressDrawInfo* di, int start, int end) 172 { 173 RECT r; 174 SetRect(&r, di->rect.left, di->rect.bottom - end, di->rect.right, di->rect.bottom - start); 175 FillRect (di->hdc, &r, di->hbrBar); 176 } 177 178 /* draw solid vertical background from 'start' to 'end' */ 179 static void draw_solid_bkg_V (const ProgressDrawInfo* di, int start, int end) 180 { 181 RECT r; 182 SetRect(&r, di->rect.left, di->rect.bottom - end, di->rect.right, di->rect.bottom - start); 183 FillRect (di->hdc, &r, di->hbrBk); 184 } 185 186 /* draw chunky horizontal bar from 'start' to 'end' */ 187 static void draw_chunk_bar_H (const ProgressDrawInfo* di, int start, int end) 188 { 189 RECT r; 190 int right = di->rect.left + end; 191 r.left = di->rect.left + start; 192 r.top = di->rect.top; 193 r.bottom = di->rect.bottom; 194 while (r.left < right) 195 { 196 r.right = min (r.left + di->ledW, right); 197 FillRect (di->hdc, &r, di->hbrBar); 198 r.left = r.right; 199 r.right = min (r.left + di->ledGap, right); 200 FillRect (di->hdc, &r, di->hbrBk); 201 r.left = r.right; 202 } 203 } 204 205 /* draw chunky vertical bar from 'start' to 'end' */ 206 static void draw_chunk_bar_V (const ProgressDrawInfo* di, int start, int end) 207 { 208 RECT r; 209 int top = di->rect.bottom - end; 210 r.left = di->rect.left; 211 r.right = di->rect.right; 212 r.bottom = di->rect.bottom - start; 213 while (r.bottom > top) 214 { 215 r.top = max (r.bottom - di->ledW, top); 216 FillRect (di->hdc, &r, di->hbrBar); 217 r.bottom = r.top; 218 r.top = max (r.bottom - di->ledGap, top); 219 FillRect (di->hdc, &r, di->hbrBk); 220 r.bottom = r.top; 221 } 222 } 223 224 /* drawing functions for "classic" style */ 225 static const ProgressDrawProc drawProcClassic[8] = { 226 /* Smooth */ 227 /* Horizontal */ 228 draw_solid_bar_H, draw_solid_bkg_H, 229 /* Vertical */ 230 draw_solid_bar_V, draw_solid_bkg_V, 231 /* Chunky */ 232 /* Horizontal */ 233 draw_chunk_bar_H, draw_solid_bkg_H, 234 /* Vertical */ 235 draw_chunk_bar_V, draw_solid_bkg_V, 236 }; 237 238 /* draw themed horizontal bar from 'start' to 'end' */ 239 static void draw_theme_bar_H (const ProgressDrawInfo* di, int start, int end) 240 { 241 RECT r; 242 r.left = di->rect.left + start; 243 r.top = di->rect.top; 244 r.bottom = di->rect.bottom; 245 r.right = di->rect.left + end; 246 DrawThemeBackground (di->theme, di->hdc, PP_CHUNK, 0, &r, NULL); 247 } 248 249 /* draw themed vertical bar from 'start' to 'end' */ 250 static void draw_theme_bar_V (const ProgressDrawInfo* di, int start, int end) 251 { 252 RECT r; 253 r.left = di->rect.left; 254 r.right = di->rect.right; 255 r.bottom = di->rect.bottom - start; 256 r.top = di->rect.bottom - end; 257 DrawThemeBackground (di->theme, di->hdc, PP_CHUNKVERT, 0, &r, NULL); 258 } 259 260 /* draw themed horizontal background from 'start' to 'end' */ 261 static void draw_theme_bkg_H (const ProgressDrawInfo* di, int start, int end) 262 { 263 RECT bgrect, r; 264 265 SetRect(&r, di->rect.left + start, di->rect.top, di->rect.left + end, di->rect.bottom); 266 bgrect = di->bgRect; 267 OffsetRect(&bgrect, -bgrect.left, -bgrect.top); 268 269 DrawThemeBackground (di->theme, di->hdc, PP_BAR, 0, &bgrect, &r); 270 } 271 272 /* draw themed vertical background from 'start' to 'end' */ 273 static void draw_theme_bkg_V (const ProgressDrawInfo* di, int start, int end) 274 { 275 RECT bgrect, r; 276 277 SetRect(&r, di->rect.left, di->rect.bottom - end, di->rect.right, di->rect.bottom - start); 278 bgrect = di->bgRect; 279 OffsetRect(&bgrect, -bgrect.left, -bgrect.top); 280 281 DrawThemeBackground (di->theme, di->hdc, PP_BARVERT, 0, &bgrect, &r); 282 } 283 284 /* drawing functions for themed style */ 285 static const ProgressDrawProc drawProcThemed[8] = { 286 /* Smooth */ 287 /* Horizontal */ 288 draw_theme_bar_H, draw_theme_bkg_H, 289 /* Vertical */ 290 draw_theme_bar_V, draw_theme_bkg_V, 291 /* Chunky */ 292 /* Horizontal */ 293 draw_theme_bar_H, draw_theme_bkg_H, 294 /* Vertical */ 295 draw_theme_bar_V, draw_theme_bkg_V, 296 }; 297 298 /*********************************************************************** 299 * PROGRESS_Draw 300 * Draws the progress bar. 301 */ 302 static LRESULT PROGRESS_Draw (PROGRESS_INFO *infoPtr, HDC hdc) 303 { 304 int barSize; 305 DWORD dwStyle; 306 BOOL barSmooth; 307 const ProgressDrawProc* drawProcs; 308 ProgressDrawInfo pdi; 309 310 TRACE("(infoPtr=%p, hdc=%p)\n", infoPtr, hdc); 311 312 pdi.hdc = hdc; 313 pdi.theme = GetWindowTheme (infoPtr->Self); 314 315 /* get the required bar brush */ 316 if (infoPtr->ColorBar == CLR_DEFAULT) 317 pdi.hbrBar = GetSysColorBrush(COLOR_HIGHLIGHT); 318 else 319 pdi.hbrBar = CreateSolidBrush (infoPtr->ColorBar); 320 321 if (infoPtr->ColorBk == CLR_DEFAULT) 322 pdi.hbrBk = GetSysColorBrush(COLOR_3DFACE); 323 else 324 pdi.hbrBk = CreateSolidBrush(infoPtr->ColorBk); 325 326 /* get the window style */ 327 dwStyle = GetWindowLongW (infoPtr->Self, GWL_STYLE); 328 329 /* get client rectangle */ 330 GetClientRect (infoPtr->Self, &pdi.rect); 331 if (!pdi.theme) { 332 FrameRect( hdc, &pdi.rect, pdi.hbrBk ); 333 InflateRect(&pdi.rect, -1, -1); 334 } 335 else 336 { 337 RECT cntRect; 338 int part = (dwStyle & PBS_VERTICAL) ? PP_BARVERT : PP_BAR; 339 340 GetThemeBackgroundContentRect (pdi.theme, hdc, part, 0, &pdi.rect, 341 &cntRect); 342 343 /* Exclude content rect - content background will be drawn later */ 344 ExcludeClipRect (hdc, cntRect.left, cntRect.top, 345 cntRect.right, cntRect.bottom); 346 if (IsThemeBackgroundPartiallyTransparent (pdi.theme, part, 0)) 347 DrawThemeParentBackground (infoPtr->Self, hdc, NULL); 348 DrawThemeBackground (pdi.theme, hdc, part, 0, &pdi.rect, NULL); 349 SelectClipRgn (hdc, NULL); 350 pdi.rect = cntRect; 351 } 352 353 /* compute some drawing parameters */ 354 barSmooth = (dwStyle & PBS_SMOOTH) && !pdi.theme; 355 drawProcs = &((pdi.theme ? drawProcThemed : drawProcClassic)[(barSmooth ? 0 : 4) 356 + ((dwStyle & PBS_VERTICAL) ? 2 : 0)]); 357 barSize = get_bar_size( dwStyle, &pdi.rect ); 358 if (pdi.theme) 359 { 360 GetWindowRect( infoPtr->Self, &pdi.bgRect ); 361 MapWindowPoints( infoPtr->Self, 0, (POINT*)&pdi.bgRect, 2 ); 362 } 363 364 if (!barSmooth) 365 pdi.ledW = get_led_size( infoPtr, dwStyle, &pdi.rect); 366 pdi.ledGap = get_led_gap( infoPtr ); 367 368 if (dwStyle & PBS_MARQUEE) 369 { 370 const int ledW = !barSmooth ? (pdi.ledW + pdi.ledGap) : 1; 371 const int leds = (barSize + ledW - 1) / ledW; 372 const int ledMEnd = infoPtr->MarqueePos + MARQUEE_LEDS; 373 374 if (ledMEnd > leds) 375 { 376 /* case 1: the marquee bar extends over the end and wraps around to 377 * the start */ 378 const int gapStart = max((ledMEnd - leds) * ledW, 0); 379 const int gapEnd = min(infoPtr->MarqueePos * ledW, barSize); 380 381 drawProcs[0]( &pdi, 0, gapStart); 382 drawProcs[1]( &pdi, gapStart, gapEnd); 383 drawProcs[0]( &pdi, gapEnd, barSize); 384 } 385 else 386 { 387 /* case 2: the marquee bar is between start and end */ 388 const int barStart = infoPtr->MarqueePos * ledW; 389 const int barEnd = min (ledMEnd * ledW, barSize); 390 391 drawProcs[1]( &pdi, 0, barStart); 392 drawProcs[0]( &pdi, barStart, barEnd); 393 drawProcs[1]( &pdi, barEnd, barSize); 394 } 395 } 396 else 397 { 398 int barEnd = get_bar_position( infoPtr, dwStyle, &pdi.rect, 399 infoPtr->CurVal); 400 if (!barSmooth) 401 { 402 const int ledW = pdi.ledW + pdi.ledGap; 403 barEnd = min (((barEnd + ledW - 1) / ledW) * ledW, barSize); 404 } 405 drawProcs[0]( &pdi, 0, barEnd); 406 drawProcs[1]( &pdi, barEnd, barSize); 407 } 408 409 /* delete bar brush */ 410 if (infoPtr->ColorBar != CLR_DEFAULT) DeleteObject (pdi.hbrBar); 411 if (infoPtr->ColorBk != CLR_DEFAULT) DeleteObject (pdi.hbrBk); 412 413 return 0; 414 } 415 416 /*********************************************************************** 417 * PROGRESS_Paint 418 * Draw the progress bar. The background need not be erased. 419 * If dc!=0, it draws on it 420 */ 421 static LRESULT PROGRESS_Paint (PROGRESS_INFO *infoPtr, HDC hdc) 422 { 423 PAINTSTRUCT ps; 424 if (hdc) return PROGRESS_Draw (infoPtr, hdc); 425 hdc = BeginPaint (infoPtr->Self, &ps); 426 PROGRESS_Draw (infoPtr, hdc); 427 EndPaint (infoPtr->Self, &ps); 428 return 0; 429 } 430 431 432 /*********************************************************************** 433 * Advance marquee progress by one step. 434 */ 435 static void PROGRESS_UpdateMarquee (PROGRESS_INFO *infoPtr) 436 { 437 LONG style = GetWindowLongW (infoPtr->Self, GWL_STYLE); 438 RECT rect; 439 int ledWidth, leds; 440 HTHEME theme = GetWindowTheme (infoPtr->Self); 441 BOOL smooth = (style & PBS_SMOOTH) && !theme; 442 443 get_client_rect (infoPtr->Self, &rect); 444 445 if (smooth) 446 ledWidth = 1; 447 else 448 ledWidth = get_led_size( infoPtr, style, &rect ) + get_led_gap( infoPtr ); 449 450 leds = (get_bar_size( style, &rect ) + ledWidth - 1) / 451 ledWidth; 452 453 /* increment the marquee progress */ 454 if (++infoPtr->MarqueePos >= leds) 455 infoPtr->MarqueePos = 0; 456 457 InvalidateRect(infoPtr->Self, &rect, TRUE); 458 UpdateWindow(infoPtr->Self); 459 } 460 461 462 /*********************************************************************** 463 * PROGRESS_CoercePos 464 * Makes sure the current position (CurVal) is within bounds. 465 */ 466 static void PROGRESS_CoercePos(PROGRESS_INFO *infoPtr) 467 { 468 if(infoPtr->CurVal < infoPtr->MinVal) 469 infoPtr->CurVal = infoPtr->MinVal; 470 if(infoPtr->CurVal > infoPtr->MaxVal) 471 infoPtr->CurVal = infoPtr->MaxVal; 472 } 473 474 475 /*********************************************************************** 476 * PROGRESS_SetFont 477 * Set new Font for progress bar 478 */ 479 static HFONT PROGRESS_SetFont (PROGRESS_INFO *infoPtr, HFONT hFont, BOOL bRedraw) 480 { 481 HFONT hOldFont = infoPtr->Font; 482 infoPtr->Font = hFont; 483 /* Since infoPtr->Font is not used, there is no need for repaint */ 484 return hOldFont; 485 } 486 487 static DWORD PROGRESS_SetRange (PROGRESS_INFO *infoPtr, int low, int high) 488 { 489 DWORD res = MAKELONG(LOWORD(infoPtr->MinVal), LOWORD(infoPtr->MaxVal)); 490 491 /* if nothing changes, simply return */ 492 if(infoPtr->MinVal == low && infoPtr->MaxVal == high) return res; 493 494 infoPtr->MinVal = low; 495 infoPtr->MaxVal = high; 496 PROGRESS_CoercePos(infoPtr); 497 InvalidateRect(infoPtr->Self, NULL, TRUE); 498 return res; 499 } 500 501 static UINT PROGRESS_SetPos (PROGRESS_INFO *infoPtr, INT pos) 502 { 503 DWORD style = GetWindowLongW(infoPtr->Self, GWL_STYLE); 504 505 if (style & PBS_MARQUEE) 506 { 507 PROGRESS_UpdateMarquee(infoPtr); 508 return 1; 509 } 510 else 511 { 512 UINT oldVal; 513 oldVal = infoPtr->CurVal; 514 if (oldVal != pos) { 515 infoPtr->CurVal = pos; 516 PROGRESS_CoercePos(infoPtr); 517 TRACE("PBM_SETPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal); 518 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal ); 519 UpdateWindow( infoPtr->Self ); 520 } 521 return oldVal; 522 } 523 } 524 525 /*********************************************************************** 526 * ProgressWindowProc 527 */ 528 static LRESULT WINAPI ProgressWindowProc(HWND hwnd, UINT message, 529 WPARAM wParam, LPARAM lParam) 530 { 531 PROGRESS_INFO *infoPtr; 532 static const WCHAR themeClass[] = {'P','r','o','g','r','e','s','s',0}; 533 HTHEME theme; 534 535 TRACE("hwnd=%p msg=%04x wparam=%lx lParam=%lx\n", hwnd, message, wParam, lParam); 536 537 infoPtr = (PROGRESS_INFO *)GetWindowLongPtrW(hwnd, 0); 538 539 if (!infoPtr && message != WM_CREATE) 540 return DefWindowProcW( hwnd, message, wParam, lParam ); 541 542 switch(message) { 543 case WM_CREATE: 544 { 545 DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE); 546 547 theme = OpenThemeData (hwnd, themeClass); 548 549 dwExStyle &= ~(WS_EX_CLIENTEDGE | WS_EX_WINDOWEDGE); 550 if (!theme) dwExStyle |= WS_EX_STATICEDGE; 551 SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle); 552 /* Force recalculation of a non-client area */ 553 SetWindowPos(hwnd, 0, 0, 0, 0, 0, 554 SWP_FRAMECHANGED | SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE); 555 556 /* allocate memory for info struct */ 557 infoPtr = heap_alloc_zero (sizeof(*infoPtr)); 558 if (!infoPtr) return -1; 559 SetWindowLongPtrW (hwnd, 0, (DWORD_PTR)infoPtr); 560 561 /* initialize the info struct */ 562 infoPtr->Self = hwnd; 563 infoPtr->MinVal = 0; 564 infoPtr->MaxVal = 100; 565 infoPtr->CurVal = 0; 566 infoPtr->Step = 10; 567 infoPtr->MarqueePos = 0; 568 infoPtr->Marquee = FALSE; 569 infoPtr->ColorBar = CLR_DEFAULT; 570 infoPtr->ColorBk = CLR_DEFAULT; 571 infoPtr->Font = 0; 572 573 TRACE("Progress Ctrl creation, hwnd=%p\n", hwnd); 574 return 0; 575 } 576 577 case WM_DESTROY: 578 TRACE("Progress Ctrl destruction, hwnd=%p\n", hwnd); 579 heap_free (infoPtr); 580 SetWindowLongPtrW(hwnd, 0, 0); 581 theme = GetWindowTheme (hwnd); 582 CloseThemeData (theme); 583 return 0; 584 585 case WM_ERASEBKGND: 586 return 1; 587 588 case WM_GETFONT: 589 return (LRESULT)infoPtr->Font; 590 591 case WM_SETFONT: 592 return (LRESULT)PROGRESS_SetFont(infoPtr, (HFONT)wParam, (BOOL)lParam); 593 594 case WM_PRINTCLIENT: 595 case WM_PAINT: 596 return PROGRESS_Paint (infoPtr, (HDC)wParam); 597 598 case WM_TIMER: 599 if (wParam == ID_MARQUEE_TIMER) 600 PROGRESS_UpdateMarquee (infoPtr); 601 return 0; 602 603 case WM_THEMECHANGED: 604 { 605 DWORD dwExStyle = GetWindowLongW (hwnd, GWL_EXSTYLE); 606 607 theme = GetWindowTheme (hwnd); 608 CloseThemeData (theme); 609 theme = OpenThemeData (hwnd, themeClass); 610 611 /* WS_EX_STATICEDGE disappears when the control is themed */ 612 if (theme) 613 dwExStyle &= ~WS_EX_STATICEDGE; 614 else 615 dwExStyle |= WS_EX_STATICEDGE; 616 SetWindowLongW (hwnd, GWL_EXSTYLE, dwExStyle); 617 618 InvalidateRect (hwnd, NULL, FALSE); 619 return 0; 620 } 621 622 case PBM_DELTAPOS: 623 { 624 INT oldVal; 625 oldVal = infoPtr->CurVal; 626 if(wParam != 0) { 627 infoPtr->CurVal += (INT)wParam; 628 PROGRESS_CoercePos (infoPtr); 629 TRACE("PBM_DELTAPOS: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal); 630 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal ); 631 UpdateWindow( infoPtr->Self ); 632 } 633 return oldVal; 634 } 635 636 case PBM_SETPOS: 637 return PROGRESS_SetPos(infoPtr, wParam); 638 639 case PBM_SETRANGE: 640 return PROGRESS_SetRange (infoPtr, (int)LOWORD(lParam), (int)HIWORD(lParam)); 641 642 case PBM_SETSTEP: 643 { 644 INT oldStep; 645 oldStep = infoPtr->Step; 646 infoPtr->Step = (INT)wParam; 647 return oldStep; 648 } 649 650 case PBM_GETSTEP: 651 return infoPtr->Step; 652 653 case PBM_STEPIT: 654 { 655 INT oldVal; 656 oldVal = infoPtr->CurVal; 657 infoPtr->CurVal += infoPtr->Step; 658 if (infoPtr->CurVal > infoPtr->MaxVal) 659 { 660 infoPtr->CurVal = (infoPtr->CurVal - infoPtr->MinVal) % (infoPtr->MaxVal - infoPtr->MinVal) + infoPtr->MinVal; 661 } 662 if (infoPtr->CurVal < infoPtr->MinVal) 663 { 664 infoPtr->CurVal = (infoPtr->CurVal - infoPtr->MinVal) % (infoPtr->MaxVal - infoPtr->MinVal) + infoPtr->MaxVal; 665 } 666 if(oldVal != infoPtr->CurVal) 667 { 668 TRACE("PBM_STEPIT: current pos changed from %d to %d\n", oldVal, infoPtr->CurVal); 669 PROGRESS_Invalidate( infoPtr, oldVal, infoPtr->CurVal ); 670 UpdateWindow( infoPtr->Self ); 671 } 672 return oldVal; 673 } 674 675 case PBM_SETRANGE32: 676 return PROGRESS_SetRange (infoPtr, (int)wParam, (int)lParam); 677 678 case PBM_GETRANGE: 679 if (lParam) { 680 ((PPBRANGE)lParam)->iLow = infoPtr->MinVal; 681 ((PPBRANGE)lParam)->iHigh = infoPtr->MaxVal; 682 } 683 return wParam ? infoPtr->MinVal : infoPtr->MaxVal; 684 685 case PBM_GETPOS: 686 return infoPtr->CurVal; 687 688 case PBM_SETBARCOLOR: 689 { 690 COLORREF clr = infoPtr->ColorBar; 691 692 infoPtr->ColorBar = (COLORREF)lParam; 693 InvalidateRect(hwnd, NULL, TRUE); 694 return clr; 695 } 696 697 case PBM_GETBARCOLOR: 698 return infoPtr->ColorBar; 699 700 case PBM_SETBKCOLOR: 701 { 702 COLORREF clr = infoPtr->ColorBk; 703 704 infoPtr->ColorBk = (COLORREF)lParam; 705 InvalidateRect(hwnd, NULL, TRUE); 706 return clr; 707 } 708 709 case PBM_GETBKCOLOR: 710 return infoPtr->ColorBk; 711 712 case PBM_SETSTATE: 713 if(wParam != PBST_NORMAL) 714 FIXME("state %04lx not yet handled\n", wParam); 715 return PBST_NORMAL; 716 717 case PBM_GETSTATE: 718 return PBST_NORMAL; 719 720 case PBM_SETMARQUEE: 721 if(wParam != 0) 722 { 723 UINT period = lParam ? (UINT)lParam : DEFAULT_MARQUEE_PERIOD; 724 infoPtr->Marquee = TRUE; 725 SetTimer(infoPtr->Self, ID_MARQUEE_TIMER, period, NULL); 726 } 727 else 728 { 729 infoPtr->Marquee = FALSE; 730 KillTimer(infoPtr->Self, ID_MARQUEE_TIMER); 731 } 732 return infoPtr->Marquee; 733 734 default: 735 if ((message >= WM_USER) && (message < WM_APP) && !COMCTL32_IsReflectedMessage(message)) 736 ERR("unknown msg %04x wp=%04lx lp=%08lx\n", message, wParam, lParam ); 737 return DefWindowProcW( hwnd, message, wParam, lParam ); 738 } 739 } 740 741 742 /*********************************************************************** 743 * PROGRESS_Register [Internal] 744 * 745 * Registers the progress bar window class. 746 */ 747 void PROGRESS_Register (void) 748 { 749 WNDCLASSW wndClass; 750 751 ZeroMemory (&wndClass, sizeof(wndClass)); 752 wndClass.style = CS_GLOBALCLASS | CS_VREDRAW | CS_HREDRAW; 753 wndClass.lpfnWndProc = ProgressWindowProc; 754 wndClass.cbClsExtra = 0; 755 wndClass.cbWndExtra = sizeof (PROGRESS_INFO *); 756 wndClass.hCursor = LoadCursorW (0, (LPWSTR)IDC_ARROW); 757 wndClass.lpszClassName = PROGRESS_CLASSW; 758 759 RegisterClassW (&wndClass); 760 } 761 762 763 /*********************************************************************** 764 * PROGRESS_Unregister [Internal] 765 * 766 * Unregisters the progress bar window class. 767 */ 768 void PROGRESS_Unregister (void) 769 { 770 UnregisterClassW (PROGRESS_CLASSW, NULL); 771 } 772