NT4/private/windows/media/mixerapp/vu.c
2020-09-30 17:12:29 +02:00

387 lines
9.7 KiB
C

/*****************************************************************************
*
* Component: sndvol32.exe
* File: vu.c
* Purpose: peak meter custom control
*
* Copyright (C) Microsoft Corporation 1985-1995. All rights reserved.
*
*****************************************************************************/
/*
* 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 *)GetWindowLong(x, 0)
#define SETVUINST(x,y) SetWindowLong(x, 0, (LONG)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;
}
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);
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);
DeleteObject(hbr);
if (cBreaks > 0)
{
// paint the color area
hdcColor = CreateCompatibleDC(ps.hdc);
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);
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 = lParam;
break;
case VU_SETRANGEMAX:
// OutputDebugString(TEXT ("SetRangeMax\r\n"));
pvi->dwMax = lParam;
break;
case VU_SETPOS:
pvi->dwLevel = 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) ;
}