|
|
/*****************************************************************************
* * Component: sndvol32.exe * File: vu.c * Purpose: peak meter custom control * * Copyright (c) 1985-1998 Microsoft Corporation * *****************************************************************************/ /*
* VUMeter Control * * */ #include <windows.h>
#include <windowsx.h>
#include "vu.h"
const TCHAR gszVUClass[] = VUMETER_CLASS;
LRESULT FAR PASCAL VUMeterProc(HWND hwnd, UINT wMessage, WPARAM wParam, LPARAM lParam);
#define GETVUINST(x) (VUINST *)GetWindowLongPtr(x, 0)
#define SETVUINST(x,y) SetWindowLongPtr(x, 0, (LONG_PTR)y)
typedef struct tag_VUINST { CREATESTRUCT cs; DWORD dwLevel; // current value
DWORD dwMax; // value max
DWORD dwMin; // value min
DWORD dwBreak; // last break
DWORD dwStyle; // dbl extra style bits ???
DWORD cBreaks; // no. of breaks
DWORD cRGB; // no. of RGBQUADs
DWORD dwHeight; DWORD dwWidth; HBITMAP hColor; // bitmap cache of full display
HBITMAP hBackground; // bitmap cache of background
RGBQUAD *aRGB; // array of RGBQUADs describing colors
} VUINST, *PVUINST, FAR *LPVUINST;
const RGBQUAD gaRGBDefault[] = { { 0, 127, 0, 0}, // dark green
{ 0, 127, 0, 0}, // dark green
{ 0, 255, 0, 0}, // light green
{ 0, 255, 255, 0}, // yellow
{ 0, 0, 255, 0} // red
};
BOOL InitVUControl(HINSTANCE hInst) { WNDCLASS wc; wc.lpszClassName = (LPTSTR)gszVUClass; wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.lpszMenuName = (LPTSTR)NULL; wc.style = CS_HREDRAW|CS_VREDRAW|CS_GLOBALCLASS; wc.lpfnWndProc = (WNDPROC) VUMeterProc; wc.hInstance = hInst; wc.hIcon = NULL; wc.cbWndExtra = sizeof(VUINST *); wc.cbClsExtra = 0; wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1 );
/* register meter window class */ if(!RegisterClass(&wc)) { return FALSE; }
return (TRUE); }
DWORD vu_CalcBreaks( PVUINST pvi) { DWORD cBreaks; if (pvi->dwMax - pvi->dwMin > 0) { cBreaks = ((pvi->dwLevel - pvi->dwMin) * pvi->cBreaks) / (pvi->dwMax - pvi->dwMin); if (!cBreaks && pvi->dwLevel > pvi->dwMin) cBreaks++; } else cBreaks = 0; if (cBreaks > pvi->cBreaks) cBreaks = pvi->cBreaks; return cBreaks; }
BOOL vu_OnCreate( HWND hwnd, LPCREATESTRUCT lpCreateStruct) { PVUINST pvi;
//
// alloc an instance data structure
pvi = LocalAlloc(LPTR, sizeof(VUINST)); if (!pvi) return FALSE; SETVUINST(hwnd, pvi); pvi->cBreaks = 10; pvi->cRGB = sizeof(gaRGBDefault)/sizeof(RGBQUAD); pvi->aRGB = (RGBQUAD *)gaRGBDefault; pvi->dwMin = 0; pvi->dwMax = 0; pvi->dwLevel = 0; pvi->dwBreak = 0; pvi->hColor = NULL; pvi->hBackground = NULL; return TRUE; }
void vu_ResetControl( PVUINST pvi) { if (pvi->hColor) { DeleteObject(pvi->hColor); pvi->hColor = NULL; } if (pvi->hBackground) { DeleteObject(pvi->hBackground); pvi->hBackground = NULL; } }
void vu_OnDestroy( HWND hwnd) { PVUINST pvi = GETVUINST(hwnd); if (pvi) { vu_ResetControl(pvi); LocalFree((HLOCAL)pvi); SETVUINST(hwnd,0); } }
void vu_OnPaint( HWND hwnd) { PVUINST pvi = GETVUINST(hwnd); RECT rc, rcB; PAINTSTRUCT ps; int i; int iSize; DWORD cBreaks; if (!GetUpdateRect(hwnd, &rc, FALSE)) return;
BeginPaint(hwnd, &ps); GetClientRect(hwnd, &rc); //
// Create the foreground bitmap if not already cached
//
if (pvi->hColor == NULL) { HDC hdc; HBITMAP hbmp, hold; HBRUSH hbr; RECT rcp; rcp.left = 0; rcp.right = rc.right - rc.left - 4; rcp.top = 0; rcp.bottom = rc.bottom - rc.top - 4 ; hdc = CreateCompatibleDC(ps.hdc); hbmp = CreateCompatibleBitmap(ps.hdc, rcp.right, rcp.bottom); hold = SelectObject(hdc, hbmp);
//
// background
//
hbr = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); FillRect(hdc, &rcp, hbr); if (hbr) DeleteObject(hbr); //
// each block will be iSize tall
//
iSize = (rcp.bottom - 1) / pvi->cBreaks;
//
// color blocks
//
for (i = 0; i < (int)pvi->cBreaks; i++) { int iColor = i / (pvi->cBreaks/pvi->cRGB); if (iColor >= (int)pvi->cRGB - 1) iColor = (int)pvi->cRGB - 1;
hbr = CreateSolidBrush(RGB(pvi->aRGB[iColor].rgbRed ,pvi->aRGB[iColor].rgbGreen ,pvi->aRGB[iColor].rgbBlue)); rcB.left = 0; rcB.right = rcp.right; rcB.top = rcp.bottom - (i+1)*iSize; // rcB.bottom = rcp.bottom - i*iSize;
rcB.bottom = rcB.top + iSize - 1;
FillRect(hdc, &rcB, hbr); DeleteObject(hbr); } pvi->hColor = SelectObject(hdc, hold); DeleteDC(hdc); }
//
// Paint it
//
{ HDC hdc, hdcColor; HBITMAP holdColor, hbmp, hold; RECT rcC = rc; HBRUSH hbr;
//
// always show something if we exceed the minimum
cBreaks = vu_CalcBreaks(pvi); rcC.left = 0; rcC.right = rc.right - rc.left - 4; rcC.top = 0; rcC.bottom = rc.bottom - rc.top - 4; // each block will be iSize+1 tall
iSize = (rcC.bottom - 1) / pvi->cBreaks ; // paint the uncolor area
hdc = CreateCompatibleDC(ps.hdc); hbmp = CreateCompatibleBitmap(ps.hdc, rcC.right, rcC.bottom); hold = SelectObject(hdc, hbmp); hbr = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); FillRect(hdc, &rcC, hbr); if (hbr) DeleteObject(hbr);
if (cBreaks > 0) { // paint the color area
hdcColor = CreateCompatibleDC(ps.hdc); if (hdcColor) holdColor = SelectObject(hdcColor, pvi->hColor);
BitBlt(hdc , 0 , rcC.bottom - (iSize * cBreaks) , rcC.right , iSize * cBreaks , hdcColor , 0 , rcC.bottom - (iSize * cBreaks) , SRCCOPY); SelectObject(hdcColor, holdColor); DeleteDC(hdcColor); } //
// finally, blt into the real dc
BitBlt(ps.hdc , 2 , 2 , rcC.right , rcC.bottom , hdc , 0 , 0 , SRCCOPY); SelectObject(hdc, hold); if (hbmp) DeleteObject(hbmp); DeleteDC(hdc); } DrawEdge(ps.hdc, &rc, BDR_SUNKENOUTER, BF_RECT);
EndPaint(hwnd, &ps); }
void vu_OnSysColorChange( HWND hwnd) { PVUINST pvi = GETVUINST(hwnd); vu_ResetControl(pvi); }
void vu_OnPaletteChanged( HWND hwnd, HWND hwndPaletteChange) { PVUINST pvi = GETVUINST(hwnd); vu_ResetControl(pvi); }
void vu_OnSize( HWND hwnd, UINT state, int cx, int cy) { PVUINST pvi = GETVUINST(hwnd); pvi->dwWidth = cx; pvi->dwHeight = cy; vu_ResetControl(pvi); }
void vu_OnEnable( HWND hwnd, BOOL fEnable) { PVUINST pvi = GETVUINST(hwnd);
}
void vu_OnPrivateMessage( HWND hwnd, UINT wMessage, WPARAM wParam, LPARAM lParam) { PVUINST pvi = GETVUINST(hwnd); switch (wMessage) { case VU_SETRANGEMIN: // OutputDebugString(TEXT ("SetRangeMin\r\n"));
pvi->dwMin = (DWORD)lParam; break; case VU_SETRANGEMAX: // OutputDebugString(TEXT ("SetRangeMax\r\n"));
pvi->dwMax = (DWORD)lParam; break;
case VU_SETPOS: pvi->dwLevel = (DWORD)lParam; // {TCHAR foo[256];
// wsprintf(foo, TEXT ("v:%lx\r\n"),lParam);
// OutputDebugString(foo);
// }
if (pvi->dwBreak != vu_CalcBreaks(pvi)) { pvi->dwBreak = vu_CalcBreaks(pvi); InvalidateRect(hwnd, NULL, TRUE); } else if (wParam) InvalidateRect(hwnd, NULL, TRUE); break; } }
LRESULT FAR PASCAL VUMeterProc( HWND hwnd, UINT wMessage, WPARAM wParam, LPARAM lParam) { switch (wMessage) { HANDLE_MSG(hwnd, WM_CREATE, vu_OnCreate); HANDLE_MSG(hwnd, WM_DESTROY, vu_OnDestroy); HANDLE_MSG(hwnd, WM_PAINT, vu_OnPaint); HANDLE_MSG(hwnd, WM_SYSCOLORCHANGE, vu_OnSysColorChange); HANDLE_MSG(hwnd, WM_PALETTECHANGED, vu_OnPaletteChanged); HANDLE_MSG(hwnd, WM_SIZE, vu_OnSize); HANDLE_MSG(hwnd, WM_ENABLE, vu_OnEnable); // HANDLE_MSG(hwnd, WM_TIMER, vu_OnTimer);
case VU_SETRANGEMIN: case VU_SETRANGEMAX: case VU_SETPOS: vu_OnPrivateMessage(hwnd, wMessage, wParam, lParam); return 0; case WM_ERASEBKGND: return TRUE; default: break; } return DefWindowProc (hwnd, wMessage, wParam, lParam) ; }
|