home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / atl / cdinfo / cdinfo1.cpp < prev    next >
C/C++ Source or Header  |  1998-03-26  |  10KB  |  401 lines

  1. // CDInfo1.cpp : Implementation of CCDInfo
  2. //
  3. // This is a part of the Active Template Library.
  4. // Copyright (C) 1996-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Active Template Library Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Active Template Library product.
  12.  
  13. #include "stdafx.h"
  14. #include <math.h>
  15.  
  16. #include "CDInfo.h"
  17. #include "CDInfo1.h"
  18.  
  19. /////////////////////////////////////////////////////////////////////////////
  20. // CCDInfo
  21.  
  22. COLORREF CCDInfo::m_colSegment[] =
  23. {
  24.     RGB(0x00,0x00,0x00),
  25.     RGB(0xff,0x00,0x00),
  26.     RGB(0x00,0xff,0x00),
  27.     RGB(0x00,0x00,0xff),
  28.     RGB(0xff,0xff,0x00),
  29.     RGB(0x00,0xff,0xff),
  30.     RGB(0xff,0x00,0xff),
  31.     RGB(0xff,0xff,0xff),
  32.     RGB(0x7f,0x7f,0x7f),
  33.     RGB(0x7f,0x00,0x00),
  34.     RGB(0x00,0x7f,0x00),
  35.     RGB(0x00,0x00,0x7f),
  36.     RGB(0x7f,0x7f,0x00),
  37.     RGB(0x00,0x7f,0x7f),
  38.     RGB(0x7f,0x00,0x7f),
  39.     RGB(0x7f,0x7f,0x7f)
  40. };
  41.  
  42. HRESULT CCDInfo::OnDraw(ATL_DRAWINFO& di)
  43. {
  44.     if (di.dwDrawAspect == DVASPECT_CONTENT)
  45.     {
  46.         ATLTRACE(_T("Ondraw\n"));
  47.         DrawOffScreen(di.hdcDraw, *(RECT*)di.prcBounds);
  48.     }
  49.     return 0;
  50. }
  51.  
  52. void CCDInfo::DrawOffScreen(HDC hdc, RECT rc)
  53. {
  54.     HBITMAP hbmMem, hbmOld;
  55.     HDC     hdcMem;
  56.     RECT    rcDP;
  57.  
  58.     // First make sure we have the coordinates in device units and we
  59.     // are offset from 0,0
  60.  
  61.     LPtoDP(hdc, (LPPOINT)&rc, 2);
  62.     rcDP = rc;
  63.     OffsetRect(&rc, -rc.left, -rc.top);
  64.  
  65.     // Create a DC to draw into
  66.     hdcMem = CreateCompatibleDC(hdc);
  67.  
  68.     // Create a bitmap big enough for our drawing
  69.     hbmMem = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top);
  70.  
  71.     // Select the bitmap into our new DC
  72.     hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem);
  73.  
  74.     // If we can get the ambient background color from the container then we
  75.     // will use it.
  76.  
  77.     CComVariant var;
  78.     if (SUCCEEDED(m_spAmbientDispatch.GetProperty(DISPID_AMBIENT_BACKCOLOR,
  79.             &var)))
  80.     {
  81.         LOGBRUSH    logbrush;
  82.         COLORREF    col;
  83.         logbrush.lbStyle = BS_SOLID;
  84.         OleTranslateColor(var.lVal, m_hPalette, &col);
  85.         logbrush.lbColor = col;
  86.         HBRUSH hBrush = CreateBrushIndirect(&logbrush);
  87.         FillRect(hdcMem, &rc, hBrush);
  88.         DeleteObject(hBrush);
  89.     }
  90.  
  91.     RECT rcEllipse = rc;
  92.     ReduceRect(&rcEllipse);
  93.     DrawCD(hdcMem, rcEllipse);
  94.  
  95.     // Now we can blt our offscreen bitmap onto the passed DC.
  96.     BitBlt(hdc,
  97.            rcDP.left, rcDP.top,
  98.            rcDP.right-rcDP.left, rcDP.bottom-rcDP.top,
  99.            hdcMem,
  100.            0, 0,
  101.            SRCCOPY);
  102.  
  103.     // Clean up our stuff
  104.     SelectObject(hdcMem, hbmOld);
  105.    DeleteObject(hbmMem);
  106.    DeleteDC(hdcMem);
  107. }
  108.  
  109. void CCDInfo::DrawCD(HDC hdc, RECT rc)
  110. {
  111.     double  dblAngle = m_dblCurrentAngle;
  112.     double  dblRadius = (rc.right - rc.left) / 2;
  113.     short   nTracks, nTrack, nTotalLength;
  114.     POINT   pt1, pt2, ptCenter, ptStart;
  115.     HBRUSH      hBrush, hOldBrush;
  116.     HPEN        hOldPen;
  117.     LOGBRUSH    logbrush;
  118.     COLORREF    col;
  119.  
  120.     ptCenter.x = (rc.right + rc.left) / 2;
  121.     ptCenter.y = (rc.bottom + rc.top) / 2;
  122.  
  123.     nTracks = m_cd.GetNumberOfTracks();
  124.     nTotalLength = m_cd.GetTotalLength();
  125.  
  126.     hOldPen = (HPEN)SelectObject(hdc, GetStockObject(BLACK_PEN));
  127.  
  128.     logbrush.lbStyle = BS_SOLID;
  129.     ptStart = pt1 = CalcPoint(ptCenter, dblRadius, dblAngle);
  130.     for (nTrack=1; nTrack<=nTracks; nTrack++)
  131.     {
  132.         col = m_colSegment[nTrack % (sizeof(m_colSegment)/sizeof(COLORREF))];
  133.         logbrush.lbColor = col;
  134.         hBrush = CreateBrushIndirect(&logbrush);
  135.         hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
  136.  
  137.         if (nTracks==1)
  138.         {
  139.             // As we only have 1 track ensure it is painted correctly
  140.             Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom);
  141.             MoveToEx(hdc, ptCenter.x, ptCenter.y, NULL);
  142.             LineTo(hdc, pt1.x, pt1.y);
  143.         }
  144.         dblAngle += m_cd.GetTrackLength(nTrack) / (double)nTotalLength * 2 * PI;
  145.         if (nTrack==nTracks)
  146.             pt2 = ptStart; // Ensure we finish where we started
  147.         else
  148.             pt2 = CalcPoint(ptCenter, dblRadius, dblAngle);
  149.  
  150.         // Only draw the wedge if it is big enough to see
  151.         if (pt1.x != pt2.x || pt1.y != pt2.y)
  152.         {
  153.             Pie(hdc, rc.left, rc.top, rc.right, rc.bottom, pt2.x, pt2.y, pt1.x, pt1.y);
  154.             pt1 = pt2;
  155.         }
  156.  
  157.         SelectObject(hdc, hOldBrush);
  158.         DeleteObject(hBrush);
  159.     }
  160.     SelectObject(hdc, hOldPen);
  161. }
  162.  
  163. POINT CCDInfo::CalcPoint(POINT ptCenter, double dwRadius, double dblAngle)
  164. {
  165.     POINT ptReturn;
  166.  
  167.     ptReturn.x = (long)(ptCenter.x + dwRadius * cos(dblAngle) + 0.5);
  168.     ptReturn.y = (long)(ptCenter.y + dwRadius * sin(dblAngle) + 0.5);
  169.     return ptReturn;
  170. }
  171.  
  172. double CCDInfo::CalcAngle(POINT ptCenter, POINT point)
  173. {
  174.     double dblAngle;
  175.     dblAngle = atan2((double)(point.y-ptCenter.y), (double)(point.x-ptCenter.x));
  176.     if (dblAngle < PI/2)
  177.         dblAngle += 2 * PI;
  178.     if (dblAngle > 3*PI/2)
  179.         dblAngle -= 2 * PI;
  180.     return dblAngle;
  181. }
  182.  
  183. LRESULT CCDInfo::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam,
  184.     BOOL& bHandled)
  185. {
  186.     POINT   pt;
  187.     short   nTrack;
  188.  
  189.     pt.x = LOWORD(lParam);  // horizontal position of cursor
  190.     pt.y = HIWORD(lParam);  // vertical position of cursor
  191.  
  192.     nTrack = GetTrackFromPoint(pt);
  193.     if (nTrack)
  194.         Click(nTrack);
  195.  
  196.     RelayEvent(uMsg, wParam, lParam, bHandled);
  197.     return 0;
  198. }
  199.  
  200. LRESULT CCDInfo::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam,
  201.     BOOL& bHandled)
  202. {
  203.     if (m_wndToolTip.m_hWnd)
  204.     {
  205.         POINT pt;
  206.         static uId;
  207.         pt.x = LOWORD(lParam);
  208.         pt.y = HIWORD(lParam);
  209.         m_nMouseTrack = GetTrackFromPoint(pt);
  210.  
  211.         if (m_nMouseTrack)
  212.         {
  213.             TOOLINFO ti;
  214.             ti.cbSize = sizeof(TOOLINFO);
  215.             ti.hwnd   = m_hTheWnd;
  216.             uId = (uId==2) ? 1 : 2;
  217.             ti.uId    = uId;
  218.             ti.rect.left   = pt.x;
  219.             ti.rect.right  = pt.x+1;
  220.             ti.rect.top    = pt.y;
  221.             ti.rect.bottom = pt.y+1;
  222.             m_wndToolTip.SendMessage(TTM_NEWTOOLRECT,   0, (LPARAM)&ti);
  223.  
  224.             if (m_nMouseTrack)
  225.             {
  226.                 short nLength = m_cd.GetTrackLength(m_nMouseTrack);
  227.                 short nSeconds = (short)(nLength % 60);
  228.                 TCHAR szTip[10];
  229.                 TCHAR szSeconds[3];
  230.                 wsprintf(szTip, _T("%hd:"), nLength / 60);
  231.                 if (nSeconds < 10)
  232.                     _tcscat(szTip, _T("0"));
  233.                 wsprintf(szSeconds, _T("%hd"), nSeconds);
  234.                 _tcscat(szTip, szSeconds);
  235.                 ti.lpszText = szTip;
  236.                 m_wndToolTip.SendMessage(TTM_UPDATETIPTEXT, 0, (LPARAM)&ti);
  237.             }
  238.         }
  239.         RelayEvent(uMsg, wParam, lParam, bHandled);
  240.     }
  241.     return 0;
  242. }
  243.  
  244. short CCDInfo::GetTrackFromPoint(const POINT& pt)
  245. {
  246.     POINT   ptCenter;
  247.     short   nTracks, nTrack, nTotalLength;
  248.     double  dblAngle, dblNewAngle, dblCursorAngle;
  249.     nTracks = m_cd.GetNumberOfTracks();
  250.     nTotalLength = m_cd.GetTotalLength();
  251.  
  252.     if (!InEllipse(m_rcEllipse, pt) || nTracks==0)
  253.         return 0;
  254.  
  255.     ptCenter.x = (m_rcEllipse.right + m_rcEllipse.left) / 2;
  256.     ptCenter.y = (m_rcEllipse.bottom + m_rcEllipse.top) / 2;
  257.  
  258.     dblAngle = m_dblCurrentAngle;
  259.     dblCursorAngle = CalcAngle(ptCenter, pt);
  260.  
  261.     // Ensure the angle will be in the range that we are checking for
  262.     if (dblCursorAngle < dblAngle)
  263.         dblCursorAngle += 2 * PI;
  264.  
  265.     for (nTrack=1; nTrack<=nTracks; nTrack++)
  266.     {
  267.         dblNewAngle = dblAngle + m_cd.GetTrackLength(nTrack) / (double)nTotalLength * 2 * PI;
  268.         if (dblAngle < dblCursorAngle && dblCursorAngle < dblNewAngle)
  269.             break;
  270.         dblAngle = dblNewAngle;
  271.     }
  272.     return nTrack;
  273. }
  274.  
  275. BOOL CCDInfo::InEllipse(RECT& rect, POINT point)
  276. {
  277.     // Determine radii
  278.     double a = (rect.right - rect.left) / 2;
  279.     double b = (rect.bottom - rect.top) / 2;
  280.  
  281.     // Determine x, y
  282.     double x = point.x - (rect.left + rect.right) / 2;
  283.     double y = point.y - (rect.top + rect.bottom) / 2;
  284.  
  285.     // Apply ellipse formula
  286.     return ((x * x) / (a * a) + (y * y) / (b * b) <= 1);
  287. }
  288.  
  289. double CCDInfo::GetTrackAngle(short nWantedTrack)
  290. {
  291.     short nTrack, nLength;
  292.     double dblMiddlePos;
  293.  
  294.     nLength = 0;
  295.     for (nTrack=1; nTrack<nWantedTrack; nTrack++)
  296.         nLength = (short)(nLength + m_cd.GetTrackLength(nTrack));
  297.  
  298.     dblMiddlePos = nLength + m_cd.GetTrackLength(nTrack) / 2.0;
  299.  
  300.     return dblMiddlePos / (double)m_cd.GetTotalLength() * 2 * PI;
  301. }
  302.  
  303. #define STEP 0.02
  304.  
  305. void CCDInfo::DrawToTrack(short nTrack)
  306. {
  307.     HDC     hDC;
  308.     HRESULT hr;
  309.     double  dblNewAngle;
  310.     double  dblStep;
  311.  
  312.     if (m_bWndLess)
  313.     {
  314.         // We're windowless so we need the DC from the client
  315.         hr = m_spInPlaceSite->GetDC(NULL, 0, &hDC);
  316.         ATLASSERT(SUCCEEDED(hr));
  317.         // We need to reset the origin if we are drawing in client coordinates
  318.         // ::SetWindowOrgEx(hDC, -m_rcPos.left, -m_rcPos.top, &ptOld);
  319.     }
  320.     else
  321.         hDC = ::GetDC(m_hWnd);
  322.  
  323.     dblNewAngle = 3 * PI / 2 - GetTrackAngle(nTrack);
  324.     if (dblNewAngle > m_dblCurrentAngle)
  325.         dblStep = +STEP;    // Anti-clockwise
  326.     else
  327.         dblStep = -STEP;    // Clockwise
  328.  
  329.     while ( fabs(m_dblCurrentAngle - dblNewAngle) > STEP)
  330.     {
  331.         Sleep(5);
  332.         m_dblCurrentAngle += dblStep;
  333.         DrawCD(hDC, m_rcEllipse);
  334.     }
  335.  
  336.     m_dblCurrentAngle = dblNewAngle;
  337.     DrawCD(hDC, m_rcEllipse);
  338.  
  339.     if (m_bWndLess)
  340.         hr = m_spInPlaceSite->ReleaseDC(hDC);
  341.     else
  342.         ::ReleaseDC(m_hWnd, hDC);
  343. }
  344.  
  345. void CCDInfo::CreateTooltipWindow()
  346. {
  347.     InitCommonControls();
  348.     m_wndToolTip.m_hWnd =
  349.         ::CreateWindow(TOOLTIPS_CLASS, (LPTSTR)NULL, TTS_ALWAYSTIP,
  350.             CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  351.             NULL, (HMENU) NULL, _Module.GetModuleInstance(), NULL);
  352.  
  353.     // Ensure the tooltip always appears above our window
  354.     m_wndToolTip.SetWindowPos(HWND_TOPMOST,0,0,0,0,
  355.         SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOSIZE);
  356.  
  357.     TOOLINFO    ti;
  358.     ti.cbSize = sizeof(TOOLINFO);
  359.     ti.uFlags = 0;
  360.     ti.hwnd   = m_hTheWnd;
  361.     ti.uId    = 1;
  362.     ti.hinst  = NULL;
  363.     ti.lpszText = _T("");
  364.     ti.rect.left   = 0;
  365.     ti.rect.right  = 0;
  366.     ti.rect.top    = 0;
  367.     ti.rect.bottom = 0;
  368.     m_wndToolTip.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti);
  369.  
  370.     ti.uId = 2;
  371.     m_wndToolTip.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti);
  372. }
  373.  
  374. // Get the window we need to use. This will either be the window that
  375. // has already been created if we are window or if we are windowless
  376. // the HWND of the client will be retrieved from the HDC.
  377.  
  378. void CCDInfo::GetTheWindow()
  379. {
  380.     // If we're windowless we still need an HWND for Direct3d
  381.     if (m_bWndLess)
  382.     {
  383.         HDC hDC;
  384.  
  385.         // Get the HDC from the client
  386.         m_spInPlaceSite->GetDC(NULL, OLEDC_NODRAW, &hDC);
  387.         m_hTheWnd = WindowFromDC(hDC);
  388.  
  389.         // Code to make VB5 paint properly now it has clipped it's own hDC
  390.  
  391.         RECT rect;
  392.         ::GetClientRect(m_hTheWnd,&rect);
  393.         HRGN hRegion = CreateRectRgn(rect.left, rect.top,
  394.             rect.right, rect.bottom);
  395.         SelectClipRgn(hDC,hRegion);
  396.         m_spInPlaceSite->ReleaseDC(hDC);
  397.     }
  398.     else
  399.         m_hTheWnd = m_hWnd;
  400. }
  401.