USING BITMAPS IN MENUS

Character strings are not the only way to display a menu item. You can also use a bitmap. If you immediately recoiled at the thought of pictures of file folders, paste jars, and trash cans in a menu, don't think of pictures. Think instead of how useful menu bitmaps might be for a drawing program. Think of using different fonts and font sizes, line widths, hatch patterns, and colors in your menus.

The program we're going to examine is called GRAFMENU (”graphics menu“). The top-level menu is shown in Figure 9-8. The enlarged block letters are obtained from 40-by-16-pixel monochrome bitmap files created in SDKPAINT and saved as .BMP files; they could be pictures instead. Choosing FONT from the menu invokes a popup containing three options—Courier, Helvetica, and Times Roman—each displayed in its respective font (Figure 9-9). These bitmaps were created in the program using a technique involving a ”memory device context.“

Finally, when you pull down the system menu, you see that you have access to some ”help“ information, with the word ”Help“ perhaps mirroring the desperation of a new user (Figure 9-10). This 64-by-64-pixel monochrome bitmap was created in SDKPAINT.

The GRAFMENU program, including the four bitmaps created in SDKPAINT, is shown in Figure 9-11.

GRAFMENU.MAK

#------------------------

# GRAFMENU.MAK make file

#------------------------

grafmenu.exe : grafmenu.obj grafmenu.def grafmenu.res

link grafmenu, /align:16, NUL, /nod slibcew libw, grafmenu

rc grafmenu.res

grafmenu.obj : grafmenu.c grafmenu.h

cl -c -Gsw -Ow -W2 -Zp grafmenu.c

grafmenu.res : grafmenu.rc grafmenu.h \

editlabl.bmp filelabl.bmp fontlabl.bmp bighelp.bmp

rc -r grafmenu.rc

GRAFMENU.C

/*----------------------------------------------

GRAFMENU.C -- Demonstrates Bitmap Menu Items

(c) Charles Petzold, 1990

----------------------------------------------*/

#include <windows.h>

#include <string.h>

#include "grafmenu.h"

long FAR PASCAL WndProc (HWND, WORD, WORD, LONG) ;

HBITMAP StretchBitmap (HBITMAP) ;

HBITMAP GetBitmapFont (int) ;

char szAppName [] = "GrafMenu" ;

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,

LPSTR lpszCmdLine, int nCmdShow)

{

HBITMAP hBitmapHelp, hBitmapFile, hBitmapEdit,

hBitmapFont, hBitmapPopFont [3] ;

HMENU hMenu, hMenuPopup ;

HWND hwnd ;

int i ;

MSG msg ;

WNDCLASS wndclass ;

if (!hPrevInstance)

{

wndclass.style = CS_HREDRAW | CS_VREDRAW ;

wndclass.lpfnWndProc = WndProc ;

wndclass.cbClsExtra = 0 ;

wndclass.cbWndExtra = 0 ;

wndclass.hInstance = hInstance ;

wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ;

wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;

wndclass.hbrBackground = GetStockObject (WHITE_BRUSH) ;

wndclass.lpszMenuName = NULL ;

wndclass.lpszClassName = szAppName ;

RegisterClass (&wndclass) ;

}

hMenu = CreateMenu () ;

hMenuPopup = LoadMenu (hInstance, "MenuFile") ;

hBitmapFile = StretchBitmap (LoadBitmap (hInstance, "BitmapFile")) ;

AppendMenu (hMenu, MF_BITMAP | MF_POPUP, hMenuPopup,

(LPSTR) (LONG) hBitmapFile) ;

hMenuPopup = LoadMenu (hInstance, "MenuEdit") ;

hBitmapEdit = StretchBitmap (LoadBitmap (hInstance, "BitmapEdit")) ;

AppendMenu (hMenu, MF_BITMAP | MF_POPUP, hMenuPopup,

(LPSTR) (LONG) hBitmapEdit) ;

hMenuPopup = CreateMenu () ;

for (i = 0 ; i < 3 ; i++)

{

hBitmapPopFont [i] = GetBitmapFont (i) ;

AppendMenu (hMenuPopup, MF_BITMAP, IDM_COUR + i,

(LPSTR) (LONG) hBitmapPopFont [i]) ;

}

hBitmapFont = StretchBitmap (LoadBitmap (hInstance, "BitmapFont")) ;

AppendMenu (hMenu, MF_BITMAP | MF_POPUP, hMenuPopup,

(LPSTR) (LONG) hBitmapFont) ;

hwnd = CreateWindow (szAppName, "Bitmap Menu Demonstration",

WS_OVERLAPPEDWINDOW,

CW_USEDEFAULT, CW_USEDEFAULT,

CW_USEDEFAULT, CW_USEDEFAULT,

NULL, hMenu, hInstance, NULL) ;

hMenu = GetSystemMenu (hwnd, FALSE) ;

hBitmapHelp = StretchBitmap (LoadBitmap (hInstance, "BitmapHelp")) ;

AppendMenu (hMenu, MF_SEPARATOR, NULL, NULL) ;

AppendMenu (hMenu, MF_BITMAP, IDM_HELP, (LPSTR) (LONG) hBitmapHelp) ;

ShowWindow (hwnd, nCmdShow) ;

UpdateWindow (hwnd) ;

while (GetMessage (&msg, NULL, 0, 0))

{

TranslateMessage (&msg) ;

DispatchMessage (&msg) ;

}

DeleteObject (hBitmapHelp) ;

DeleteObject (hBitmapEdit) ;

DeleteObject (hBitmapFile) ;

DeleteObject (hBitmapFont) ;

for (i = 0 ; i < 3 ; i++)

DeleteObject (hBitmapPopFont [i]) ;

return msg.wParam ;

}

HBITMAP StretchBitmap (HBITMAP hBitmap1)

{

BITMAP bm1, bm2 ;

HBITMAP hBitmap2 ;

HDC hdc, hdcMem1, hdcMem2 ;

TEXTMETRIC tm ;

hdc = CreateIC ("DISPLAY", NULL, NULL, NULL) ;

GetTextMetrics (hdc, &tm) ;

hdcMem1 = CreateCompatibleDC (hdc) ;

hdcMem2 = CreateCompatibleDC (hdc) ;

DeleteDC (hdc) ;

GetObject (hBitmap1, sizeof (BITMAP), (LPSTR) &bm1) ;

bm2 = bm1 ;

bm2.bmWidth = (tm.tmAveCharWidth * bm2.bmWidth) / 4 ;

bm2.bmHeight = (tm.tmHeight * bm2.bmHeight) / 8 ;

bm2.bmWidthBytes = ((bm2.bmWidth + 15) / 16) * 2 ;

hBitmap2 = CreateBitmapIndirect (&bm2) ;

SelectObject (hdcMem1, hBitmap1) ;

SelectObject (hdcMem2, hBitmap2) ;

StretchBlt (hdcMem2, 0, 0, bm2.bmWidth, bm2.bmHeight,

hdcMem1, 0, 0, bm1.bmWidth, bm1.bmHeight, SRCCOPY) ;

DeleteDC (hdcMem1) ;

DeleteDC (hdcMem2) ;

DeleteObject (hBitmap1) ;

return hBitmap2 ;

}

HBITMAP GetBitmapFont (int i)

{

static struct

{

BYTE lfPitchAndFamily ;

BYTE lfFaceName [LF_FACESIZE] ;

char *szMenuText ;

}

lfSet [3] =

{

FIXED_PITCH | FF_MODERN, "Courier", "Courier",

VARIABLE_PITCH | FF_SWISS, "Helvetica", "Helvetica",

VARIABLE_PITCH | FF_ROMAN, "Tms Rmn", "Times Roman"

} ;

DWORD dwSize ;

HBITMAP hBitmap ;

HDC hdc, hdcMem ;

HFONT hFont ;

LOGFONT lf ;

hFont = GetStockObject (SYSTEM_FONT) ;

GetObject (hFont, sizeof (LOGFONT), (LPSTR) &lf) ;

lf.lfHeight *= 2 ;

lf.lfWidth *= 2 ;

lf.lfPitchAndFamily = lfSet[i].lfPitchAndFamily ;

strcpy (lf.lfFaceName, lfSet[i].lfFaceName) ;

hdc = CreateIC ("DISPLAY", NULL, NULL, NULL) ;

hdcMem = CreateCompatibleDC (hdc) ;

SelectObject (hdcMem, CreateFontIndirect (&lf)) ;

dwSize = GetTextExtent (hdcMem, lfSet[i].szMenuText,

strlen (lfSet[i].szMenuText)) ;

hBitmap = CreateBitmap (LOWORD (dwSize)-1, HIWORD (dwSize), 1, 1, NULL) ;

SelectObject (hdcMem, hBitmap) ;

TextOut (hdcMem, 0, 0, lfSet[i].szMenuText,

strlen (lfSet[i].szMenuText)) ;

DeleteObject (SelectObject (hdcMem, hFont)) ;

DeleteDC (hdcMem) ;

DeleteDC (hdc) ;

return hBitmap ;

}

long FAR PASCAL WndProc (HWND hwnd, WORD message, WORD wParam, LONG lParam)

{

HMENU hMenu ;

static short nCurrentFont = IDM_COUR ;

switch (message)

{

case WM_CREATE :

CheckMenuItem (GetMenu (hwnd), nCurrentFont, MF_CHECKED) ;

return 0 ;

case WM_SYSCOMMAND :

switch (wParam)

{

case IDM_HELP :

MessageBox (hwnd, "Help not yet implemented.",

szAppName, MB_OK | MB_ICONEXCLAMATION) ;

return 0 ;

}

break ;

case WM_COMMAND :

switch (wParam)

{

case IDM_NEW :

case IDM_OPEN :

case IDM_SAVE :

case IDM_SAVEAS :

case IDM_UNDO :

case IDM_CUT :

case IDM_COPY :

case IDM_PASTE :

case IDM_CLEAR :

MessageBeep (0) ;

return 0 ;

case IDM_COUR :

case IDM_HELV :

case IDM_TMSRMN :

hMenu = GetMenu (hwnd) ;

CheckMenuItem (hMenu, nCurrentFont, MF_UNCHECKED) ;

nCurrentFont = wParam ;

CheckMenuItem (hMenu, nCurrentFont, MF_CHECKED) ;

return 0 ;

}

break ;

case WM_DESTROY :

PostQuitMessage (0) ;

return 0 ;

}

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

}

GRAFMENU.RC

/*-----------------------------

GRAFMENU.RC resource script

-----------------------------*/

#include "grafmenu.h"

BitmapEdit BITMAP editlabl.bmp

BitmapFile BITMAP filelabl.bmp

BitmapFont BITMAP fontlabl.bmp

BitmapHelp BITMAP bighelp.bmpMenuFile MENU

{

MENUITEM "&New", IDM_NEW

MENUITEM "&Open...", IDM_OPEN

MENUITEM "&Save", IDM_SAVE

MENUITEM "Save &As...", IDM_SAVEAS

}

MenuEdit MENU

{

MENUITEM "&Undo", IDM_UNDO

MENUITEM SEPARATOR

MENUITEM "Cu&t", IDM_CUT

MENUITEM "&Copy", IDM_COPY

MENUITEM "&Paste", IDM_PASTE

MENUITEM "C&lear", IDM_CLEAR

}

GRAFMENU.H

/*------------------------

GRAFMENU.H header file

------------------------*/

#define IDM_NEW 1

#define IDM_OPEN 2

#define IDM_SAVE 3

#define IDM_SAVEAS 4

#define IDM_UNDO 5

#define IDM_CUT 6

#define IDM_COPY 7

#define IDM_PASTE 8

#define IDM_CLEAR 9

#define IDM_COUR 10

#define IDM_HELV 11

#define IDM_TMSRMN 12

#define IDM_HELP 13

EDITLABL.BMP

FILELABL.BMP

FONTLABL.BMP

BIGHELP.BMP

GRAFMENU.DEF

;-------------------------------------

; GRAFMENU.DEF module definition file

;-------------------------------------

NAME GRAFMENU

DESCRIPTION 'Demo of Bitmapped Menu Items (c) Charles Petzold, 1990'

EXETYPE WINDOWS

STUB 'WINSTUB.EXE'

CODE PRELOAD MOVEABLE DISCARDABLE

DATA PRELOAD MOVEABLE MULTIPLE

HEAPSIZE 1024

STACKSIZE 8192

EXPORTS WndProc

To examine the subject of bitmaps and menus in the detail it deserves, we'll need to cross the border into GDI territory—a full exploration of which awaits us in the next section of this book. The discussion here will serve as a preview of topics that we'll return to again in Chapter 11.