windows-nt/Source/XPSP1/NT/enduser/netmeeting/ui/conf/progressbar.cpp
2020-09-26 16:20:57 +08:00

563 lines
12 KiB
C++

// File: Progressbar.cpp
#include "precomp.h"
#include "ProgressBar.h"
#include "GenControls.h"
#define SIGNAL_STATUS_TRANSMIT 0x01 // data is being received/sent
#define SIGNAL_STATUS_JAMMED 0x02 // wave dev failed to open
CProgressBar::CProgressBar()
{
for (int i=0; i<ARRAY_ELEMENTS(m_hbs); ++i)
{
m_hbs[i] = NULL;
}
}
CProgressBar::~CProgressBar()
{
for (int i=0; i<ARRAY_ELEMENTS(m_hbs); ++i)
{
if (NULL != m_hbs[i])
{
DeleteObject(m_hbs[i]);
m_hbs[i] = NULL;
}
}
}
BOOL CProgressBar::Create(
HBITMAP hbFrame, // The outside (static) part of the progress bar
HBITMAP hbBar, // The inside part of the progress bar that jumps around
HWND hWndParent // The parent of the toolbar window
)
{
ASSERT(NULL!=hbFrame && NULL!=hbBar);
SetFrame(hbFrame);
SetBar(hbBar);
if (!CGenWindow::Create(hWndParent, 0, g_szEmpty, 0, 0))
{
return(FALSE);
}
return(TRUE);
}
void CProgressBar::GetDesiredSize(SIZE *ppt)
{
CGenWindow::GetDesiredSize(ppt);
if (NULL == GetFrame())
{
return;
}
SIZE sizeBitmap;
CBitmapButton::GetBitmapSizes(&m_hbs[Frame], &sizeBitmap, 1);
ppt->cx += sizeBitmap.cx;
ppt->cy += sizeBitmap.cy;
}
LRESULT CProgressBar::ProcessMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
HANDLE_MSG(hwnd, WM_PAINT, OnPaint);
}
return(CGenWindow::ProcessMessage(hwnd, message, wParam, lParam));
}
void CProgressBar::OnPaint(HWND hwnd)
{
if (NULL == GetFrame() || NULL == GetBar() || 0 == GetMaxValue())
{
FORWARD_WM_PAINT(hwnd, CGenWindow::ProcessMessage);
return;
}
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
HDC hdcTemp = CreateCompatibleDC(hdc);
if (NULL != hdcTemp)
{
HPALETTE hPal = GetPalette();
HPALETTE hOld = NULL;
if (NULL != hPal)
{
hOld = SelectPalette(hdc, hPal, TRUE);
RealizePalette(hdc);
SelectPalette(hdcTemp, hPal, TRUE);
RealizePalette(hdcTemp);
}
SIZE sizes[NumBitmaps];
CBitmapButton::GetBitmapSizes(m_hbs, sizes, NumBitmaps);
// BUGBUG georgep: This is going to flicker, so I will need to fix that
SelectObject(hdcTemp, GetFrame());
BitBlt(hdc, 0, 0, sizes[Frame].cx, sizes[Frame].cy, hdcTemp, 0, 0, SRCCOPY);
// BUGBUG georgep: We should clean out the "uncovered" area here
UINT cur = GetCurrentValue();
UINT max = GetMaxValue();
if (cur > max)
{
cur = max;
}
SelectObject(hdcTemp, GetBar());
// Center the bitmap, but only display to the current percentage
BitBlt(hdc, (sizes[Frame].cx-sizes[Bar].cx)/2, (sizes[Frame].cy-sizes[Bar].cy)/2,
(sizes[Bar].cx*cur)/max, sizes[Bar].cy, hdcTemp, 0, 0, SRCCOPY);
// This is where we should attempt to alpha blend the inner onto the
// outer for a few pixels in either direction
// Clean up
DeleteDC(hdcTemp);
if (NULL != hPal)
{
SelectPalette(hdc, hOld, TRUE);
}
}
EndPaint(hwnd, &ps);
}
// Change the max value displayed by this progress bar
void CProgressBar::SetMaxValue(UINT maxVal)
{
m_maxVal = maxVal;
InvalidateRect(GetWindow(), NULL, FALSE);
}
// Change the current value displayed by this progress bar
void CProgressBar::SetCurrentValue(UINT curVal)
{
m_curVal = curVal;
InvalidateRect(GetWindow(), NULL, FALSE);
}
static const int DefWidth = 170;
static const int DefHeight = 23;
CProgressTrackbar::CProgressTrackbar() :
m_nValChannel(0)
{
m_desSize.cx = DefWidth;
m_desSize.cy = DefHeight;
}
CProgressTrackbar::~CProgressTrackbar()
{
}
BOOL CProgressTrackbar::Create(
HWND hWndParent, // The parent of the toolbar window
INT_PTR nId, // The ID of the control
IScrollChange *pNotify // Object to notify of changes
)
{
if (!CFillWindow::Create(
hWndParent,
nId,
"NMTrackbar",
0,
WS_EX_CONTROLPARENT
))
{
return(FALSE);
}
// Create the Win32 button
CreateWindowEx(0, TRACKBAR_CLASS, g_szEmpty,
TBS_HORZ|TBS_NOTICKS|TBS_BOTH
|WS_CLIPSIBLINGS|WS_TABSTOP|WS_VISIBLE|WS_CHILD,
0, 0, 10, 10,
GetWindow(), reinterpret_cast<HMENU>(nId), _Module.GetModuleInstance(), NULL);
m_pNotify = pNotify;
if (NULL != m_pNotify)
{
m_pNotify->AddRef();
}
return(TRUE);
}
void CProgressTrackbar::GetDesiredSize(SIZE *ppt)
{
*ppt = m_desSize;
}
void CProgressTrackbar::SetDesiredSize(SIZE *psize)
{
m_desSize = *psize;
OnDesiredSizeChanged();
}
LRESULT CProgressTrackbar::ProcessMessage(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
HANDLE_MSG(hwnd, WM_NOTIFY , OnNotify);
HANDLE_MSG(hwnd, WM_HSCROLL , OnScroll);
HANDLE_MSG(hwnd, WM_VSCROLL , OnScroll);
HANDLE_MSG(hwnd, WM_CTLCOLORSTATIC, OnCtlColor);
HANDLE_MSG(hwnd, WM_NCDESTROY , OnNCDestroy);
}
return(CFillWindow::ProcessMessage(hwnd, message, wParam, lParam));
}
HBRUSH CProgressTrackbar::OnCtlColor(HWND hwnd, HDC hdc, HWND hwndChild, int type)
{
return(GetBackgroundBrush());
}
LRESULT CProgressTrackbar::PaintChannel(LPNMCUSTOMDRAW pCustomDraw)
{
static const int NUM_RECTANGLES_MAX = 16;
static const int NUM_RECTANGLES_MIN = 6;
static const int g_nAudMeterHeight = 7;
static const int BorderWidth = 1;
HDC hdc = pCustomDraw->hdc;
BOOL bGotDC = FALSE;
DWORD dwVolume = m_nValChannel;
bool bTransmitting;
bTransmitting = HIWORD(dwVolume) & SIGNAL_STATUS_TRANSMIT;
dwVolume = LOWORD(dwVolume);
if (!hdc)
{
hdc = GetDC(GetWindow());
bGotDC = TRUE;
}
// rectangle leading is 1
UINT max = GetMaxValue();
if (dwVolume > max)
{
dwVolume = max;
}
RECT rect = pCustomDraw->rc;
int nVuWidth = rect.right - rect.left - 2*BorderWidth;
if (nVuWidth < (NUM_RECTANGLES_MIN*2))
return(0);
// "rect" represents the edges of the meter's outer rectangle
// compute the number of individual rectangles to use
// we do the computation this way so that sizing the rebar band
// makes the size changes consistant
int nRectsTotal;
nRectsTotal = (nVuWidth + (g_nAudMeterHeight - 1)) / g_nAudMeterHeight;
nRectsTotal = min(nRectsTotal, NUM_RECTANGLES_MAX);
nRectsTotal = max(nRectsTotal, NUM_RECTANGLES_MIN);
// nRectangleWidth - width of colored rectangle - no leading
int nRectangleWidth = (nVuWidth/nRectsTotal) - 1;
// nVuWidth - width of entire VU meter including edges
nVuWidth = (nRectangleWidth + 1)*nRectsTotal;
// re-adjust meter size to be an integral number of rects
int nDiff = (rect.right - rect.left) - (nVuWidth + 2*BorderWidth);
// Subtract 1 since there is no border on the last one
rect.right = rect.left + nVuWidth + 2*BorderWidth - 1;
// center vu-meter across whole channel area so that the
// slider's thumb is always covering some portion of the channel
rect.left += (nDiff/2);
rect.right += (nDiff/2);
// the background color may change on us!
COLORREF GreyColor = GetSysColor(COLOR_3DFACE);
static const COLORREF RedColor = RGB(255,0,0);
static const COLORREF YellowColor = RGB(255,255,0);
static const COLORREF GreenColor = RGB(0,255,0);
COLORREF ShadowColor = GetSysColor(COLOR_3DSHADOW);
COLORREF HiLiteColor = GetSysColor(COLOR_3DHIGHLIGHT);
COLORREF LiteColor = GetSysColor(COLOR_3DLIGHT);
COLORREF DkShadowColor = GetSysColor(COLOR_3DDKSHADOW);
HBRUSH hGreyBrush = CreateSolidBrush(GreyColor);
HPEN hShadowPen = CreatePen(PS_SOLID, 0, ShadowColor);
HBRUSH hRedBrush = CreateSolidBrush (RedColor);
HBRUSH hGreenBrush = CreateSolidBrush(GreenColor);
HBRUSH hYellowBrush = CreateSolidBrush(YellowColor);
RECT rectDraw = rect;
// draw the 3D frame border
// HACKHACK georgep: draw outside the rect they gave us
++rect.bottom;
DrawEdge(hdc, &rect, BDR_RAISEDINNER, BF_RECT);
HPEN hOldPen = reinterpret_cast<HPEN>(SelectObject(hdc, hShadowPen));
// the top and left of the meter has a 2 line border
// the bottom and right of the meter has a 2 line border
rectDraw.top += 1;
rectDraw.left += 1;
rectDraw.right = rectDraw.left + nRectangleWidth;
// how many colored rectangles do we draw ?
int nRects = (dwVolume * nRectsTotal) / max;
// not transmitting - don't show anything
if ((false == bTransmitting))
nRects = 0;
// transmitting or receiving something very quiet -
// light up at least one rectangle
else if ((bTransmitting) && (nRects == 0))
nRects = 1;
HBRUSH hCurrentBrush = hGreenBrush;
POINT ptOld;
MoveToEx(hdc, 0, 0, &ptOld);
for (int nIndex = 0; nIndex < nRectsTotal; nIndex++)
{
// far left fourth of the bar is green
// right fourth of the bar is red
// middle is yellow
if (nIndex > ((nRectsTotal*3)/4))
hCurrentBrush = hRedBrush;
else if (nIndex >= nRectsTotal/2)
hCurrentBrush = hYellowBrush;
if (nIndex >= nRects)
hCurrentBrush = hGreyBrush;
FillRect(hdc, &rectDraw, hCurrentBrush);
if (nIndex != (nRectsTotal-1))
{
MoveToEx(hdc, rectDraw.left + nRectangleWidth, rectDraw.top, NULL);
LineTo(hdc, rectDraw.left + nRectangleWidth, rectDraw.bottom);
}
rectDraw.left += nRectangleWidth + 1; // +1 for the leading
rectDraw.right = rectDraw.left + nRectangleWidth;
}
MoveToEx(hdc, ptOld.x, ptOld.y, NULL);
SelectObject (hdc, hOldPen);
if (bGotDC)
{
ReleaseDC(GetWindow(), hdc);
}
DeleteObject(hGreyBrush);
DeleteObject(hShadowPen);
DeleteObject(hRedBrush);
DeleteObject(hGreenBrush);
DeleteObject(hYellowBrush);
return(CDRF_SKIPDEFAULT);
}
LRESULT CProgressTrackbar::PaintThumb(LPNMCUSTOMDRAW pCustomDraw)
{
return(0);
#if FALSE // {
HBITMAP hbThumb = GetThumb();
ASSERT(NULL != hbThumb);
// Draw in the upper left
HDC hdcDraw = pCustomDraw->hdc;
HDC hdcTemp = CreateCompatibleDC(hdcDraw);
if (NULL != hdcTemp)
{
HPALETTE hPal = GetPalette();
HPALETTE hOld = NULL;
if (NULL != hPal)
{
hOld = SelectPalette(hdcDraw, hPal, TRUE);
RealizePalette(hdcDraw);
SelectPalette(hdcTemp, hPal, TRUE);
RealizePalette(hdcTemp);
}
SIZE sizeBitmap[NumBitmaps];
CBitmapButton::GetBitmapSizes(m_hbs, sizeBitmap, NumBitmaps);
HBITMAP hbThumb = GetThumb();
if (NULL != SelectObject(hdcTemp, hbThumb))
{
RECT rc = pCustomDraw->rc;
StretchBlt(hdcDraw,
rc.left, rc.top,
rc.right-rc.left, rc.bottom-rc.top,
hdcTemp,
0, 0, sizeBitmap[Thumb].cx, sizeBitmap[Thumb].cy,
SRCCOPY);
// BUGBUG georgep: We should clear any "uncovered" area here
}
DeleteDC(hdcTemp);
if (NULL != hPal)
{
SelectPalette(hdcDraw, hOld, TRUE);
}
}
return(CDRF_SKIPDEFAULT);
#endif // FALSE }
}
LRESULT CProgressTrackbar::OnNotify(HWND hwnd, int id, NMHDR *pHdr)
{
if (NM_CUSTOMDRAW != pHdr->code)
{
return(FORWARD_WM_NOTIFY(hwnd, id, pHdr, CGenWindow::ProcessMessage));
}
LPNMCUSTOMDRAW pCustomDraw = reinterpret_cast<LPNMCUSTOMDRAW>(pHdr);
switch (pCustomDraw->dwDrawStage)
{
case CDDS_PREPAINT:
return(CDRF_NOTIFYITEMDRAW | CDRF_NOTIFYPOSTPAINT);
break;
case CDDS_ITEMPREPAINT:
switch (pCustomDraw->dwItemSpec)
{
case TBCD_CHANNEL:
return(PaintChannel(pCustomDraw));
case TBCD_THUMB:
return(PaintThumb(pCustomDraw));
}
default:
break;
}
return(FORWARD_WM_NOTIFY(hwnd, id, pHdr, CGenWindow::ProcessMessage));
}
void CProgressTrackbar::OnScroll(HWND hwnd, HWND hwndCtl, UINT code, int pos)
{
if (NULL != m_pNotify)
{
m_pNotify->OnScroll(this, code, pos);
return;
}
// Translate the hwndCtl and let the parent handle the message
FORWARD_WM_HSCROLL(GetParent(hwnd), GetWindow(), code, pos, SendMessage);
}
void CProgressTrackbar::OnNCDestroy(HWND hwnd)
{
if (NULL != m_pNotify)
{
m_pNotify->Release();
m_pNotify = NULL;
}
FORWARD_WM_NCDESTROY(hwnd, CFillWindow::ProcessMessage);
}
// Change the max value displayed by this progress bar
void CProgressTrackbar::SetMaxValue(UINT maxVal)
{
HWND hwnd = GetChild();
::SendMessage( hwnd,
TBM_SETRANGE,
FALSE,
MAKELONG(0, maxVal));
}
// Return the max value displayed by this progress bar
UINT CProgressTrackbar::GetMaxValue()
{
HWND hwnd = GetChild();
return(static_cast<UINT>(::SendMessage( hwnd,
TBM_GETRANGEMAX,
0,
0)));
}
// Change the current value displayed by this progress bar
void CProgressTrackbar::SetTrackValue(UINT curVal)
{
HWND hwnd = GetChild();
::SendMessage( hwnd,
TBM_SETPOS,
TRUE,
curVal);
}
// Return the current value displayed by this progress bar
UINT CProgressTrackbar::GetTrackValue()
{
HWND hwnd = GetChild();
return(static_cast<UINT>(::SendMessage( hwnd,
TBM_GETPOS,
0,
0)));
}
// Change the current value displayed by this progress bar
void CProgressTrackbar::SetProgressValue(UINT curVal)
{
if (curVal != m_nValChannel)
{
m_nValChannel = curVal;
SchedulePaint();
}
}
// Return the current value displayed by this progress bar
UINT CProgressTrackbar::GetProgressValue()
{
return(m_nValChannel);
}