|
|
/*==========================================================================
* * Copyright (C) 1999 Microsoft Corporation. All Rights Reserved. * * File: peakmetr.cpp * Content: Implements a peak meter custom control * * History: * Date By Reason * ==== == ====== * 09/22/99 pnewson Created * 03/23/00 rodtoll Added casts for Win64 * 04/19/2000 pnewson Error handling cleanup ***************************************************************************/
#include "dxvtlibpch.h"
#undef DPF_SUBCOMP
#define DPF_SUBCOMP DN_SUBCOMP_VOICE
struct SPeakMeterWndInfo { DWORD dwCurLevel; DWORD dwMinLevel; DWORD dwMaxLevel; DWORD dwSteps; HGDIOBJ hBlackStockPen; HGDIOBJ hWhiteStockPen; HGDIOBJ hRedPen; HGDIOBJ hYellowPen; HGDIOBJ hGreenPen; HBRUSH hRedBrush; HBRUSH hYellowBrush; HBRUSH hGreenBrush; };
LRESULT CALLBACK PeakMeterWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT WM_CREATE_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT WM_DESTROY_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); LRESULT WM_PAINT_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
// the window class name of the peak meter custom control
const TCHAR gc_szPeakMeterWindowClassName[] = _T("DirectPlayVoicePeakMeter");
// default values for caller settable data
#define DEFAULT_CURLEVEL 0
#define DEFAULT_MINLEVEL 0
#define DEFAULT_MAXLEVEL 0xffffffff
#define DEFAULT_STEPS 20
// sizes of various things in the window
#define WINDOW_BORDER_SIZE 1
#define MIN_BAR_HEIGHT 2
#define MIN_BAR_WIDTH 2
#define BAR_GUTTER_SIZE 1
#define MIN_NUMBER_BARS 5
// the threshold above which the bar turns yellow, then red
#define RED_THRESHOLD 0.9
#define YELLOW_THRESHOLD 0.8
#undef DPF_MODNAME
#define DPF_MODNAME "CPeakMeterWndClass::Register"
HRESULT CPeakMeterWndClass::Register() { WNDCLASS wndclass; ATOM atom; HRESULT hr; LONG lRet; DPF_ENTER(); m_hinst = GetModuleHandleA(gc_szDVoiceDLLName); if (m_hinst == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "GetModuleHandle failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; }
wndclass.style = CS_HREDRAW|CS_VREDRAW; wndclass.lpfnWndProc = PeakMeterWndProc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = sizeof(LONG_PTR); wndclass.hInstance = m_hinst; wndclass.hIcon = NULL; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW); wndclass.hbrBackground = (HBRUSH) GetSysColorBrush(COLOR_BTNFACE); wndclass.lpszMenuName = NULL; wndclass.lpszClassName = gc_szPeakMeterWindowClassName;
atom = RegisterClass(&wndclass); if (atom == 0) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "RegisterClass failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; }
DPF_EXIT(); return S_OK;
error_cleanup: DPF_EXIT(); return hr; }
#undef DPF_MODNAME
#define DPF_MODNAME "CPeakMeterWndClass::Unregister"
HRESULT CPeakMeterWndClass::Unregister() { HRESULT hr; LONG lRet; DPF_ENTER();
if (!UnregisterClass(gc_szPeakMeterWindowClassName, m_hinst)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ENTRYLEVEL, "RegisterClass failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } DPF_EXIT(); return S_OK;
error_cleanup: DPF_EXIT(); return hr; }
#undef DPF_MODNAME
#define DPF_MODNAME "PeakMeterWndProc"
LRESULT CALLBACK PeakMeterWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { LRESULT lres; LONG lRet; SPeakMeterWndInfo* lppmwi;
DPF_ENTER();
switch (message) { case WM_CREATE: lres = WM_CREATE_Handler(hwnd, message, wParam, lParam); DPF_EXIT(); return lres;
case WM_DESTROY: lres = WM_DESTROY_Handler(hwnd, message, wParam, lParam); DPF_EXIT(); return lres; case PM_SETCUR: case PM_SETMAX: case PM_SETMIN: case PM_SETSTEPS: SetLastError(ERROR_SUCCESS); lppmwi = (SPeakMeterWndInfo*)GetWindowLongPtr(hwnd, 0); lRet = GetLastError(); if (lRet != ERROR_SUCCESS) { DPFX(DPFPREP, DVF_ERRORLEVEL, "GetWindowLongPtr failed, code: %i", lRet); DPF_EXIT(); return DVERR_WIN32; }
switch (message) { case PM_SETCUR: lppmwi->dwCurLevel = (DWORD) lParam; break; case PM_SETMAX: lppmwi->dwMaxLevel = (DWORD) lParam; break; case PM_SETMIN: lppmwi->dwMinLevel = (DWORD) lParam; break; case PM_SETSTEPS: if (lParam < MIN_NUMBER_BARS) { lppmwi->dwSteps = MIN_NUMBER_BARS; } else { lppmwi->dwSteps = (DWORD) lParam; } break; default: DPFX(DPFPREP, DVF_ERRORLEVEL, "Unreachable code!?!"); DPF_EXIT(); return DVERR_GENERIC; }
// no error handling available
InvalidateRgn(hwnd, NULL, TRUE); return S_OK;
case WM_PAINT: lres = WM_PAINT_Handler(hwnd, message, wParam, lParam); DPF_EXIT(); return lres; } lres = DefWindowProc(hwnd, message, wParam, lParam); DPF_EXIT(); return lres; }
LRESULT WM_CREATE_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); SPeakMeterWndInfo* lppmwi = NULL; LONG lRet; HRESULT hr; // allocate a window info struct
lppmwi = (SPeakMeterWndInfo*)DNMalloc(sizeof(SPeakMeterWndInfo)); if (lppmwi == NULL) { DPFX(DPFPREP, DVF_ERRORLEVEL, "DNMalloc failed"); hr = DVERR_OUTOFMEMORY; goto error_cleanup; } ZeroMemory(lppmwi, sizeof(SPeakMeterWndInfo));
lppmwi->dwCurLevel = DEFAULT_CURLEVEL; lppmwi->dwMinLevel = DEFAULT_MINLEVEL; lppmwi->dwMaxLevel = DEFAULT_MAXLEVEL; lppmwi->dwSteps = DEFAULT_STEPS;
// create the pens and brushes we'll be needing
lppmwi->hBlackStockPen = GetStockObject(BLACK_PEN); if (lppmwi->hBlackStockPen == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "GetStockObject failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } lppmwi->hWhiteStockPen = GetStockObject(WHITE_PEN); if (lppmwi->hWhiteStockPen == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "GetStockObject failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } lppmwi->hRedBrush = CreateSolidBrush(RGB(0xff, 0x00, 0x00)); if (lppmwi->hRedBrush == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "CreateSolidBrush failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; }
lppmwi->hYellowBrush = CreateSolidBrush(RGB(0xff, 0xff, 0x00)); if (lppmwi->hYellowBrush == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "CreateSolidBrush failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; }
lppmwi->hGreenBrush = CreateSolidBrush(RGB(0x00, 0xff, 0x00)); if (lppmwi->hGreenBrush == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "CreateSolidBrush failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; }
lppmwi->hRedPen = CreatePen(PS_SOLID, 1, RGB(0xff, 0x00, 0x00)); if (lppmwi->hRedPen == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "CreatePen failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; }
lppmwi->hYellowPen = CreatePen(PS_SOLID, 1, RGB(0xff, 0xff, 0x00)); if (lppmwi->hYellowPen == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "CreatePen failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; }
lppmwi->hGreenPen = CreatePen(PS_SOLID, 1, RGB(0x00, 0xff, 0x00)); if (lppmwi->hGreenPen == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "CreatePen failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } // save the window information
SetLastError(ERROR_SUCCESS); SetWindowLongPtr(hwnd, 0, (LONG_PTR)lppmwi); lRet = GetLastError(); if (lRet != ERROR_SUCCESS) { DPFX(DPFPREP, DVF_ERRORLEVEL, "SetWindowLongPtr failed, code: %i", lRet); hr = DVERR_GENERIC; goto error_cleanup; } DPF_EXIT(); return 0; // will continue window creation
error_cleanup: if (lppmwi != NULL) { if (lppmwi->hGreenPen != NULL) { DeleteObject(lppmwi->hGreenPen); lppmwi->hGreenPen = NULL; } if (lppmwi->hYellowPen != NULL) { DeleteObject(lppmwi->hYellowPen); lppmwi->hYellowPen = NULL; } if (lppmwi->hRedPen != NULL) { DeleteObject(lppmwi->hRedPen); lppmwi->hRedPen = NULL; } if (lppmwi->hGreenBrush != NULL) { DeleteObject(lppmwi->hGreenBrush); lppmwi->hGreenBrush = NULL; } if (lppmwi->hYellowBrush != NULL) { DeleteObject(lppmwi->hYellowBrush); lppmwi->hYellowBrush = NULL; } if (lppmwi->hRedBrush != NULL) { DeleteObject(lppmwi->hRedBrush); lppmwi->hRedBrush = NULL; } DNFree(lppmwi); }
DPF_EXIT(); return -1; // will abort window creation
}
LRESULT WM_DESTROY_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER();
SPeakMeterWndInfo* lppmwi; LONG lRet; // get the window info
SetLastError(ERROR_SUCCESS); lppmwi = (SPeakMeterWndInfo*)GetWindowLongPtr(hwnd, 0); lRet = GetLastError(); if (lRet != ERROR_SUCCESS) { DPFX(DPFPREP, DVF_ERRORLEVEL, "GetWindowLongPtr failed, code: %i", lRet);
// Couldn't get the pointer, so can't clean anything else up!
DPF_EXIT(); return 0; // not sure what returning non-zero will do...
}
// set the window info to null, just in case...
SetLastError(ERROR_SUCCESS); SetWindowLongPtr(hwnd, 0, (LONG_PTR)NULL); lRet = GetLastError(); if (lRet != ERROR_SUCCESS) { DPFX(DPFPREP, DVF_ERRORLEVEL, "SetWindowLongPtr failed, code: %i", lRet); }
if (lppmwi != NULL) { if (lppmwi->hGreenPen != NULL) { DeleteObject(lppmwi->hGreenPen); lppmwi->hGreenPen = NULL; } if (lppmwi->hYellowPen != NULL) { DeleteObject(lppmwi->hYellowPen); lppmwi->hYellowPen = NULL; } if (lppmwi->hRedPen != NULL) { DeleteObject(lppmwi->hRedPen); lppmwi->hRedPen = NULL; } if (lppmwi->hGreenBrush != NULL) { DeleteObject(lppmwi->hGreenBrush); lppmwi->hGreenBrush = NULL; } if (lppmwi->hYellowBrush != NULL) { DeleteObject(lppmwi->hYellowBrush); lppmwi->hYellowBrush = NULL; } if (lppmwi->hRedBrush != NULL) { DeleteObject(lppmwi->hRedBrush); lppmwi->hRedBrush = NULL; } DNFree(lppmwi); } DPF_EXIT(); return 0; }
LRESULT WM_PAINT_Handler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { DPF_ENTER(); LONG lRet; HDC hdc = NULL; PAINTSTRUCT ps; RECT rect; SPeakMeterWndInfo* lppmwi; DWORD dwStepsLocal;
// get the window info
SetLastError(ERROR_SUCCESS); lppmwi = (SPeakMeterWndInfo*)GetWindowLongPtr(hwnd, 0); lRet = GetLastError(); if (lRet != ERROR_SUCCESS) { DPFX(DPFPREP, DVF_ERRORLEVEL, "SetWindowLongPtr failed, code: %i", lRet); goto error_cleanup; } // get the client rectangle
if (!GetClientRect(hwnd, &rect)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "GetClientRect failed, code: %i", lRet); goto error_cleanup; }
// start painting
hdc = BeginPaint(hwnd, &ps); if (hdc == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "BeginPaint failed, code: %i", lRet); goto error_cleanup; }
// make sure the client rectangle is a minimum reasonable size.
if (rect.right - rect.left < 2 * WINDOW_BORDER_SIZE + 2 * BAR_GUTTER_SIZE + MIN_BAR_WIDTH || rect.bottom - rect.top < 2 * WINDOW_BORDER_SIZE + (MIN_BAR_HEIGHT + BAR_GUTTER_SIZE) * MIN_NUMBER_BARS ) { // unreasonable size - fill the whole rect with red so
// the developer will notice
if (SelectObject(hdc, lppmwi->hRedPen) == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet); goto error_cleanup; }
if (SelectObject(hdc, lppmwi->hRedBrush) == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet); goto error_cleanup; }
if (!Rectangle(hdc, rect.left, rect.top, rect.right, rect.bottom)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "Rectangle failed, code: %i", lRet); goto error_cleanup; } } else { // select the black pen - should be the default, but I'm paranoid
if (SelectObject(hdc, lppmwi->hBlackStockPen) == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet); goto error_cleanup; }
// move to the upper left corner, again should be default.
if (!MoveToEx(hdc, 0, 0, NULL)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "MoveToEx failed, code: %i", lRet); goto error_cleanup; }
// draw a black line across the top
if (!LineTo(hdc, rect.right, 0)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "LineTo failed, code: %i", lRet); goto error_cleanup; }
// move to one pixel below the upper left
if (!MoveToEx(hdc, 0, 1, NULL)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "MoveToEx failed, code: %i", lRet); goto error_cleanup; } // draw a black line down the left side, leave the last pixel alone.
if (!LineTo(hdc, 0, rect.bottom-1)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "LineTo failed, code: %i", lRet); goto error_cleanup; }
// select the white pen
if (SelectObject(hdc, lppmwi->hWhiteStockPen) == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet); goto error_cleanup; }
// move to the upper right corner
if (!MoveToEx(hdc, rect.right-1 , 0, NULL)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "MoveToEx failed, code: %i", lRet); goto error_cleanup; }
// draw a white line down the right side
if (!LineTo(hdc, rect.right-1, rect.bottom)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "LineTo failed, code: %i", lRet); goto error_cleanup; }
// move to the lower left corner,
if (!MoveToEx(hdc, 0 , rect.bottom-1, NULL)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "MoveToEx failed, code: %i", lRet); goto error_cleanup; }
// draw a white line across the bottom
if (!LineTo(hdc, rect.right-1, rect.bottom-1)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "LineTo failed, code: %i", lRet); goto error_cleanup; }
// see if there is enough room to display the suggested
// number of bars.
DWORD dwFreeSpace = (rect.bottom) - (2 * WINDOW_BORDER_SIZE) - BAR_GUTTER_SIZE; if (dwFreeSpace < lppmwi->dwSteps * (BAR_GUTTER_SIZE + MIN_BAR_HEIGHT)) { // There is not enough room to display the suggested size.
// Figure out how many bars we can display if they are the
// minimum size.
dwStepsLocal = dwFreeSpace / (BAR_GUTTER_SIZE + MIN_BAR_HEIGHT); } else { dwStepsLocal = lppmwi->dwSteps; }
// start drawing the bars from the bottom up
HBRUSH hCurBrush; HGDIOBJ hCurPen; DWORD dwIndex; for (dwIndex = 0; dwIndex < dwStepsLocal; ++dwIndex) { // what "value" does the bar we are about to draw have?
// i.e. how far up the scale is it?
float fBarValue = (float)(dwIndex + 1) / (float)dwStepsLocal;
// what is the "value" of the control at this moment?
// i.e. how far up the scale should the bars go?
float fCurValue = (float)(lppmwi->dwCurLevel - lppmwi->dwMinLevel) / (float)(lppmwi->dwMaxLevel - lppmwi->dwMinLevel);
// are we done drawning bars?
if (fBarValue > fCurValue) { // that's it, we're finished
break; } // figure out what color this bar should be
if (fBarValue > RED_THRESHOLD) { hCurBrush = lppmwi->hRedBrush; hCurPen = lppmwi->hRedPen; } else if (fBarValue > YELLOW_THRESHOLD) { hCurBrush = lppmwi->hYellowBrush; hCurPen = lppmwi->hYellowPen; } else { hCurBrush = lppmwi->hGreenBrush; hCurPen = lppmwi->hGreenPen; }
if (SelectObject(hdc, hCurPen) == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet); goto error_cleanup; }
if (SelectObject(hdc, hCurBrush) == NULL) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "SelectObject failed, code: %i", lRet); goto error_cleanup; }
POINT pUpperLeft; POINT pLowerRight;
pUpperLeft.x = WINDOW_BORDER_SIZE + BAR_GUTTER_SIZE; pUpperLeft.y = (rect.bottom) - WINDOW_BORDER_SIZE - ((dwIndex + 1) * dwFreeSpace) / dwStepsLocal;
pLowerRight.x = rect.right - WINDOW_BORDER_SIZE - BAR_GUTTER_SIZE; pLowerRight.y = (rect.bottom) - WINDOW_BORDER_SIZE - BAR_GUTTER_SIZE - (dwIndex * dwFreeSpace) / dwStepsLocal; if (!Rectangle(hdc, pUpperLeft.x, pUpperLeft.y, pLowerRight.x, pLowerRight.y)) { lRet = GetLastError(); DPFX(DPFPREP, DVF_ERRORLEVEL, "Rectangle failed, code: %i", lRet); goto error_cleanup; } } }
// we're done - no error checking available on this call...
EndPaint(hwnd, &ps); hdc = NULL;
// return zero to indicate that we processed this message
DPF_EXIT(); return 0;
error_cleanup: if (hdc != NULL) { EndPaint(hwnd, &ps); hdc = NULL; }
// return non-zero to indicate that we did not process
// this message successfully
DPF_EXIT(); return -1; }
|