// CDInfo1.cpp : Implementation of CCDInfo // // This is a part of the Active Template Library. // Copyright (C) 1996-1998 Microsoft Corporation // All rights reserved. // // This source code is only intended as a supplement to the // Active Template Library Reference and related // electronic documentation provided with the library. // See these sources for detailed information regarding the // Active Template Library product. #include "stdafx.h" #include #include "CDInfo.h" #include "CDInfo1.h" ///////////////////////////////////////////////////////////////////////////// // CCDInfo COLORREF CCDInfo::m_colSegment[] = { RGB(0x00,0x00,0x00), RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00), RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00), RGB(0x00,0xff,0xff), RGB(0xff,0x00,0xff), RGB(0xff,0xff,0xff), RGB(0x7f,0x7f,0x7f), RGB(0x7f,0x00,0x00), RGB(0x00,0x7f,0x00), RGB(0x00,0x00,0x7f), RGB(0x7f,0x7f,0x00), RGB(0x00,0x7f,0x7f), RGB(0x7f,0x00,0x7f), RGB(0x7f,0x7f,0x7f) }; HRESULT CCDInfo::OnDraw(ATL_DRAWINFO& di) { if (di.dwDrawAspect == DVASPECT_CONTENT) { ATLTRACE(_T("Ondraw\n")); DrawOffScreen(di.hdcDraw, *(RECT*)di.prcBounds); } return 0; } void CCDInfo::DrawOffScreen(HDC hdc, RECT rc) { HBITMAP hbmMem, hbmOld; HDC hdcMem; RECT rcDP; // First make sure we have the coordinates in device units and we // are offset from 0,0 LPtoDP(hdc, (LPPOINT)&rc, 2); rcDP = rc; OffsetRect(&rc, -rc.left, -rc.top); // Create a DC to draw into hdcMem = CreateCompatibleDC(hdc); // Create a bitmap big enough for our drawing hbmMem = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top); // Select the bitmap into our new DC hbmOld = (HBITMAP)SelectObject(hdcMem, hbmMem); // If we can get the ambient background color from the container then we // will use it. CComVariant var; if (SUCCEEDED(m_spAmbientDispatch.GetProperty(DISPID_AMBIENT_BACKCOLOR, &var))) { LOGBRUSH logbrush; COLORREF col; logbrush.lbStyle = BS_SOLID; OleTranslateColor(var.lVal, m_hPalette, &col); logbrush.lbColor = col; HBRUSH hBrush = CreateBrushIndirect(&logbrush); FillRect(hdcMem, &rc, hBrush); DeleteObject(hBrush); } RECT rcEllipse = rc; ReduceRect(&rcEllipse); DrawCD(hdcMem, rcEllipse); // Now we can blt our offscreen bitmap onto the passed DC. BitBlt(hdc, rcDP.left, rcDP.top, rcDP.right-rcDP.left, rcDP.bottom-rcDP.top, hdcMem, 0, 0, SRCCOPY); // Clean up our stuff SelectObject(hdcMem, hbmOld); DeleteObject(hbmMem); DeleteDC(hdcMem); } void CCDInfo::DrawCD(HDC hdc, RECT rc) { double dblAngle = m_dblCurrentAngle; double dblRadius = (rc.right - rc.left) / 2; short nTracks, nTrack, nTotalLength; POINT pt1, pt2, ptCenter, ptStart; HBRUSH hBrush, hOldBrush; HPEN hOldPen; LOGBRUSH logbrush; COLORREF col; ptCenter.x = (rc.right + rc.left) / 2; ptCenter.y = (rc.bottom + rc.top) / 2; nTracks = m_cd.GetNumberOfTracks(); nTotalLength = m_cd.GetTotalLength(); hOldPen = (HPEN)SelectObject(hdc, GetStockObject(BLACK_PEN)); logbrush.lbStyle = BS_SOLID; ptStart = pt1 = CalcPoint(ptCenter, dblRadius, dblAngle); for (nTrack=1; nTrack<=nTracks; nTrack++) { col = m_colSegment[nTrack % (sizeof(m_colSegment)/sizeof(COLORREF))]; logbrush.lbColor = col; hBrush = CreateBrushIndirect(&logbrush); hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); if (nTracks==1) { // As we only have 1 track ensure it is painted correctly Ellipse(hdc, rc.left, rc.top, rc.right, rc.bottom); MoveToEx(hdc, ptCenter.x, ptCenter.y, NULL); LineTo(hdc, pt1.x, pt1.y); } dblAngle += m_cd.GetTrackLength(nTrack) / (double)nTotalLength * 2 * PI; if (nTrack==nTracks) pt2 = ptStart; // Ensure we finish where we started else pt2 = CalcPoint(ptCenter, dblRadius, dblAngle); // Only draw the wedge if it is big enough to see if (pt1.x != pt2.x || pt1.y != pt2.y) { Pie(hdc, rc.left, rc.top, rc.right, rc.bottom, pt2.x, pt2.y, pt1.x, pt1.y); pt1 = pt2; } SelectObject(hdc, hOldBrush); DeleteObject(hBrush); } SelectObject(hdc, hOldPen); } POINT CCDInfo::CalcPoint(POINT ptCenter, double dwRadius, double dblAngle) { POINT ptReturn; ptReturn.x = (long)(ptCenter.x + dwRadius * cos(dblAngle) + 0.5); ptReturn.y = (long)(ptCenter.y + dwRadius * sin(dblAngle) + 0.5); return ptReturn; } double CCDInfo::CalcAngle(POINT ptCenter, POINT point) { double dblAngle; dblAngle = atan2((double)(point.y-ptCenter.y), (double)(point.x-ptCenter.x)); if (dblAngle < PI/2) dblAngle += 2 * PI; if (dblAngle > 3*PI/2) dblAngle -= 2 * PI; return dblAngle; } LRESULT CCDInfo::OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { POINT pt; short nTrack; pt.x = LOWORD(lParam); // horizontal position of cursor pt.y = HIWORD(lParam); // vertical position of cursor nTrack = GetTrackFromPoint(pt); if (nTrack) Click(nTrack); RelayEvent(uMsg, wParam, lParam, bHandled); return 0; } LRESULT CCDInfo::OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (m_wndToolTip.m_hWnd) { POINT pt; static uId; pt.x = LOWORD(lParam); pt.y = HIWORD(lParam); m_nMouseTrack = GetTrackFromPoint(pt); if (m_nMouseTrack) { TOOLINFO ti; ti.cbSize = sizeof(TOOLINFO); ti.hwnd = m_hTheWnd; uId = (uId==2) ? 1 : 2; ti.uId = uId; ti.rect.left = pt.x; ti.rect.right = pt.x+1; ti.rect.top = pt.y; ti.rect.bottom = pt.y+1; m_wndToolTip.SendMessage(TTM_NEWTOOLRECT, 0, (LPARAM)&ti); if (m_nMouseTrack) { short nLength = m_cd.GetTrackLength(m_nMouseTrack); short nSeconds = (short)(nLength % 60); TCHAR szTip[10]; TCHAR szSeconds[3]; wsprintf(szTip, _T("%hd:"), nLength / 60); if (nSeconds < 10) _tcscat(szTip, _T("0")); wsprintf(szSeconds, _T("%hd"), nSeconds); _tcscat(szTip, szSeconds); ti.lpszText = szTip; m_wndToolTip.SendMessage(TTM_UPDATETIPTEXT, 0, (LPARAM)&ti); } } RelayEvent(uMsg, wParam, lParam, bHandled); } return 0; } short CCDInfo::GetTrackFromPoint(const POINT& pt) { POINT ptCenter; short nTracks, nTrack, nTotalLength; double dblAngle, dblNewAngle, dblCursorAngle; nTracks = m_cd.GetNumberOfTracks(); nTotalLength = m_cd.GetTotalLength(); if (!InEllipse(m_rcEllipse, pt) || nTracks==0) return 0; ptCenter.x = (m_rcEllipse.right + m_rcEllipse.left) / 2; ptCenter.y = (m_rcEllipse.bottom + m_rcEllipse.top) / 2; dblAngle = m_dblCurrentAngle; dblCursorAngle = CalcAngle(ptCenter, pt); // Ensure the angle will be in the range that we are checking for if (dblCursorAngle < dblAngle) dblCursorAngle += 2 * PI; for (nTrack=1; nTrack<=nTracks; nTrack++) { dblNewAngle = dblAngle + m_cd.GetTrackLength(nTrack) / (double)nTotalLength * 2 * PI; if (dblAngle < dblCursorAngle && dblCursorAngle < dblNewAngle) break; dblAngle = dblNewAngle; } return nTrack; } BOOL CCDInfo::InEllipse(RECT& rect, POINT point) { // Determine radii double a = (rect.right - rect.left) / 2; double b = (rect.bottom - rect.top) / 2; // Determine x, y double x = point.x - (rect.left + rect.right) / 2; double y = point.y - (rect.top + rect.bottom) / 2; // Apply ellipse formula return ((x * x) / (a * a) + (y * y) / (b * b) <= 1); } double CCDInfo::GetTrackAngle(short nWantedTrack) { short nTrack, nLength; double dblMiddlePos; nLength = 0; for (nTrack=1; nTrackGetDC(NULL, 0, &hDC); ATLASSERT(SUCCEEDED(hr)); // We need to reset the origin if we are drawing in client coordinates // ::SetWindowOrgEx(hDC, -m_rcPos.left, -m_rcPos.top, &ptOld); } else hDC = ::GetDC(m_hWnd); dblNewAngle = 3 * PI / 2 - GetTrackAngle(nTrack); if (dblNewAngle > m_dblCurrentAngle) dblStep = +STEP; // Anti-clockwise else dblStep = -STEP; // Clockwise while ( fabs(m_dblCurrentAngle - dblNewAngle) > STEP) { Sleep(5); m_dblCurrentAngle += dblStep; DrawCD(hDC, m_rcEllipse); } m_dblCurrentAngle = dblNewAngle; DrawCD(hDC, m_rcEllipse); if (m_bWndLess) hr = m_spInPlaceSite->ReleaseDC(hDC); else ::ReleaseDC(m_hWnd, hDC); } void CCDInfo::CreateTooltipWindow() { InitCommonControls(); m_wndToolTip.m_hWnd = ::CreateWindow(TOOLTIPS_CLASS, (LPTSTR)NULL, TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, (HMENU) NULL, _Module.GetModuleInstance(), NULL); // Ensure the tooltip always appears above our window m_wndToolTip.SetWindowPos(HWND_TOPMOST,0,0,0,0, SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOREDRAW|SWP_NOSIZE); TOOLINFO ti; ti.cbSize = sizeof(TOOLINFO); ti.uFlags = 0; ti.hwnd = m_hTheWnd; ti.uId = 1; ti.hinst = NULL; ti.lpszText = _T(""); ti.rect.left = 0; ti.rect.right = 0; ti.rect.top = 0; ti.rect.bottom = 0; m_wndToolTip.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti); ti.uId = 2; m_wndToolTip.SendMessage(TTM_ADDTOOL, 0, (LPARAM)&ti); } // Get the window we need to use. This will either be the window that // has already been created if we are window or if we are windowless // the HWND of the client will be retrieved from the HDC. void CCDInfo::GetTheWindow() { // If we're windowless we still need an HWND for Direct3d if (m_bWndLess) { HDC hDC; // Get the HDC from the client m_spInPlaceSite->GetDC(NULL, OLEDC_NODRAW, &hDC); m_hTheWnd = WindowFromDC(hDC); // Code to make VB5 paint properly now it has clipped it's own hDC RECT rect; ::GetClientRect(m_hTheWnd,&rect); HRGN hRegion = CreateRectRgn(rect.left, rect.top, rect.right, rect.bottom); SelectClipRgn(hDC,hRegion); m_spInPlaceSite->ReleaseDC(hDC); } else m_hTheWnd = m_hWnd; }