text: //////////////////////////////////////////////////////////////////////////
  // Slider.cpp: Custom slider control.
  // 
  // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
  // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
  // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
  // PARTICULAR PURPOSE.
  //
  // Copyright (c) Microsoft Corporation. All rights reserved.
  //
  //////////////////////////////////////////////////////////////////////////
  
  #include "MFPlayer.h"
  #include <windowsx.h>
  
  namespace SliderControl
  {
  
      PCWSTR ClassName = L"SLIDER_CLASS";
  
      PCWSTR InstanceData = L"SLIDER_PROP";
  
      const LONG DEFAULT_MIN = 0;
      const LONG DEFAULT_MAX = 100;
      const LONG DEFAULT_THUMB = 0;
  
  
      struct Slider_Info
      {
          // Logical units
          LONG    posMin;     // minimum logical position
          LONG    posMax;     // maximum logical position
          LONG    posThumb;   // current logical position
  
          // Client area
          SIZE    pxThumbSize;    // real size of thumb bitmap (constant until bitmap changes
          RECT    rcThumb;        // client area of the thumb (changes with position)
  
          // state    
          BOOL    bThumbDown;     // User is dragging the thumb?
  
          // GDI objects
          HBRUSH  hBackground;
          HBITMAP hbmThumb;       // Thumb bitmap
      };
  
  
      LRESULT CALLBACK Slider_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  
      // Message handlers
      LRESULT OnCreate(HWND hwnd); 
      LRESULT OnNcDestroy(HWND hwnd, Slider_Info *pInfo); 
      LRESULT OnPaint(HWND hwnd, Slider_Info *pInfo); 
      LRESULT OnLButtonDown(HWND hwnd, LONG x, LONG y, Slider_Info *pInfo);
      LRESULT OnLButtonUp(HWND hwnd, LONG x, LONG y, Slider_Info *pInfo);
      LRESULT OnMouseMove(HWND hwnd, LONG x, LONG y, Slider_Info *pInfo);
      LRESULT OnReleaseSlider(HWND hwnd, Slider_Info *pInfo);
  
      // Private message handlers
      LRESULT OnSetThumbBitmap(HWND hwnd, WORD nID, Slider_Info *pInfo);
      LRESULT OnSetBackground(HWND hwnd, HBRUSH hBrush, Slider_Info *pInfo);
      LRESULT OnSetMinMax(HWND hwnd, LONG posMin, LONG posMax, Slider_Info *pInfo);   
      LRESULT OnSetPosition(HWND hwnd, LONG pos, Slider_Info *pInfo);
      LRESULT OnGetPosition(HWND hwnd, Slider_Info *pInfo);
  
  
      //--------------------------------------------------------------------------------------
      // SetInfo
      // Description: Store the control's instance information.
      //--------------------------------------------------------------------------------------
  
      inline BOOL SetInfo(HWND hwnd, Slider_Info *pInfo)
      {
          return SetProp(hwnd, InstanceData, pInfo);
      }
  
      //--------------------------------------------------------------------------------------
      // GetInfo
      // Description: Get the control's instance information.
      //--------------------------------------------------------------------------------------
  
      inline Slider_Info * GetInfo(HWND hwnd)
      {
          return (Slider_Info*)GetProp(hwnd, InstanceData);
      }
  
      //--------------------------------------------------------------------------------------
      // GetThumbRect
      // Description: Get the current position of the thumb rectangle.
      // 
      // The position is updated in the rcThumb member of pInfo.
      //--------------------------------------------------------------------------------------
  
      void GetThumbRect(HWND hwnd, Slider_Info *pInfo)
      {
          // 1. Convert logical position to pixels:
          //      logical width = max position - min position
          //      pixel width = client area - thumb width
          //      logical thumb position = current position - min position
          //      pixel thumb position = (logical thumb position / logical width) * pixel width
  
          RECT rc;
          GetClientRect(hwnd, &rc);
  
          LONG logWidth = pInfo->posMax - pInfo->posMin;
          LONG pixWidth = Width(rc) - pInfo->pxThumbSize.cx;
          LONG logPosition = pInfo->posThumb - pInfo->posMin;
          LONG left = MulDiv(logPosition, pixWidth, logWidth);    
  
          // 2. Center vertically
          LONG top = (Height(rc) - pInfo->pxThumbSize.cy) / 2;
      
          SetRect(
              &pInfo->rcThumb,
              left,
              top,
              left + pInfo->pxThumbSize.cx,
              top + pInfo->pxThumbSize.cy
              );
      }
  
      //--------------------------------------------------------------------------------------
      // PixelToLogical
      // Description: Convert a pixel position to a logical position.
      // 
      // Returns the logical position.
      //--------------------------------------------------------------------------------------
  
      LONG PixelToLogical(HWND hwnd, LONG x, Slider_Info *pInfo)
      {
          // % of pixel width * logical width, max = logical max
  
          // (x / pixel width) * logical width + logical min
  
          RECT rc;
          GetClientRect(hwnd, &rc);
  
          LONG pixWidth = Width(rc);
          LONG logWidth = pInfo->posMax - pInfo->posMin;
          LONG pos = MulDiv(x, logWidth, pixWidth) + pInfo->posMin;
  
          // clamp to slider min and max
          return max(pInfo->posMin, min(pos, pInfo->posMax));
      }
  
      //--------------------------------------------------------------------------------------
      // NotifyParent
      // Description: Send the parent window a WM_NOTIFY message with our current status.
      // 
      // hwnd: Control window.
      // code: WM_NOTIFY code. (One of the SLIDER_NOTIFY_xxx constants.)
      // pInfo: Instance data.
      //--------------------------------------------------------------------------------------
      void NotifyParent(HWND hwnd, UINT code, Slider_Info *pInfo)
      {
          HWND hParent = GetParent(hwnd);
  
          if (hParent)
          {   
              NMSLIDER_INFO nminfo;
  
              nminfo.hdr.hwndFrom = hwnd;
              nminfo.hdr.idFrom = (UINT_PTR)GetMenu(hwnd);  
              nminfo.hdr.code = code;
              nminfo.bSelected = pInfo->bThumbDown;
              nminfo.position = pInfo->posThumb;
  
              SendMessage(hParent, WM_NOTIFY, (WPARAM)nminfo.hdr.idFrom, (LPARAM)&nminfo);
          }
      }
  
      //--------------------------------------------------------------------------------------
      // Slider_WndProc
      // Description: Window proc for the control.
      //--------------------------------------------------------------------------------------
  
  #include <strsafe.h>
      LRESULT CALLBACK Slider_WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
      {
          Slider_Info * const pInfo = GetInfo(hwnd);
  
          switch (uMsg)
          {
          case WM_CREATE:
              return OnCreate(hwnd);
  
          case WM_PAINT:
              return OnPaint(hwnd, pInfo);
  
          case WM_NCDESTROY:
              return OnNcDestroy(hwnd, pInfo);
  
          case WM_LBUTTONDOWN:
              return OnLButtonDown(hwnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pInfo);
  
          case WM_LBUTTONUP:
              return OnLButtonUp(hwnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pInfo);
  
          case WM_MOUSEMOVE:
              return OnMouseMove(hwnd, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pInfo);
  
          case WM_ENABLE:
              if (wParam == FALSE) // Window is disabled. Stop tracking.
              {
                  return OnReleaseSlider(hwnd, pInfo);
              }
              break;
  
          case WM_CAPTURECHANGED:
             // The window lost focus while the slider was tracking the mouse OR 
             // the slider released the mouse capture itself.
             return OnReleaseSlider(hwnd, pInfo);
  
              
          // Custom messages
          case WM_SLIDER_SET_THUMB_BITMAP:
              return OnSetThumbBitmap(hwnd, (WORD)wParam, pInfo);
  
          case WM_SLIDER_SET_BACKGROUND:
              return OnSetBackground(hwnd, (HBRUSH)wParam, pInfo);
  
          case WM_SLIDER_SET_MIN_MAX:
              return OnSetMinMax(hwnd, (LONG)wParam, (LONG)lParam, pInfo);
  
          case WM_SLIDER_SET_POSITION:
              return OnSetPosition(hwnd, (LONG)wParam, pInfo);
  
          case WM_SLIDER_GET_POSITION:
              return OnGetPosition(hwnd, pInfo);
  
          default:
              return DefWindowProc(hwnd, uMsg, wParam, lParam);
          }
  
          return 0;
      };
  
      
      LRESULT OnCreate(HWND hwnd)
      {
          Slider_Info *pInfo = new (std::nothrow) Slider_Info;
          if (!pInfo)
          {
              return (LRESULT)-1;
          }
  
          ZeroMemory(pInfo, sizeof(Slider_Info));
  
          pInfo->posMin = DEFAULT_MIN;
          pInfo->posMax = DEFAULT_MAX;
          pInfo->posThumb = DEFAULT_THUMB;
  
          pInfo->bThumbDown = FALSE;
  
          pInfo->hBackground = CreateSolidBrush(RGB(0xFF, 0x80, 0x80));
  
          if (SetInfo(hwnd, pInfo))
          {
              return 0;
          }
          else
          {
              delete pInfo;
              return -1;
          }
      }
  
      LRESULT OnNcDestroy(HWND /*hwnd*/, Slider_Info *pInfo)
      {
          if (pInfo)
          {
              DeleteObject(pInfo->hBackground);
              DeleteObject(pInfo->hbmThumb);
              delete pInfo;
          }
          return 0;
      }
  
  
      LRESULT OnPaint(HWND hwnd, Slider_Info *pInfo)
      {
          PAINTSTRUCT ps;
          HDC hdc;
  
          hdc = BeginPaint(hwnd, &ps);
  
          // Draw the background
          if (pInfo->hBackground)
          {
              FillRect(hdc, &ps.rcPaint, pInfo->hBackground);
          }
  
          // Draw the thumb
  
          if (pInfo->hbmThumb)
          {
              HDC hdcCompat = CreateCompatibleDC(hdc); 
              SelectObject(hdcCompat, pInfo->hbmThumb); 
  
              (void)BitBlt(
                  hdc, 
                  pInfo->rcThumb.left, 
                  pInfo->rcThumb.top, 
                  pInfo->pxThumbSize.cx,
                  pInfo->pxThumbSize.cy,
                  hdcCompat,
                  0, 0,
                  SRCCOPY
                  );
  
              DeleteDC(hdcCompat);
          }
  
          EndPaint(hwnd, &ps);
          return 0;
      }
  
  
      void SetSliderPosition(HWND hwnd, LONG pos, Slider_Info *pInfo)
      {
          // Invalidate the old thumb rect
          InvalidateRect(hwnd, &pInfo->rcThumb, FALSE);
  
          pInfo->posThumb = pos;
  
          GetThumbRect(hwnd, pInfo);
  
          // Invalidate the new thumb rect
          InvalidateRect(hwnd, &pInfo->rcThumb, FALSE);
      }
  
  
  
      LRESULT OnLButtonDown(HWND hwnd, LONG x, LONG /*y*/, Slider_Info *pInfo)
      {
          // Move the slider to the mouse position.
          SetSliderPosition(hwnd, PixelToLogical(hwnd, x, pInfo), pInfo);
  
          // Set the thumb-down flag.
          pInfo->bThumbDown = TRUE;
  
          // Start capturing mouse moves so we can update the slider position.
          SetCapture(hwnd);
  
          // Notify the owner window that the control was selected.
          NotifyParent(hwnd, SLIDER_NOTIFY_SELECT, pInfo);
  
          return 0;
      }
  
      LRESULT OnLButtonUp(HWND hwnd, LONG /*x*/, LONG /*y*/, Slider_Info *pInfo)
      {
          return OnReleaseSlider(hwnd, pInfo);
      }
  
      LRESULT OnMouseMove(HWND hwnd, LONG x, LONG /*y*/, Slider_Info *pInfo)
      {
          // If the control is selected, update the slider position
          // and notify the owner window.
          if (pInfo->bThumbDown)
          {
              SetSliderPosition(hwnd, PixelToLogical(hwnd, x, pInfo), pInfo);
  
              NotifyParent(hwnd, SLIDER_NOTIFY_DRAG, pInfo);
  
          }
          return 0;
      }
  
      // OnReleaseSlider: Stop tracking the slider movement.
      LRESULT OnReleaseSlider(HWND hwnd, Slider_Info *pInfo)
      {
          if (pInfo->bThumbDown)
          {
              // Reset the thumb-down flag.
              pInfo->bThumbDown = FALSE;
  
              InvalidateRect(hwnd, &pInfo->rcThumb, FALSE);
  
              // Stop capturing mouse moves.
              ReleaseCapture();
  
              // Notify the owner window that the control was deselected.
              NotifyParent(hwnd, SLIDER_NOTIFY_RELEASE, pInfo);
          }
          return 0;
      }
  
      //--------------------------------------------------------------------------------------
      // OnSetThumbBitmap
      // Description: Sets the bitmap image for the slider thumb.
      // 
      // Handler for WM_SLIDER_SET_THUMB_BITMAP message.
      //--------------------------------------------------------------------------------------
  
      LRESULT OnSetThumbBitmap(HWND hwnd, WORD nID, Slider_Info *pInfo)
      {
          HBITMAP hbm = LoadBitmap(GetInstance(), MAKEINTRESOURCE(nID));
  
          if (hbm == NULL)
          {
              return FALSE;
          }
  
          BITMAP bm;
          GetObject(hbm, sizeof(BITMAP), &bm);
  
          pInfo->pxThumbSize.cx = bm.bmWidth;
          pInfo->pxThumbSize.cy = bm.bmHeight;
  
          if (pInfo->hbmThumb)
          {
              DeleteObject(pInfo->hbmThumb);
          }
  
          pInfo->hbmThumb = hbm;
  
          GetThumbRect(hwnd, pInfo);
  
          return TRUE;
      }
  
      //--------------------------------------------------------------------------------------
      // OnSetBackground
      // Description: Sets the background brush.
      // 
      // Handler for WM_SLIDER_SET_BACKGROUND message.
      //--------------------------------------------------------------------------------------
  
      LRESULT OnSetBackground(HWND /*hwnd*/, HBRUSH hBrush, Slider_Info *pInfo)
      {
          if (pInfo->hBackground)
          {
              DeleteObject(pInfo->hBackground);
          }
  
          pInfo->hBackground = hBrush;
      
          return TRUE;
      }
  
  
      //--------------------------------------------------------------------------------------
      // OnSetMinMax
      // Description: Sets the slider range.
      // 
      // Handler for WM_SLIDER_SET_MIN_MAX message.
      //--------------------------------------------------------------------------------------
      LRESULT OnSetMinMax(HWND hwnd, LONG posMin, LONG posMax, Slider_Info *pInfo)
      {
          pInfo->posMin = posMin;
          pInfo->posMax = posMax;
  
          if (pInfo->posThumb < posMin)
          {
              SetSliderPosition(hwnd, posMin, pInfo);
          }
          else if (pInfo->posThumb > posMax)
          {
              SetSliderPosition(hwnd, posMax, pInfo);
          }
          return TRUE;
      }
  
      //--------------------------------------------------------------------------------------
      // OnSetPosition
      // Description: Sets the slider range.
      // 
      // Handler for WM_SLIDER_SET_POSITION message.
      //--------------------------------------------------------------------------------------
  
      LRESULT OnSetPosition(HWND hwnd, LONG pos, Slider_Info *pInfo)
      {
          if (pos < pInfo->posMin || pos > pInfo->posMax)
          {
              return FALSE;
          }
          else
          {
              SetSliderPosition(hwnd, pos, pInfo);
              return TRUE;
          }
      }
  
      //--------------------------------------------------------------------------------------
      // OnSetPosition
      // Description: Sets the slider range.
      // 
      // Handler for WM_SLIDER_GET_POSITION message.
      //--------------------------------------------------------------------------------------
  
      LRESULT OnGetPosition(HWND /*hwnd*/, Slider_Info *pInfo)
      {
          return pInfo->posThumb;
      }
  
  }  // namespace SliderControl
  
  
  
  
  //--------------------------------------------------------------------------------------
  // Slider_Init
  // Description: Initializes the slider window class.
  // 
  // Call this function before using the slider control.
  //--------------------------------------------------------------------------------------
  
  HRESULT Slider_Init()
  {
      WNDCLASSEX wce;
      ZeroMemory(&wce, sizeof(wce));
  
      wce.cbSize = sizeof(WNDCLASSEX);
      wce.lpfnWndProc = SliderControl::Slider_WndProc;
      wce.hInstance = GetInstance();
      wce.lpszClassName = SliderControl::ClassName;
      wce.cbWndExtra = sizeof(SliderControl::Slider_Info);        // Reserve space for slider instance data
  
      ATOM a = RegisterClassEx(&wce);
  
      if (a == 0)
      {
          return __HRESULT_FROM_WIN32(GetLastError());
      }
      else
      {
          return S_OK;
      }
  }
  
  
  
  
  