STATUS.C


/******************************************************************************\
* This is a part of the Microsoft Source Code Samples.
* Copyright 1993 - 1998 Microsoft Corporation.
* All rights reserved.
* This source code is only intended as a supplement to
* Microsoft Development Tools and/or WinHelp documentation.
* See these sources for detailed information regarding the
* Microsoft samples programs.
\******************************************************************************/

#define NOMINMAX
#include <windows.h>

#include <stdlib.h> // For 'abs'

#if !defined (APIENTRY)
#define APIENTRY FAR PASCAL
#endif

#define MAXSTATUS 10
typedef struct _tagStatus {
HWND hwnd;
int iMaxWidth, iMinWidth, iGiveWidth;
} Status;
Status statusField[MAXSTATUS];

HWND hwndStatus;
int cntStatusField = 0;
int dyStatus, cxStatusBorder, cyStatusBorder, cxFrame, cyFrame, dyField;
HFONT hfontStatus;
TEXTMETRIC tmStatusFont;
HBRUSH hbrBtnFace;

LONG APIENTRY StatusProc (HWND, UINT, UINT, LONG);
LONG APIENTRY StatusFieldProc (HWND, UINT, UINT, LONG);

BOOL InitStatusBar (HANDLE hInstance)
{
WNDCLASS wndclass;

hbrBtnFace = CreateSolidBrush(GetSysColor(COLOR_BTNFACE));

wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = (WNDPROC)StatusProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = hbrBtnFace;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "SamplerStatus";

if (!RegisterClass (&wndclass))
return FALSE;

wndclass.style = CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = (WNDPROC)StatusFieldProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);
wndclass.hbrBackground = hbrBtnFace;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = "StatusField";

if (!RegisterClass (&wndclass))
return FALSE;

}

BOOL CreateStatusBar (HWND hwnd, HANDLE hInst, int iId)
{
cxStatusBorder = GetSystemMetrics (SM_CXBORDER);
cyStatusBorder = GetSystemMetrics (SM_CYBORDER);

hwndStatus = CreateWindow ("SamplerStatus", "SamplerStatus",
WS_CHILD | WS_BORDER | WS_VISIBLE,
0, 0, 0, 0,
hwnd, (HMENU)iId, hInst, NULL);

if (!hwndStatus) {
return FALSE;
}
return TRUE;
}

int StatusBarHeight (HWND hwnd)
{
RECT rect;
GetClientRect (hwndStatus, &rect);
return rect.bottom-rect.top;

hwnd; // unreferenced formal parameter
}

BOOL AdjustStatusBar (HWND hwnd)
{
RECT rect;
GetClientRect (hwnd, &rect);
MoveWindow (hwndStatus,
rect.left-cxStatusBorder,
rect.bottom - dyStatus + cyStatusBorder,
rect.right - rect.left + (cxStatusBorder*2),
dyStatus,
TRUE);
return TRUE;
}

HWND AddStatusField (HANDLE hInst, int iId, int iMin, int iMax, BOOL bNewGroup)
{
LONG lStyle;

if (cntStatusField >= MAXSTATUS) return (HWND)0; // No room left in our fixed array

statusField[cntStatusField].hwnd = CreateWindow ("StatusField", "",
WS_CHILD | WS_VISIBLE,
0, 0, 0, 0,
hwndStatus, (HMENU)iId, hInst, NULL);

if (!statusField[cntStatusField].hwnd) return (HWND)0; // CreateWindow failed for some reason

if (iMin < 0) {
statusField[cntStatusField].iMinWidth = tmStatusFont.tmAveCharWidth*abs(iMin);
} else {
statusField[cntStatusField].iMinWidth = iMin;
}

if (iMax < 0) {
statusField[cntStatusField].iMaxWidth = tmStatusFont.tmAveCharWidth*abs(iMax);
} else {
statusField[cntStatusField].iMaxWidth = iMax;
}

if (bNewGroup) {
lStyle = GetWindowLong (statusField[cntStatusField].hwnd, GWL_STYLE);
lStyle |= WS_GROUP;
SetWindowLong (statusField[cntStatusField].hwnd, GWL_STYLE, lStyle);
}

return statusField[cntStatusField++].hwnd;
}

BOOL DestroyStatusBar (void)
{
return DeleteObject (hbrBtnFace);
}

LONG APIENTRY StatusProc (HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
HDC hdc;
PAINTSTRUCT ps;
int x, y, i;
int wAvailWidth, wFlexWidth, cntFlexWidth, wNeedWidth, cntNeedWidth;
RECT rect, border;
HBRUSH hBrush;
LOGFONT lfTmp;

switch (msg) {
case WM_CREATE:
hfontStatus = CreateFont(14, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
VARIABLE_PITCH | FF_SWISS, "");

if (GetObject (hfontStatus, sizeof(LOGFONT), &lfTmp)) {
if ((lfTmp.lfPitchAndFamily & VARIABLE_PITCH) &&
(lfTmp.lfPitchAndFamily & FF_SWISS)) {
} else {
MessageBox (GetFocus(),
"Unable to get an unnamed variable pitch swiss font", "Status Bar CreateFont Error",
MB_OK);
hfontStatus = CreateFont(14, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0,
VARIABLE_PITCH | FF_SWISS, "Arial");
}
}


if (!hfontStatus) {
MessageBox (GetFocus(), "Failed To Create Font", "StatusProc", MB_OK);
}
hdc = GetDC (hwnd);
SelectObject (hdc, hfontStatus);
GetTextMetrics (hdc, &tmStatusFont);
cxStatusBorder = GetSystemMetrics (SM_CXBORDER);
cyStatusBorder = GetSystemMetrics (SM_CYBORDER);
cxFrame = 3*cxStatusBorder;
cyFrame = 3*cyStatusBorder;
dyField = tmStatusFont.tmHeight + (2*cyStatusBorder);
dyStatus = dyField + (2*cyFrame);
ReleaseDC (hwnd, hdc);
return DefWindowProc (hwnd, msg, wParam, lParam);

case WM_DESTROY:
if (hfontStatus) {
DeleteObject (hfontStatus);
}
break;

case WM_SIZE:
if (cntStatusField) {
GetClientRect (hwnd, &rect);
wAvailWidth = rect.right - rect.left - (cxStatusBorder*8);
wNeedWidth = 0;
cntNeedWidth = 0;
cntFlexWidth = 0;

/* First Pass: Dole out to fields that have a minimum need */
for (i=0; i<cntStatusField; i++) {
statusField[i].iGiveWidth = 0; // Make sure all are initialized to 0
if (statusField[i].iMinWidth) {
/* (n, ?) */
statusField[i].iGiveWidth = statusField[i].iMinWidth;
wAvailWidth -= (statusField[i].iGiveWidth + cxStatusBorder*2);
if (GetWindowLong(statusField[i].hwnd, GWL_STYLE) & WS_GROUP) {
wAvailWidth -= cxStatusBorder*4;
}
} else {
/* They didn't specify a minimum... don't give them anything yet */
/* (0, ?) */
statusField[i].iGiveWidth = 0;
}

/* For those that have a minimum, but can grow to be as large as possible...*/
/* (n, 0) */
if ((statusField[i].iMinWidth >0) && (statusField[i].iMaxWidth ==0)) {
++cntFlexWidth;
}

/* For those that have a max that is greater then their min... */
/* Includes (0,n) and (n,>n) */
if (statusField[i].iMaxWidth > statusField[i].iGiveWidth) {
wNeedWidth += (statusField[i].iMaxWidth - statusField[i].iGiveWidth);
++cntNeedWidth;
}
}

/* Second Pass: Dole out to fields that have a stated maximum need */
/* This will also hit those who had no minimum, but did have a maximum */
/* It will still not give anything to those with no min, no max */
if ((cntNeedWidth > 0) && (wAvailWidth > 0)) {
if (wNeedWidth > wAvailWidth) {
wNeedWidth = wAvailWidth;
}
wNeedWidth = wNeedWidth / cntNeedWidth;
for (i=0; i<cntStatusField; i++) {
if (statusField[i].iMaxWidth > statusField[i].iGiveWidth) {
statusField[i].iGiveWidth += wNeedWidth;
wAvailWidth -= (statusField[i].iGiveWidth + cxStatusBorder*2);
if (GetWindowLong(statusField[i].hwnd, GWL_STYLE) & WS_GROUP) {
wAvailWidth -= cxStatusBorder*4;
}
}
}
}

/* Third Pass: Dole out the remaining to fields that want all they can get */
/* This includes those who had a minimum, but no maximum */
if ((cntFlexWidth > 0) && (wAvailWidth > 0)) {
wFlexWidth = wAvailWidth / cntFlexWidth;
for (i=0; i<cntStatusField; i++) {
if (statusField[i].iMaxWidth==0) {
statusField[i].iGiveWidth += wFlexWidth;
wAvailWidth -= ((wFlexWidth - statusField[i].iMinWidth) + cxStatusBorder*2);
if (GetWindowLong(statusField[i].hwnd, GWL_STYLE) & WS_GROUP) {
wAvailWidth -= cxStatusBorder*4;
}
}
}
}

x = cxStatusBorder*4;
y = rect.top + (2*cyStatusBorder);
for (i=0; i<cntStatusField; i++) {
if (GetWindowLong (statusField[i].hwnd, GWL_STYLE) & WS_GROUP) {
x += (cxStatusBorder*4);
}
MoveWindow (statusField[i].hwnd, x, y, statusField[i].iGiveWidth, dyField, TRUE);
x += statusField[i].iGiveWidth + (cxStatusBorder*2);
}
}
break;

case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
GetClientRect (hwnd, &rect);

hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
border = rect;
border.bottom = border.top + cyStatusBorder;
FillRect (hdc, &border, hBrush);
DeleteObject (hBrush);

hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
border = rect;
border.top = border.bottom - cyStatusBorder;
FillRect (hdc, &border, hBrush);
DeleteObject (hBrush);

EndPaint (hwnd, &ps);

return DefWindowProc (hwnd, msg, wParam, lParam);

default:
return DefWindowProc (hwnd, msg, wParam, lParam);
}
return 0L;
}



LONG APIENTRY StatusFieldProc (HWND hwnd, UINT msg, UINT wParam, LONG lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect, border;
HBRUSH hBrush;
WORD edge = 1;
HFONT hTmp;
char szText[80];
int len;

switch (msg) {
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps);
GetClientRect (hwnd, &rect);

hBrush = CreateSolidBrush(GetSysColor(COLOR_BTNSHADOW));
border = rect;
border.bottom = border.top + cyStatusBorder;
FillRect (hdc, &border, hBrush);
border = rect;
border.right = border.left + cxStatusBorder;
FillRect (hdc, &border, hBrush);
DeleteObject (hBrush);

hBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
border = rect;
border.top = border.bottom - cyStatusBorder;
FillRect (hdc, &border, hBrush);
border = rect;
border.left = border.right - cxStatusBorder;
FillRect (hdc, &border, hBrush);
DeleteObject (hBrush);

if (len = GetWindowText(hwnd, szText, sizeof (szText))) {
hTmp = SelectObject(hdc, hfontStatus);

SetTextColor(hdc, GetSysColor(COLOR_BTNTEXT));
SetBkColor(hdc, GetSysColor(COLOR_BTNFACE));

InflateRect (&rect, -(cxStatusBorder*2), -cyStatusBorder);
ExtTextOut(hdc, rect.left, rect.top,
ETO_OPAQUE | ETO_CLIPPED,
&rect,
(LPSTR)szText,
len, NULL);

SelectObject (hdc, hTmp);
}

EndPaint (hwnd, &ps);
break;

case WM_SETTEXT:
InvalidateRect (hwnd, NULL, TRUE);
return DefWindowProc (hwnd, msg, wParam, lParam);

default:
return DefWindowProc (hwnd, msg, wParam, lParam);
}
return 0L;
}