//=========================================================== // StatBar - A set of routines that adds a status bar to a // client window. // Copyright (C) 1994 Douglas Boling // Copyright (C) 1995 Ziff-Davis Publishing Company // // To Use: // Include Statbar.h in source file // // Revision History: // // 1.0 Initial Release // 2.0 Added lots'a function //=========================================================== // Returns no. of elements #define dim(x) (sizeof(x) / sizeof(x[0])) #include "windows.h" #include "string.h" #include "stdlib.h" #define INT int #define UINT WORD #define APIENTRY PASCAL #define WNDPROC FARPROC #include "statbar.h" #define TEXTBUFFSIZE 512 struct decodeUINT { // structure associates UINT Code; // messages LONG (*Fxn)(HWND, UINT, UINT, LONG); // with a function }; typedef struct { UINT fFlags; INT sWidth; DWORD dwData; char far *lpszText; } FIELDENT; typedef struct { HFONT hFont; DWORD dwData; UINT wActCtl; INT sCap; INT sHeight; LPSTR lpEnd; INT sFreeSpace; INT sNumFields; FIELDENT feField[1]; } STATUSBARDATA; typedef STATUSBARDATA far * LPSTATUSBARDATA; //----------------------------------------------------------- // NonPublic procedure declarations //---------------------------------------------------------- LONG CALLBACK ClientSCProc(HWND, UINT, UINT, LONG); LONG CALLBACK StatBarWinProc(HWND, UINT, UINT, LONG); // Message handler functions for client subclass proc LONG DoSizeClient (HWND, UINT, UINT, LONG); LONG DoKeyDownClient (HWND, UINT, UINT, LONG); LONG DoMenuSelectClient (HWND, UINT, UINT, LONG); LONG DoDestroyClient (HWND, UINT, UINT, LONG); // Message handler functions for status bar window proc LONG DoSetFontStatBar (HWND, UINT, UINT, LONG); LONG DoGetFontStatBar (HWND, UINT, UINT, LONG); LONG DoSetTextStatBar (HWND, UINT, UINT, LONG); LONG DoGetTextStatBar (HWND, UINT, UINT, LONG); LONG DoCommandStatBar (HWND, UINT, UINT, LONG); LONG DoPaintStatBar (HWND, UINT, UINT, LONG); LONG DoMenuCharStatBar (HWND, UINT, UINT, LONG); LONG DoDrawItemStatBar (HWND, UINT, UINT, LONG); LONG DoMeasureItemStatBar (HWND, UINT, UINT, LONG); LONG DoLButtonDownStatBar (HWND, UINT, UINT, LONG); LONG DoLButtonUpStatBar (HWND, UINT, UINT, LONG); LONG DoDestroyStatBar (HWND, UINT, UINT, LONG); LONG DoGetItemDataStatBar (HWND, UINT, UINT, LONG); LONG DoGetEventDataStatBar (HWND, UINT, UINT, LONG); LONG DoPostEventStatBar (HWND, UINT, UINT, LONG); //Status bar functions HFONT SetStatusBarFont (LPSTATUSBARDATA, HFONT); void GetFieldRect (LPSTATUSBARDATA, INT, RECT *, RECT *); void DrawFieldBitmap (LPSTATUSBARDATA, HWND, LPSTR, RECT *); void DrawFieldText (LPSTATUSBARDATA, HWND, LPSTR, RECT *); void DrawSBText (HWND, char far *, INT); void DrawSBIcon (HWND, HBITMAP, INT); HBITMAP Icon2BMP (HWND, HICON); // Utility routines WNDPROC MySubClassWindow (HWND, WNDPROC); //----------------------------------------------------------- // Global data //----------------------------------------------------------- // Message dispatch table for ClientSCProc struct decodeUINT ClientSCMessages[] = { WM_SIZE, DoSizeClient, WM_SYSKEYDOWN, DoKeyDownClient, WM_MENUSELECT, DoMenuSelectClient, WM_DESTROY, DoDestroyClient, }; // Message dispatch table for StatbarWndProc struct decodeUINT StatBarMessages[] = { WM_SETFONT, DoSetFontStatBar, WM_GETFONT, DoGetFontStatBar, WM_SETTEXT, DoSetTextStatBar, WM_GETTEXT, DoGetTextStatBar, WM_COMMAND, DoCommandStatBar, WM_LBUTTONDOWN, DoLButtonDownStatBar, WM_LBUTTONUP, DoLButtonUpStatBar, WM_PAINT, DoPaintStatBar, WM_MENUCHAR, DoMenuCharStatBar, WM_MEASUREITEM, DoMeasureItemStatBar, WM_DRAWITEM, DoDrawItemStatBar, WM_DESTROY, DoDestroyStatBar, STATM_GETITEMDATA, DoGetItemDataStatBar, STATM_GETEVENTDATA, DoGetEventDataStatBar, STATM_POSTEVENT, DoPostEventStatBar, }; extern HANDLE hInst; FARPROC lpfnClientSCProc, lpfnOldClientWndProc = 0; BOOL fUnHook; char szDebug[256]; //============================================================ // Status Bar Public functions //============================================================ //----------------------------------------------------------- // StatusBarInit - Initialization code for the status bar. //----------------------------------------------------------- INT StatusBarInit(HANDLE hInstance) { WNDCLASS wc; hInst = hInstance; // // Register status bar window class // wc.style = CS_HREDRAW; // Class style wc.lpfnWndProc = StatBarWinProc; // Callback function wc.cbClsExtra = 0; // Extra class data wc.cbWndExtra = sizeof (HGLOBAL); // Extra window data wc.hInstance = hInst; // Owner handle wc.hIcon = 0; // Application icon wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Default cursor wc.hbrBackground = CreateSolidBrush (GetSysColor (COLOR_BTNFACE)); wc.lpszMenuName = 0; // Menu name wc.lpszClassName = "StatusBarCls"; // Window class name if (RegisterClass(&wc) == 0) return 1; lpfnClientSCProc = MakeProcInstance ((FARPROC) ClientSCProc, hInst); return 0; } //----------------------------------------------------------- // StatusBarTerm - Termination code for the status bar. //----------------------------------------------------------- INT StatusBarTerm(HANDLE hInstance) { FreeProcInstance ((FARPROC) lpfnClientSCProc); return 0; } //----------------------------------------------------------- // SBCreate - Internal routie that creates a status bar window //----------------------------------------------------------- INT SBCreate (HWND hWndClient, INT sNumFields, SBCREATESTRUCT *psb, BOOL fNewStyle) { INT x, y, cx, cy, sTW; HWND hwndStatBar; RECT rect; HDC hdc; HFONT hOld; TEXTMETRIC tm; HGLOBAL hData; LPSTATUSBARDATA lpStatData; // //Alloc memory for status window info block // hData = GlobalAlloc (GHND, sizeof (STATUSBARDATA) + sNumFields * sizeof(FIELDENT) + TEXTBUFFSIZE); if (!hData) return STERR_NOMEMORY; lpStatData = (LPSTATUSBARDATA) GlobalLock (hData); // //Init memory block // lpStatData->hFont = 0; lpStatData->sCap = 0; lpStatData->sFreeSpace = TEXTBUFFSIZE; lpStatData->lpEnd = (LPSTR) lpStatData + sizeof (STATUSBARDATA) + sNumFields * sizeof(FIELDENT); //Create the status bar font if (fNewStyle) lpStatData->hFont = SetStatusBarFont (lpStatData, psb->hFont); else lpStatData->hFont = SetStatusBarFont (lpStatData, 0); lpStatData->sNumFields = sNumFields; hdc = GetDC(NULL); hOld = SelectObject(hdc, lpStatData->hFont); GetTextMetrics(hdc, &tm); lpStatData->sHeight = tm.tmHeight + tm.tmExternalLeading + 10; sTW = 0; for (x = 0; x < sNumFields; x++) { if (fNewStyle) { if (psb->sbi[x].sWidth == -1) { if (psb->sbi[x].fFlags & FLAG_ICON) lpStatData->feField[x].sWidth = lpStatData->sHeight - 2; else lpStatData->feField[x].sWidth = (INT)GetTextExtent (hdc, psb->sbi[x].pText, lstrlen (psb->sbi[x].pText)) + 12; } else lpStatData->feField[x].sWidth = psb->sbi[x].sWidth; lpStatData->feField[x].fFlags = psb->sbi[x].fFlags; lpStatData->feField[x].dwData = psb->sbi[x].dwData; } else { lpStatData->feField[x].sWidth = *((INT *)psb)++; lpStatData->feField[x].fFlags = 0; } lpStatData->feField[x].lpszText = 0; // compute total width; sTW += lpStatData->feField[x].sWidth; } SelectObject(hdc, hOld); ReleaseDC(NULL, hdc); // // Create status bar window // GetClientRect (hWndClient, &rect); x = rect.left; y = rect.bottom - lpStatData->sHeight; cx = rect.right - rect.left; cy = lpStatData->sHeight; // Check width vs total width of fields if (cx < sTW) return STERR_TOOWIDE; hwndStatBar = CreateWindow ("StatusBarCls", NULL, WS_CHILD | WS_VISIBLE, x, y, cx, cy, hWndClient, IDD_STATBAR, hInst, NULL); if(!hwndStatBar) { return STERR_NOWNDCREATE; } SetWindowWord (hwndStatBar, 0, hData); GlobalUnlock (hData); // Now set the initial text if (fNewStyle) { for (x = 0; x < sNumFields; x++) { if (psb->sbi[x].pText) SetStatusBarText (hWndClient, psb->sbi[x].pText, x); } } fUnHook = FALSE; lpfnOldClientWndProc = MySubClassWindow (hWndClient, lpfnClientSCProc); return 0; // return success flag } //----------------------------------------------------------- // StatusBarCreate - Creates a status bar window //----------------------------------------------------------- INT StatusBarCreate (HWND hWndClient, INT sNumFields, INT *sFieldArray) { return SBCreate (hWndClient, sNumFields, (SBCREATESTRUCT *)*sFieldArray, FALSE); } //----------------------------------------------------------- // StatusBarCreateEx - Creates a status bar window with // extended caps. //----------------------------------------------------------- INT StatusBarCreateEx (HWND hWndClient, SBCREATESTRUCT *psb) { return SBCreate (hWndClient, psb->sFields, psb, TRUE); } //------------------------------------------------------------ // GetStatusBarHeight - returns the height of the status bar //------------------------------------------------------------ INT GetStatusBarHeight (HWND hWndClient) { HWND hWndStatBar; HDC hdc; HFONT hOld; TEXTMETRIC tm; HGLOBAL hData; LPSTATUSBARDATA lpStatData; hWndStatBar = GetDlgItem (hWndClient, IDD_STATBAR); hData = GetWindowWord (hWndStatBar, 0); lpStatData = (LPSTATUSBARDATA) GlobalLock (hData); if (!lpStatData) return 0; // //Create the status bar font and compute its size // hdc = GetDC(NULL); hOld = SelectObject(hdc, lpStatData->hFont); GetTextMetrics(hdc, &tm); SelectObject(hdc, hOld); ReleaseDC(NULL, hdc); GlobalUnlock (hData); return tm.tmHeight + tm.tmExternalLeading + 10; } //------------------------------------------------------------ // ModifyClientRect - Modifies a rect structure filled with // the client window dimentions to reflect the status bar //------------------------------------------------------------ INT ModifyClientRect (HWND hWnd, RECT *rectOut) { RECT rect; HWND hwndStatBar; hwndStatBar = GetDlgItem (hWnd, IDD_STATBAR); if (hwndStatBar == 0) return 0; GetClientRect (hwndStatBar, &rect); rectOut->bottom -= (rect.bottom - rect.top); return 0; } //------------------------------------------------------------ // SetStatusBarLong - Displays a number in a status bar field // status bar. //------------------------------------------------------------ INT SetStatusBarLong (HWND hWnd, LPSTR pszText, LONG lNum, INT sField) { char szTemp[256]; wsprintf (szTemp, "%s %d", pszText, lNum); return SetStatusBarText (hWnd, szTemp, sField); } //------------------------------------------------------------ // SetStatusBarIcon - Sets the icon in a field //------------------------------------------------------------ INT SetStatusBarIcon (HWND hWnd, DWORD dwData, INT sField) { LPSTATUSBARDATA lpStatData; HWND hwndStatBar; HGLOBAL hData; HBITMAP hBitmap, hOld; HBITMAP hBitmap2, hOld2; HDC hdc, hdc1, hdc2; RECT rect, rectOut; HICON hIcon; HBRUSH hBr, hOldBr; INT sDim; hIcon = LOWORD (dwData); hwndStatBar = GetDlgItem (hWnd, IDD_STATBAR); hData = GetWindowWord (hwndStatBar, 0); lpStatData = (LPSTATUSBARDATA) GlobalLock (hData); GetClientRect (hWnd, &rect); GetFieldRect (lpStatData, sField, &rect, &rectOut); rectOut.top += 1; rectOut.bottom -= 1; // Convert icon to bitmap hdc = GetDC (NULL); hdc1 = CreateCompatibleDC (hdc); hdc2 = CreateCompatibleDC (hdc); // Create bitmap sDim = rectOut.bottom - rectOut.top; hBitmap = CreateCompatibleBitmap (hdc, sDim, sDim); hOld = SelectObject (hdc1, hBitmap); hBitmap2 = CreateCompatibleBitmap (hdc, 100, 100); hOld2 = SelectObject (hdc2, hBitmap2); // Create background hBr = CreateSolidBrush (GetSysColor (COLOR_BTNFACE)); rect.left = 0; rect.top = 0; rect.right = 50; rect.bottom = 50; hOldBr = SelectObject (hdc2, hBr); FillRect (hdc2, &rect, hBr); SelectObject (hdc2, hOldBr); hOldBr = SelectObject (hdc1, hBr); FillRect (hdc1, &rect, hBr); SelectObject (hdc1, hOldBr); DeleteObject (hBr); SetMapMode (hdc2, MM_TEXT); DrawIcon (hdc2, 0, 0, hIcon); SetStretchBltMode (hdc1, STRETCH_DELETESCANS); StretchBlt (hdc1, 0, 0, sDim, sDim, hdc2, 0, 0, 32, 32, SRCCOPY); // Clean up SelectObject (hdc1, hOld); SelectObject (hdc2, hOld2); DeleteObject (hBitmap2); DeleteDC (hdc1); DeleteDC (hdc2); ReleaseDC (NULL, hdc); DestroyIcon (hIcon); lpStatData->feField[sField].lpszText = (LPSTR)MAKELONG (hBitmap, HIWORD (dwData)); // lpStatData->feField[sField].lpszText = (LPSTR) MAKELONG (hBitmap, hIcon); DrawSBText (hwndStatBar, lpStatData->feField[sField].lpszText, sField); GlobalUnlock (hData); return 0; } //------------------------------------------------------------ // SetStatusBarText - Sets the texts for a field in the // status bar. //------------------------------------------------------------ INT SetStatusBarText (HWND hWnd, LPSTR pszText, INT sField) { HWND hwndStatBar; LPSTATUSBARDATA lpStatData; INT i, sLen, sSrcLen; LPSTR lpSrc; LPSTR lpDest; hwndStatBar = GetDlgItem (hWnd, IDD_STATBAR); if (hwndStatBar == 0) return 1; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hwndStatBar, 0)); // If icon instead of text, don't set if (lpStatData->feField[sField].fFlags & FLAG_ICON) { i = SetStatusBarIcon (hWnd, (DWORD)pszText, sField); GlobalUnlock (GetWindowWord (hwndStatBar, 0)); return i; } // // If new text same as current text, exit. // if (lpStatData->feField[sField].lpszText && pszText && (lstrcmp (lpStatData->feField[sField].lpszText, pszText) == 0)) { GlobalUnlock (GetWindowWord (hwndStatBar, 0)); return 0; } // //Copy the text into the status bar global buffer // if (lpStatData->feField[sField].lpszText != 0) { // //If field already has text, remove and collapse the buffer //strings over the string being removed. // lpDest = lpStatData->feField[sField].lpszText; sLen = lstrlen (lpDest) + 1; lpSrc = lpDest + sLen; while (lpSrc < lpStatData->lpEnd) { // //Search array for pointer to this string // for (i = 0; i < lpStatData->sNumFields; i++) if (lpSrc == lpStatData->feField[i].lpszText) break; // //Move string and update pointer. // lpStatData->feField[i].lpszText = lpDest; lstrcpy (lpDest, lpSrc); sSrcLen = lstrlen (lpSrc) + 1; lpDest += sSrcLen; lpSrc += sSrcLen; } lpStatData->lpEnd = lpDest; lpStatData->sFreeSpace += sLen; } sLen = lstrlen (pszText) + 1; i = 0; if (sLen < lpStatData->sFreeSpace) { lstrcpy (lpStatData->lpEnd, pszText); lpStatData->feField[sField].lpszText = lpStatData->lpEnd; lpStatData->lpEnd += sLen; lpStatData->sFreeSpace -= sLen; DrawSBText (hwndStatBar, pszText, sField); } else i = 2; GlobalUnlock (GetWindowWord (hwndStatBar, 0)); return i; } //============================================================ // Client window subclass procedures //============================================================ //------------------------------------------------------------ // ClientSCProc - Callback subclass function for client window //------------------------------------------------------------ LONG CALLBACK ClientSCProc(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { INT i; LONG lRet; // // Search message list to see if we need to handle this // message. If in list, call procedure. // for(i = 0; i < dim(ClientSCMessages); i++) { if(wMsg == ClientSCMessages[i].Code) { //wsprintf (szDebug, "SC Message %x start\n", wMsg); //OutputDebugString (szDebug); lRet = (*ClientSCMessages[i].Fxn)(hWnd, wMsg, wParam, lParam); //wsprintf (szDebug, "SC Message %x end\n", wMsg); //OutputDebugString (szDebug); return lRet; } } lRet = CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg, wParam, lParam); if (fUnHook) { MySubClassWindow (hWnd, lpfnOldClientWndProc); fUnHook = FALSE; } return lRet; } //------------------------------------------------------------ // DoSizeClient - process WM_SIZE message for client window. //------------------------------------------------------------ LONG DoSizeClient (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { INT x,y, cx, cy; RECT rect; LPSTATUSBARDATA lpStatData; HGLOBAL hData; HWND hwndStatBar; hwndStatBar = GetDlgItem (hWnd, IDD_STATBAR); if (hwndStatBar == 0) return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg, wParam, lParam); hData = GetWindowWord (hwndStatBar, 0); lpStatData = (LPSTATUSBARDATA) GlobalLock (hData); // Compute size of window GetClientRect (hWnd, &rect); x = rect.left; y = rect.bottom - lpStatData->sHeight; cx = rect.right - rect.left; cy = lpStatData->sHeight; SetWindowPos (hwndStatBar, NULL, x, y, cx, cy, SWP_NOZORDER); GlobalUnlock (hData); return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg, wParam, lParam); } //------------------------------------------------------------ // DoMenuSelectClient - process WM_MENUSELECT message for client window. //------------------------------------------------------------ LONG DoMenuSelectClient (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { HWND hwndStatBar; char szText[128]; UINT usFlags, usMenu; LPSTATUSBARDATA lpStatData; hwndStatBar = GetDlgItem (hWnd, IDD_STATBAR); if (hwndStatBar == 0) return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg, wParam, lParam); usFlags = LOWORD (lParam); usMenu = wParam; szText[0] = '\0'; if ((usFlags & MF_SYSMENU) && (usMenu == NULL)) { lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hwndStatBar, 0)); if (lpStatData->feField[0].lpszText) DrawSBText (hwndStatBar, lpStatData->feField[0].lpszText, 0); else DrawSBText (hwndStatBar, "", 0); GlobalUnlock (GetWindowWord (hwndStatBar, 0)); } else if (!(usFlags & MF_SEPARATOR)) { if ((usFlags & MF_SYSMENU) && (usFlags & MF_POPUP)) LoadString (hInst, IDM_SYSMENUACTIVE, szText, sizeof (szText)); else if (!(usFlags & MF_POPUP)) LoadString (hInst, usMenu+MENUTEXT, szText, sizeof (szText)); DrawSBText (hwndStatBar, szText, 0); } return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg, wParam, lParam); } //------------------------------------------------------------ // DoKeyDownClient - process WM_KEYDOWN message for client window. //------------------------------------------------------------ LONG DoKeyDownClient (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { LPSTATUSBARDATA lpStatData; HWND hwndStatBar; char ch, ch1 = 0; LPSTR lpPtr; INT i; // Only act on Alt key if ((lParam & 0x20000000) == 0) return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg, wParam, lParam); ch = (char)(DWORD)AnsiUpper ((LPSTR)(LONG) MapVirtualKey (wParam, 2)); if (ch == 0) return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg, wParam, lParam); hwndStatBar = GetDlgItem (hWnd, IDD_STATBAR); lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hwndStatBar, 0)); for (i = 0; i < lpStatData->sNumFields; i++) { lpPtr = lpStatData->feField[i].lpszText; if (lpPtr) { if (lpStatData->feField[i].fFlags & FLAG_ICON) ch1 = (char) HIWORD (lpPtr); else { while (*lpPtr) { lpPtr++; if (*(lpPtr-1) == '&') { ch1 = (char)(DWORD)AnsiUpper ((LPSTR)(LONG) *lpPtr); break; } } } if (ch == ch1) { SendMessage (hwndStatBar, STATM_POSTEVENT, i, 0); ch1 = -1; break; } } } GlobalUnlock (GetWindowWord (hwndStatBar, 0)); if (ch1 != -1) return CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg, wParam, lParam); return 0; } //------------------------------------------------------------ // DoDestroyClient - process WM_DESTROY message for client window. //------------------------------------------------------------ LONG DoDestroyClient (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { LONG lRC; DestroyWindow (GetDlgItem (hWnd, IDD_STATBAR)); lRC = CallWindowProc (lpfnOldClientWndProc, hWnd, wMsg, wParam, lParam); return lRC; } //============================================================ // Status Bar Window functions //============================================================ //------------------------------------------------------------ // StatBarWinProc - Callback function for status bar window //------------------------------------------------------------ LONG CALLBACK StatBarWinProc(HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { INT i; LONG lRet; // // Search message list to see if we need to handle this // message. If in list, call procedure. // for(i = 0; i < dim(StatBarMessages); i++) { if(wMsg == StatBarMessages[i].Code) { //wsprintf (szDebug, "Statbar Message %x end\n", wMsg); //OutputDebugString (szDebug); lRet = (*StatBarMessages[i].Fxn)(hWnd, wMsg, wParam, lParam); //wsprintf (szDebug, "Statbar Message %x end\n", wMsg); //OutputDebugString (szDebug); return lRet; } } return DefWindowProc(hWnd, wMsg, wParam, lParam); } //------------------------------------------------------------ // DoSetFontStatBar - process WM_SETFONT message for StatBar window. //------------------------------------------------------------ LONG DoSetFontStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { LPSTATUSBARDATA lpStatData; HFONT hFont; RECT rect; INT cy, oldcy; oldcy = GetStatusBarHeight (GetParent (hWnd)); lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); hFont = SetStatusBarFont (lpStatData, (HFONT)wParam); GlobalUnlock (GetWindowWord (hWnd, 0)); cy = GetStatusBarHeight (GetParent (hWnd)); GetClientRect (hWnd, &rect); SetWindowPos (hWnd, NULL, rect.left, rect.top - (cy - oldcy), rect.right - rect.left, cy, SWP_NOZORDER); InvalidateRect (hWnd, NULL, TRUE); return hFont; } //------------------------------------------------------------ // DoGetFontStatBar - process WM_GETFONT message for StatBar window. //------------------------------------------------------------ LONG DoGetFontStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { LPSTATUSBARDATA lpStatData; HFONT hFont = 0; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); if (lpStatData) { if (!lpStatData->hFont) lpStatData->hFont = SetStatusBarFont (lpStatData, 0); hFont = lpStatData->hFont; GlobalUnlock (GetWindowWord (hWnd, 0)); } return hFont; } //------------------------------------------------------------ // DoSetTextStatBar - process WM_SETTEXT message for StatBar window. // Place default text in field 0 //------------------------------------------------------------ LONG DoSetTextStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { char szTemp[256]; lstrcpyn (szTemp, (LPSTR) lParam, sizeof (szTemp) - 1); szTemp[255] = '\0'; SetStatusBarText (GetParent (hWnd), szTemp, 0); return 0; } //------------------------------------------------------------ // DoGetTextStatBar - process WM_GETTEXT message for StatBar window. // Return text from field 0 //------------------------------------------------------------ LONG DoGetTextStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { LPSTATUSBARDATA lpStatData; UINT usLen; LPSTR lpSrc; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); // //Copy the text into the status bar global buffer // usLen = 0; if (lpStatData->feField[0].lpszText != 0) { lpSrc = lpStatData->feField[0].lpszText; usLen = min ((UINT)lstrlen (lpSrc), wParam-1); lstrcpyn ((LPSTR) lParam, lpSrc, usLen); *((LPSTR)lParam+usLen) = '\0'; } GlobalUnlock (GetWindowWord (hWnd, 0)); return usLen; } //------------------------------------------------------------ // DoPaintStatBar - process WM_PAINT message for StatBar window. //------------------------------------------------------------ LONG DoPaintStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { INT i; LPSTATUSBARDATA lpStatData; HDC hdc; PAINTSTRUCT ps; RECT rect, rectOut; HPEN hLPen, hDPen, hOldPen; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); GetClientRect (hWnd, &rect); hdc = BeginPaint (hWnd, &ps); hDPen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNSHADOW)); hLPen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNHIGHLIGHT)); // //Draw sep line across the top of the status bar // hOldPen = SelectObject (hdc, hDPen); MoveTo (hdc, rect.left, rect.top); LineTo (hdc, rect.right, rect.top); SelectObject (hdc, hLPen); MoveTo (hdc, rect.left, rect.top+1); LineTo (hdc, rect.right, rect.top+1); SelectObject (hdc, hOldPen); // //Draw the individual fields // for (i = 0; i < lpStatData->sNumFields; i++) { GetFieldRect (lpStatData, i, &rect, &rectOut); Draw3DRect (hdc, hDPen, hLPen, &rectOut, lpStatData->feField[i].fFlags); if (lpStatData->feField[i].fFlags & FLAG_ICON) DrawFieldBitmap (lpStatData, hWnd, lpStatData->feField[i].lpszText, &rectOut); else DrawFieldText (lpStatData, hWnd, lpStatData->feField[i].lpszText, &rectOut); } DeleteObject (hDPen); DeleteObject (hLPen); EndPaint (hWnd, &ps); GlobalUnlock (GetWindowWord (hWnd, 0)); return 0; } //------------------------------------------------------------ // DoDrawItemStatBar - process WM_DRAWITEM message for StatBar window. //------------------------------------------------------------ LONG DoDrawItemStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { return SendMessage (GetParent (hWnd), wMsg, wParam, lParam); } //------------------------------------------------------------ // DoMeasureItemStatBar - process WM_MEASUREITEM message for // StatBar window. //------------------------------------------------------------ LONG DoMeasureItemStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { return SendMessage (GetParent (hWnd), wMsg, wParam, lParam); } //------------------------------------------------------------ // DoMenuCharStatBar - process WM_MENUCHAR message for status bar //------------------------------------------------------------ LONG DoMenuCharStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { return SendMessage (GetParent (hWnd), wMsg, wParam, lParam); } //------------------------------------------------------------ // DoCommandStatBar - process WM_COMMAND message for status bar //------------------------------------------------------------ LONG DoCommandStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { LPSTATUSBARDATA lpStatData; UINT idItem, wNotifyCode; HWND hwndCtl; idItem = (UINT) wParam; // Parse Parameters hwndCtl = (HWND) LOWORD(lParam); wNotifyCode = (UINT) HIWORD(lParam); lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); lpStatData->dwData = idItem; if (lpStatData->wActCtl) SendMessage (GetParent (hWnd), WM_COMMAND, lpStatData->wActCtl, MAKELPARAM (hWnd, STATN_PICKMENU)); GlobalUnlock (GetWindowWord (hWnd, 0)); return 0; } //------------------------------------------------------------ // Cheat routine so that statbar can determine the total // height of an owner drawn menu. //------------------------------------------------------------ INT ComputeItemHeight (HWND hWnd, INT sID) { INT cy; if ((sID == -2) || (sID == -3)) cy = 3; else if (sID == -4) cy = 6; else cy = GetStatusBarHeight (GetParent (hWnd)) - 2; return cy; } //------------------------------------------------------------ // DoLButtonDownStatBar - process WM_LBUTTONDOWN message for window. //------------------------------------------------------------ LONG DoLButtonDownStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { INT i, sItem; UINT wID; LPSTATUSBARDATA lpStatData; RECT rect, rectOut; POINT pt; HDC hdc; HPEN hLPen, hDPen; HMENU hMenu, htm; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); // //Perform hit test on each field on bar // GetClientRect (hWnd, &rect); for (i = 0; i < lpStatData->sNumFields; i++) { GetFieldRect (lpStatData, i, &rect, &rectOut); if ((((INT)LOWORD (lParam) > rectOut.left) && ((INT)LOWORD (lParam) < rectOut.right)) && (((INT)HIWORD (lParam) > rectOut.top) && ((INT)HIWORD (lParam) < rectOut.bottom))) { break; } } sItem = i; if (sItem < lpStatData->sNumFields) { hdc = GetDC (hWnd); hDPen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNSHADOW)); hLPen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNHIGHLIGHT)); pt.x = rectOut.left; pt.y = rect.top; ClientToScreen (hWnd, &pt); rect = rectOut; rect.right = rect.right - rect.left; rect.bottom = rect.bottom - rect.top; ClientToScreen (hWnd, (LPPOINT)&rect); rect.right = rect.right + rect.left; rect.bottom = rect.bottom + rect.top; lpStatData->wActCtl = IDD_STATBAR + sItem; switch (lpStatData->feField[sItem].fFlags & FLAG_TYPEMASK) { case STATT_BUTTON: //Redraw the Field Draw3DRect (hdc, hDPen, hLPen, &rectOut, FLAG_DIN); // Capture the mouse SetCapture (hWnd); lpStatData->sCap = sItem+1; break; case STATT_MENU: //Redraw the Field Draw3DRect (hdc, hDPen, hLPen, &rectOut, FLAG_DIN); // Get menu handle from data structure hMenu = HIWORD (lpStatData->feField[sItem].dwData); // Do this to force popup flag. The works around a bug // in Windows. htm = CreateMenu (); InsertMenu (htm, 0, MF_POPUP, hMenu, NULL); hMenu = GetSubMenu (htm, 0); if (hMenu) { // pt.y -= GetMenuItemCount (hMenu) * GetSystemMetrics (SM_CYMENU); for (i = 0; i < GetMenuItemCount (hMenu); i++) { wID = GetMenuItemID (hMenu, i); pt.y -= ComputeItemHeight (hWnd, (INT)wID); } pt.y -= 2; TrackPopupMenu (hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, &rect); RemoveMenu (htm, 0, MF_BYPOSITION); DestroyMenu (htm); } Draw3DRect (hdc, hDPen, hLPen, &rectOut, lpStatData->feField[sItem].fFlags); break; case STATT_DYNAMENU: //Redraw the Field Draw3DRect (hdc, hDPen, hLPen, &rectOut, FLAG_DIN); // Ask parent for handle to dynamically created menu hMenu = (HMENU) SendMessage (GetParent (hWnd), WM_COMMAND, IDD_STATBAR + sItem, MAKELPARAM (hWnd, STATN_CREATEMENU)); if (hMenu) { for (i = 0; i < GetMenuItemCount (hMenu); i++) { wID = GetMenuItemID (hMenu, i); pt.y -= ComputeItemHeight (hWnd, (INT)wID); } pt.y -= 2; TrackPopupMenu (hMenu, TPM_LEFTALIGN, pt.x, pt.y, 0, hWnd, &rect); DestroyMenu (hMenu); } Draw3DRect (hdc, hDPen, hLPen, &rectOut, lpStatData->feField[sItem].fFlags); if (hMenu) { // Ask parent to clean up after dynamically created menu SendMessage (GetParent (hWnd), WM_COMMAND, IDD_STATBAR + sItem, MAKELPARAM (hWnd, STATN_DESTROYMENU)); } break; default: // OutputDebugString ("Other statbar field type processed!\n"); break; } DeleteObject (hDPen); DeleteObject (hLPen); ReleaseDC (hWnd, hdc); } GlobalUnlock (GetWindowWord (hWnd, 0)); return 0; } //------------------------------------------------------------ // DoLButtonUpStatBar - process WM_LBUTTONUP message for window. //------------------------------------------------------------ LONG DoLButtonUpStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { INT i; LPSTATUSBARDATA lpStatData; RECT rect, rectOut; HDC hdc; HPEN hLPen, hDPen; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); // If in capture mode, a button has been clicked on the bar if (lpStatData->sCap) { // Free the mouse! ReleaseCapture(); // Zero base the number. lpStatData->sCap--; // //Perform hit test on each field on bar // GetClientRect (hWnd, &rect); for (i = 0; i < lpStatData->sNumFields; i++) { GetFieldRect (lpStatData, i, &rect, &rectOut); if ((((INT)LOWORD (lParam) > rectOut.left) && ((INT)LOWORD (lParam) < rectOut.right)) && (((INT)HIWORD (lParam) > rectOut.top) && ((INT)HIWORD (lParam) < rectOut.bottom))) { break; } } // If button up on button, notify parent if ((i < lpStatData->sNumFields) && (i == lpStatData->sCap)) { SendMessage (GetParent(hWnd), WM_COMMAND, IDD_STATBAR + i, MAKELPARAM (hWnd, STATN_CLICKED)); } // Restore normal look to button hdc = GetDC (hWnd); hDPen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNSHADOW)); hLPen = CreatePen (PS_SOLID, 1, GetSysColor (COLOR_BTNHIGHLIGHT)); GetFieldRect (lpStatData, lpStatData->sCap, &rect, &rectOut); Draw3DRect (hdc, hDPen, hLPen, &rectOut, lpStatData->feField[lpStatData->sCap].fFlags); DeleteObject (hDPen); DeleteObject (hLPen); ReleaseDC (hWnd, hdc); lpStatData->sCap = 0; } GlobalUnlock (GetWindowWord (hWnd, 0)); return 0; } //------------------------------------------------------------ // DoPostEventStatBar - process STATM_POSTEVENT message // for status bar window. //------------------------------------------------------------ LONG DoPostEventStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { LPSTATUSBARDATA lpStatData; RECT rect, rectWnd; UINT wKeys; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); wKeys = 0; if (GetKeyState (VK_SHIFT) & 0x8000) wKeys |= MK_SHIFT; if (GetKeyState (VK_CONTROL) & 0x8000) wKeys |= MK_CONTROL; GetClientRect (hWnd, &rectWnd); GetFieldRect (lpStatData, wParam, &rectWnd, &rect); PostMessage (hWnd, WM_LBUTTONDOWN, wKeys, MAKELPARAM (rect.left + 1, rect.top + 1)); PostMessage (hWnd, WM_LBUTTONUP, wKeys, MAKELPARAM (rect.left + 1, rect.top + 1)); GlobalUnlock (GetWindowWord (hWnd, 0)); return 0; } //------------------------------------------------------------ // DoGetEventDataStatBar - process STATM_GETEVENTDATA message // for status bar window. //------------------------------------------------------------ LONG DoGetEventDataStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { LPSTATUSBARDATA lpStatData; DWORD dwData; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); dwData = lpStatData->dwData; GlobalUnlock (GetWindowWord (hWnd, 0)); return (LONG)dwData; } //------------------------------------------------------------ // DoGetItemDataStatBar - process STATM_GETITEMDATA message // for status bar window. //------------------------------------------------------------ LONG DoGetItemDataStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { LPSTATUSBARDATA lpStatData; DWORD dwData = 0; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); wParam -= IDD_STATBAR; if (((INT)wParam < lpStatData->sNumFields) && ((INT)wParam >= 0)) dwData = lpStatData->feField[wParam].dwData; GlobalUnlock (GetWindowWord (hWnd, 0)); return (LONG)dwData; } //------------------------------------------------------------ // DoDestroyStatBar - process WM_DESTROY message for status bar // window. //------------------------------------------------------------ LONG DoDestroyStatBar (HWND hWnd, UINT wMsg, UINT wParam, LONG lParam) { LPSTATUSBARDATA lpStatData; INT i; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); DeleteObject (lpStatData->hFont); for (i = 0; i < lpStatData->sNumFields; i++) { if (lpStatData->feField[i].fFlags & FLAG_ICON) { DeleteObject (LOWORD(lpStatData->feField[i].lpszText)); // DestroyIcon (HIWORD(lpStatData->feField[i].lpszText)); } if ((lpStatData->feField[i].fFlags & FLAG_TYPEMASK) == STATT_MENU) { DestroyMenu ((HMENU) HIWORD (lpStatData->feField[i].dwData)); } } fUnHook = TRUE; GlobalUnlock (GetWindowWord (hWnd, 0)); GlobalFree (GetWindowWord (hWnd, 0)); return DefWindowProc(hWnd, wMsg, wParam, lParam); } //------------------------------------------------------------ // SetStatusBarFont - returns a font handle for the status // bar font. //------------------------------------------------------------ HFONT SetStatusBarFont (LPSTATUSBARDATA lpStatData, HFONT hFont) { HDC hdc; LOGFONT lf; INT sFHeight; // //Create the status bar font and compute its size // if (hFont == 0) { hdc = GetDC(NULL); sFHeight = MulDiv(-10, GetDeviceCaps(hdc, LOGPIXELSY), 72); hFont = CreateFont(sFHeight, 0, 0, 0, FW_BOLD, 0, 0, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "Helv"); ReleaseDC(NULL, hdc); } else { // Check for valid font if (GetObject (hFont, sizeof (lf), &lf) == 0) { if (lpStatData->hFont == 0) return SetStatusBarFont (lpStatData, 0); else return lpStatData->hFont; } if ((lpStatData->hFont != hFont) && (lpStatData->hFont)) DeleteObject (lpStatData->hFont); } lpStatData->hFont = hFont; return hFont; } //------------------------------------------------------------ // DrawFieldText - Draws text in a status bar field //------------------------------------------------------------ void DrawFieldText (LPSTATUSBARDATA lpStatData, HWND hWnd, LPSTR lpszText, RECT *rect) { HDC hdc; HFONT hOldFont; rect->top += 2; rect->bottom -= 2; rect->left += 5; rect->right -= 5; hdc = GetDC (hWnd); hOldFont = SelectObject (hdc, lpStatData->hFont); SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT)); SetBkColor (hdc, GetSysColor (COLOR_BTNFACE)); ExtTextOut (hdc, rect->left, rect->top, ETO_CLIPPED | ETO_OPAQUE, rect, "", 0, NULL); if (lpszText) DrawText (hdc, lpszText, -1, rect, DT_VCENTER | DT_CENTER | DT_SINGLELINE); SelectObject (hdc, hOldFont); ReleaseDC (hWnd, hdc); return; } //------------------------------------------------------------ // DrawFieldBitmap - Draws a bitmap in a status bar field //------------------------------------------------------------ void DrawFieldBitmap (LPSTATUSBARDATA lpStatData, HWND hWnd, LPSTR lpszText, RECT *rect) { HDC hdc, hdcMem; HBITMAP hOld; rect->top += 1; rect->bottom -= 1; rect->left += 1; rect->right -= 1; hdc = GetDC (hWnd); hdcMem = CreateCompatibleDC (NULL); hOld = SelectObject (hdcMem, LOWORD (lpszText)); BitBlt (hdc, rect->left+1, rect->top+1, rect->right - rect->left, rect->bottom - rect->top, hdcMem, 0, 0, SRCCOPY); SelectObject (hdcMem, hOld); ReleaseDC (hWnd, hdc); DeleteDC (hdcMem); return; } //------------------------------------------------------------ // GetFieldRect - Computes the rectangle for a given field. //------------------------------------------------------------ void GetFieldRect (LPSTATUSBARDATA lpStatData, INT sField, RECT *rect, RECT *rectOut) { INT i, sRight; *rectOut = *rect; rectOut->top += 3; rectOut->bottom -= 3; rectOut->left += 3; rectOut->right -= 3; sRight = rectOut->right; for (i = 0; i < sField; i++) if (lpStatData->feField[i].sWidth) rectOut->left += lpStatData->feField[i].sWidth + 3; else break; if (lpStatData->feField[i].sWidth == 0) { for (i = lpStatData->sNumFields - 1; i > sField; i--) rectOut->right -= lpStatData->feField[i].sWidth + 3; if (lpStatData->feField[sField].sWidth != 0) rectOut->left = rectOut->right - lpStatData->feField[sField].sWidth; } else if (sField == lpStatData->sNumFields - 1) rectOut->right = sRight; else rectOut->right = rectOut->left + lpStatData->feField[i].sWidth - 3; return; } //------------------------------------------------------------ // DrawSBText - Displays text in a status bar field //------------------------------------------------------------ void DrawSBText (HWND hWnd, char far *lpszText, INT sField) { LPSTATUSBARDATA lpStatData; RECT rect; lpStatData = (LPSTATUSBARDATA) GlobalLock (GetWindowWord (hWnd, 0)); GetClientRect (hWnd, &rect); GetFieldRect (lpStatData, sField, &rect, &rect); if (lpStatData->feField[sField].fFlags & FLAG_ICON) DrawFieldBitmap (lpStatData, hWnd, lpszText, &rect); else DrawFieldText (lpStatData, hWnd, lpszText, &rect); GlobalUnlock (GetWindowWord (hWnd, 0)); return; } //------------------------------------------------------------ // Draw3DRect - Routine that draws a 3D effect rectangle //------------------------------------------------------------ void Draw3DRect (HDC hdc, HPEN hDPen, HPEN hLPen, RECT far *rect, UINT fFlags) { HPEN hOldPen = 0; if (fFlags & FLAG_DFLAT) { hOldPen = SelectObject (hdc, hDPen); MoveTo (hdc, rect->left, rect->bottom); LineTo (hdc, rect->left, rect->top); LineTo (hdc, rect->right+1, rect->top); MoveTo (hdc, rect->left+1, rect->bottom); LineTo (hdc, rect->right, rect->bottom); LineTo (hdc, rect->right, rect->top); } else if (fFlags & FLAG_DOUT) { hOldPen = SelectObject (hdc, hLPen); //Start at bottom left, draw dark pen up and over top. MoveTo (hdc, rect->left, rect->bottom); LineTo (hdc, rect->left, rect->top); LineTo (hdc, rect->right+1, rect->top); SelectObject (hdc, hDPen); //Start at bottom left, draw light pen over and up. MoveTo (hdc, rect->left+1, rect->bottom); LineTo (hdc, rect->right, rect->bottom); LineTo (hdc, rect->right, rect->top); } else if (fFlags & FLAG_DIN2) { hOldPen = SelectObject (hdc, hDPen); //Start at bottom left, draw dark pen up and over top. MoveTo (hdc, rect->left, rect->top); LineTo (hdc, rect->right, rect->top); MoveTo (hdc, rect->right-1, rect->top+1); LineTo (hdc, rect->left+1, rect->top+1); SelectObject (hdc, hLPen); //Start at bottom left, draw light pen over and up. MoveTo (hdc, rect->left, rect->bottom); LineTo (hdc, rect->right, rect->bottom); MoveTo (hdc, rect->right-1, rect->bottom-1); LineTo (hdc, rect->left+1, rect->bottom-1); } else if (fFlags & FLAG_DIN) { hOldPen = SelectObject (hdc, hDPen); //Start at bottom left, draw dark pen up and over top. MoveTo (hdc, rect->left, rect->bottom); LineTo (hdc, rect->left, rect->top); LineTo (hdc, rect->right+1, rect->top); SelectObject (hdc, hLPen); //Start at bottom left, draw light pen over and up. MoveTo (hdc, rect->left+1, rect->bottom); LineTo (hdc, rect->right, rect->bottom); LineTo (hdc, rect->right, rect->top); // } else { // hOldPen = SelectObject (hdc, hDPen); // //Start at bottom left, draw dark pen up and over top. // MoveTo (hdc, rect->left, rect->bottom); // LineTo (hdc, rect->left, rect->top); // LineTo (hdc, rect->right+1, rect->top); // // SelectObject (hdc, hLPen); // //Start at bottom left, draw light pen over and up. // MoveTo (hdc, rect->left+1, rect->bottom); // LineTo (hdc, rect->right, rect->bottom); // LineTo (hdc, rect->right, rect->top); } if (hOldPen) SelectObject (hdc, hOldPen); }