The program of this section demonstrates the specification of menus, as discussed in the previous section. The source files for the application are shown in the table below.
MenuDemonstration.cpp | The source code of the program. |
MenuDemonstration.h | The header containing the resource identitites. |
MenuDemonstration.rc | The resource file for the application. |
The program has five items in the main menu: file, edit, background, timer and help. Each of these items is associated with a popup menu. The application performs the simplest possible processing in response to menu item selection.
The identities of menu items are used in the program as well as in the resource script. This means that the header file MenuDemonstration.h is included by the program as well as the resource script. The identites for menu items are entirely arbitrary.
The notification message::command receives the selections made within the menu. In preparation for many of the selections, the first thing that the code does is query the menu associated with the frame - as shown below.
case message::command: { handle menu = get_menu(window_handle); switch (low_part(parameter1)) { .... } } break;
The first statement inside the notification message::command obtains the handle of the menu that is associated with the frame. After obtaining this handle, the program switches on the identity of the menu item. For the items from the file and edit submenus, the program simply issues a beep.
Until now, the programs that have been discussed are terminated via the system menu (which is a submenu occurring to the left of the title bar of the application). Now that the application has its own menu, it may code a proper exit selection - the coding for which is shown below.
case MenuItemExit: send_message(window_handle,message::close); break;
Upon receiving the menu selection MenuItemExit, the application sends itself the message message::close. The close notification code is shown below.
case message::close: if (message_box(window_handle, (const character*)core::resource_string(StringExit), (const character*)core::resource_string(StringApplication), message_box_style::YesNo) == item_identity::Yes) post_quit_message(); break;
One might be tempted to place the above code in the menu notification code (that is, below case MenuItemExit); however, the close notification may be received:
The menu notification MenuItemExit merely manufactures a close message so that all means of closing the application are handled in a uniform manner. The notification message::close (as shown above) is properly coded to use resource strings only.
The submenu for background color selections is used to change the color of the background of the client window. The coding is such that the current state of the background is indicated by checking the appropriate item in the menu.
The code that performs the selection by checking and unchecking the items and changing the background brush of the client is shown below.
case MenuItemWhite: case MenuItemLightGray: case MenuItemGray: case MenuItemDarkGray: case MenuItemBlack: { check_menu_item(menu, data->selection, menu_item_flag::unchecked); data->selection = low_part(parameter1); check_menu_item(menu, data->selection, menu_item_flag::checked); set_class_pointer(window_handle, class_offset::background_brush, get_standard_object(data->brush_array[low_part(parameter1) - MenuItemWhite])); invalidate_rectangle(window_handle, (const irectangle*)null, true); } break;
The currently selected item is stored in the variable selection. When a new selection is made, the check status is removed from the currently checked item and the newly selected item is then checked. A background brush is selected from the array Brusharray and it is set to be the new background brush of the window.
It is often the case that in a submenu, only one of a number of items is available, and the others should be disabled. Starting and stopping a timer is an example. Once a timer is started, the option to start should be disabled and the option to stop the timer should be enabled. Likewise, when the timer is stopped, the option to start should be enabled whilst the option to stop should be disabled. The logic to do this is shown in the menu notifications below.
case MenuItemStart: if (set_timer(window_handle, 1, 1000, (timer_procedure)null)) { enable_menu_item(menu,MenuItemStart,menu_item_flag::grayed); enable_menu_item(menu,MenuItemStop,menu_item_flag::enabled); } break; case MenuItemStop: cancel_timer(window_handle,1); enable_menu_item(menu,MenuItemStart,menu_item_flag::enabled); enable_menu_item(menu,MenuItemStop,memu_item_flag::grayed); break;
Notice that the top level menu is specified when enabling and disabling items. The function descends into submenus to locate the appropriate item. This is a reason why unique identities should be supplied in the header for all items within the menu-submenu system.