The program of this section demonstrates the use of bitmaps in menus. It consists of the following source files.
A couple of snapshots of the program running are shown below.
![]() | ![]() |
The bitmaps for the main menu (being FILE, EDIT and FONT) as well as the bitmap embedded in the system menu (shakey HELP) are all loaded as resources. The portion of the resource script that identifies these bitmaps is shown below.
BitmapIdentityEdit BITMAP EditLabel.bmp BitmapIdentityFile BITMAP FileLabel.bmp BitmapIdentityFont BITMAP FontLabel.bmp BitmapIdentityHelp BITMAP BigHelp.bmp
Each of these bitmaps may be created in the graphics program of the readers choice. Once created, they reside on the hard disk with the given names. Although these bitmaps are loaded, they are later scaled using an algorithm to be discussed. The bitmaps for the font names are created within the program.
The data structure for the window procedure declares seven bitmap handles as shown below.
struct window_data { handle bitmap_help; handle bitmap_edit; handle bitmap_file; handle bitmap_font; handle bitmap_array[3]; int current_font; window_data() { current_font = MenuItemCourier; } };
These handles are initialized during the processing of the creation message - all of which is shown below.
case message::create: { window_data* data = new window_data(); set_window_pointer(window_handle, 0, (void*)data); handle menu = create_menu(); handle module_handle = get_module_handle<character>(); handle file_menu = load_menu(module_handle, (const character*)MenuFile); data->bitmap_file = stretch_the_bitmap(load_bitmap(module_handle, (const character*)BitmapIdentityFile)); append_menu(menu, menu_item_flag::bitmap | menu_item_flag::submenu, file_menu, (character*)data->bitmap_file); handle edit_menu = load_menu(module_handle, (const character*)MenuEdit); data->bitmap_edit = stretch_the_bitmap(load_bitmap(module_handle, (const character*)BitmapIdentityEdit)); append_menu(menu, menu_item_flag::bitmap | menu_item_flag::submenu, edit_menu, (character*)data->bitmap_edit); handle font_menu = create_menu(); for (int i = 0; i < 3; i++) { data->bitmap_array[i] = get_font_bitmap(i); append_menu(font_menu, menu_item_flag::bitmap, (void*)(MenuItemCourier + i), (character*)data->bitmap_array[i]); } data->bitmap_font = stretch_the_bitmap(load_bitmap(module_handle, (const character*)BitmapIdentityFont)); append_menu(menu, menu_item_flag::bitmap | menu_item_flag::submenu, (void*)font_menu, (character*)data->bitmap_font); set_menu(window_handle, menu); handle system_menu = get_system_menu(window_handle, false); data->bitmap_help = stretch_the_bitmap(load_bitmap(module_handle, (const character*)BitmapIdentityHelp)); append_menu(system_menu, menu_item_flag::separator, (handle)null, (const character*)null); append_menu(system_menu, menu_item_flag::bitmap, (void*)MenuItemHelp, (const character*)data->bitmap_help); check_menu_item(get_menu(window_handle), data->current_font, menu_item_flag::checked); } break;
Firstly, an empty menu is created (menu). The file menu is then loaded as a resource (FileMenu) and associated with the bitmap bitmap_file upon adding it to the main menu (menu). Likewise for the edit menu. The templates of the file and edit menus may be found in the resource file. Next, an empty font menu is created (FontMenu). The items associated with bitmaps are then appended to the font menu. The font menu is then added to the main menu. The main menu is then associated with the client window. A couple of items are then added to the system menu.
Perhaps the code to stretch the bitmaps is the most complicated aspect of this application. It uses a number memory device contexts and defines a bitmap of return. This code is shown below.
handle stretch_the_bitmap(handle bitmap1) { handle device_context = create_informational_device_context(L"DISPLAY", (const character*)null, (const character*)null, (const device_mode*)null); text_metrics text_metrics_get; get_text_metrics(device_context, &text_metrics_get); handle memory_device1 = create_memory_device_context(device_context); handle memory_device2 = create_memory_device_context(device_context); delete_device_context(device_context); bitmap_definition bitmap_definition1; get_object(bitmap1, sizeof(bitmap_definition), (character*)&bitmap_definition1); bitmap_definition bitmap_definition2 = bitmap_definition1; bitmap_definition2.width = (text_metrics_get.average_character_width * bitmap_definition2.width) / 4; bitmap_definition2.height = (text_metrics_get.height * bitmap_definition2.height) / 8; bitmap_definition2.bytes = ((bitmap_definition2.width + 15) / 16) * 2; handle bitmap2 = create_bitmap_indirect(&bitmap_definition2); select_object(memory_device1, bitmap1); select_object(memory_device2, bitmap2); stretch_bit_block_transfer(memory_device2, 0, 0, bitmap_definition2.width, bitmap_definition2.height, memory_device1, 0, 0, bitmap_definition1.width, bitmap_definition1.height, raster_operation::source_copy); delete_device_context(memory_device1); delete_device_context(memory_device2); delete_object(bitmap1); return bitmap2; }
In the above code, the bitmap is stretched according to the size of the currently selected system font. The original bitmaps of the fonts were created where the system font was of height 8 pixels and of width 4 pixels. This gives rise to the scaling calculations above.
The bitmaps that were loaded as resources have been accounted for, so that it remains to explain the creation of the other three - the Courier, Arial and Times bitmaps. The function that does this is get_font_bitmap - which is shown below.
handle get_font_bitmap(int i) { character courier[50]; character arial[50]; character times[50]; load_string(0, StringCourier, courier, 50); load_string(0, StringArial, arial, 50); load_string(0, StringTimes, times, 50); character* face_names[3] = { courier,arial,times }; handle device_context = create_informational_device_context(L"DISPLAY", (const character*)null, (const character*)null, (const device_mode*)null); text_metrics text_metrics_get; get_text_metrics(device_context, &text_metrics_get); logical_font logical_font_create; logical_font_create.height = 2 * text_metrics_get.height; copy_string((character*)logical_font_create.face_name, face_names[i]); handle memory_device = create_memory_device_context(device_context); handle font = (handle)select_object(memory_device, create_font_indirect(&logical_font_create)); idimensions text; get_text_extent(memory_device, face_names[i], string_length(face_names[i]), &text); handle bitmap = create_bitmap(text(0), text(1), 1, 1, (handle)null); select_object(memory_device, bitmap); text_out(memory_device, 0, 0, face_names[i], string_length(face_names[i])); delete_object(select_object(memory_device, font)); delete_device_context(memory_device); delete_device_context(device_context); return bitmap; }
In the above code, one of three integers representing a name of a font should be passed. A font of the given name is created. A bitmap of an appropriate size (for drawing the text naming the font) is created. That bitmap is selected into a memory device context and the text is rendered to the device context thereby creating a bitmap containing the name of the font.