Using ViewKit Menu Subclasses

This section describes the features of each ViewKit ObjectPak menu subclass. In addition to specific member functions listed, each class also supports all functions provided by the VkMenu class.

Menu Bar

The VkMenuBar class provides a menu bar designed to work with the VkWindow class. In addition to the functions described in this section, the VkWindow class provides some member functions for installing a VkMenuBar object as a menu bar. "Menu Bar Support" describes the functions provided by VkWindow.

Examples of menu bar construction were given in "Creating a Menubar Using a Static Description" (Example 24.) and "Creating a Menubar Using a Static Description" (Example 25.).

Menu Bar Constructors

There are four different versions of the VkMenuBar constructor:

VkMenuBar(Boolean showHelpPane = TRUE)
VkMenuBar(const char *name,
Boolean showHelpPane = TRUE);
VkMenuBar(VkMenuDesc *menuDesc,
XtPointer defaultCientData= NULL,
Boolean showHelpPane = TRUE)
VkMenuBar(const char *name,
VkMenuDesc *menuDesc,
XtPointer defaultCientData = NULL,
Boolean showHelpPane = TRUE)

The forms of the constructor that do not take a name argument automatically use the name "menuBar".

If you use a form of the VkMenuBar constructor that accepts a menuDesc argument, the constructor creates a menu from the VkMenuDesc structure you provide.

Some forms of the constructor also accept an optional defaultClientData argument. If provided, any menu item that does not provide a client data argument will use this argument instead. This allows menus to be specified statically, while still allowing an instance pointer to be used with callbacks, as described in "Constructing Menus" .

The last argument to each version of the constructor is a Boolean value that specifies whether the constructor should create a help pane that interfaces to the help system. The default is to automatically provide the help pane. The help pane is implemented by the VkHelpPane class, described in "ViewKit Help Menu" .

Menu Bar access functions

The VkMenuBar class also provides the helpPane() member function:

VkHelpPane *helpPane() const

helpPane() returns a pointer to the menu bar's help pane. If the menu bar does not have a help pane, helpPane() returns NULL.

Submenus

The VkSubMenu class supports pull-down menu panes. You can use these menu panes within a menu bar (a VkMenuBar object), or as a cascading, pull-right menu in a popup or other pull-down menu.

Submenu constructor

You seldom need to instantiate a VkSubMenu object directly. You can add a submenu to any type of menu by calling that menu's addSubmenu() member function. You can also add menu panes to the menu bar of a VkWindow object by calling VkWindow::addMenuPane().

If you do need to instantiate a VkSubMenu object directly, use the following constructor form:

VkSubMenu(const char *name,
VkMenuDesc *menuDesc = NULL,
XtPointer defaultClientData = NULL)

where name specifies the name of the submenu. If you supply the optional menuDesc argument, the constructor creates a menu from the VkMenuDesc structure you provide. If you supply the optional defaultClientData argument, any menu item that does not provide a client data argument will use this argument instead. This allows you to specify menus statically, and allows you to use an instance pointer with callbacks (see "Considerations for Xt Callback client data" for more detailed information.)

Submenu utility and access functions

The VkSubMenu class provides additional public member functions.

OSF/Motif supports tear-off menus that enable the user to retain a menu pane on the screen. If tear-off behavior is enabled for a menu pane, a tear-off button (appears as a dashed line) appears at the top of the menu pane. The user can tear off the pane by selecting the tear-off button.

By default, tear-off behavior is disabled for all menu panes. You can change the tear-off behavior of a submenu using VkSubMenu::showTearOff():

void showTearOff(Boolean showIt)

If you pass the Boolean value TRUE to showTearOff(), the submenu displays the tear-off button. If you pass the value FALSE, the submenu hides the tear-off button.

You can also enable tear-off behavior for a menu by setting the its XmNtearOffModel resource to XmTEAR_OFF_ENABLED (for example, in a resource file).

You can access the RowColumn widget used to implement the submenu's pulldown pane, by calling VkSubMenu::pulldown():

Widget pulldown()


Note: The baseWidget() function of a VkSubMenu object returns the CascadeButton widget required by OSF/Motif pulldown menus.


Radio Submenus

The VkRadioSubMenu class, derived from VkSubMenu, supports pull-down menu panes. Its function is similar to that of VkSubMenu, but the RowColumn widget used as a menu pane is set to exhibit radio behavior. This class is intended to support one-of-many collections of VkToggleItem objects. You can use VkRadioSubMenu objects as menu panes within a menu bar (a VkMenuBar object), or as a cascading, pull-right menu in a popup or other pull-down menu.

It is seldom necessary to directly create a VkRadioSubMenu object. You can add radio submenus to any VkMenuBar, VkPopupMenu, or VkSubMenu by calling those classes's addRadioSubmenu() member function. You can also add menu panes to a VkWindow by calling VkWindow::addRadioMenuPane().

Radio submenu constructor

You should seldom need to instantiate a VkRadioSubMenu object directly. You can add a radio submenu to any type of menu by calling that menu's addRadioSubmenu() member function. You can also add radio menu panes to the menu bar of a VkWindow object by calling VkWindow::addRadioMenuPane().

For those cases where you do need to instantiate a VkRadioSubMenu object directly, the form of the constructor you should use is:

VkRadioSubMenu(const char *name,
VkMenuDesc *menuDesc = NULL,
XtPointer defaultClientData = NULL)

name specifies the name of the radio submenu. If you provide the optional menuDesc argument, the constructor creates a menu from the VkMenuDesc structure you provide. If you provide the optional defaultClientData argument, any menu item that does not provide a client data argument will use this argument instead. This allows menus to be specified statically, while still allowing an instance pointer to be used with callbacks, as described in "Constructing Menus" .

Radio Submenu Utility and Access Functions

The VkRadioSubMenu class does not provide any public member functions in addition to those provided by the VkSubMenu class. For information on the utility and access functions provided by VkSubMenu, see "Submenus" .

Example 27. illustrates an example of using a VkRadioSubMenu class.

Example 27. Using a VkRadioSubMenu Object

Code

#include <Vk/VkApp.h>
#include <Vk/VkWindow.h>
#include <Vk/VkSubMenu.h>
#include <Vk/VkRadioSubMenu.h>
#include <Vk/VkMenu.h>
#include <Xm/Label.h>
#include <stream.h>
#include <stdlib.h>
class MyWindow: public VkWindow {
private:
static void sampleCallback( Widget, XtPointer , XtPointer);
static void quitCallback( Widget, XtPointer , XtPointer);
protected:
void sample();
public:
MyWindow( const char *name);
~MyWindow();
virtual const char* className();
};
MyWindow::~MyWindow()
{
// Empty
}
void MyWindow::sampleCallback( Widget, XtPointer clientData , XtPointer)
{
MyWindow *obj = (MyWindow *) clientData;
obj->sample();
}
const char* MyWindow::className() { return "MyWindow";}
void MyWindow::sample()
{
cout << "In Sample Callback" << "\n" << flush;
}
void MyWindow::quitCallback ( Widget, XtPointer, XtPointer )
{
exit(0);
}
MyWindow::MyWindow( const char *name) : VkWindow( name)
{
Widget label = XmCreateLabel(mainWindowWidget(), "a menu", NULL, 0);
// Add a menu pane
VkSubMenu *appMenuPane = addMenuPane("Application");
appMenuPane->addAction("One", &MyWindow::sampleCallback, (XtPointer) this);
appMenuPane->addAction("Two", &MyWindow::sampleCallback, (XtPointer) this);
appMenuPane->addSeparator();
appMenuPane->addAction("Quit", &MyWindow::quitCallback, (XtPointer) this);
// Add a menu second pane
VkSubMenu *sampleMenuPane = addMenuPane("Sample");
sampleMenuPane->addLabel("Test Label");
sampleMenuPane->addSeparator();
sampleMenuPane->addAction("An Action", &MyWindow::sampleCallback,
(XtPointer) this);
// Create a cascading submenu
VkRadioSubMenu *subMenu = sampleMenuPane->addRadioSubmenu("A Submenu");
subMenu->addToggle("foo", &MyWindow::sampleCallback, (XtPointer) this);
subMenu->addToggle("bar", &MyWindow::sampleCallback, (XtPointer) this);
subMenu->addToggle("baz", &MyWindow::sampleCallback, (XtPointer) this);
addView(label);
}
void main(int argc, char **argv)
{
VkApp *myApp = new VkApp("Menu", &argc, argv);
MyWindow *w1 = new MyWindow("menuwindow");
w1->show();
myApp->run();
}

Option Menus

The VkOptionMenu class supports option menus. You can use this component anywhere in your interface.


Note: Unlike many other ObjectPak components, VkOptionMenu objects are automatically visible when you create them; you do not need to call show() initially to display a VkOptionMenu object.


Option menu constructors

There are two different versions of the VkOptionMenu constructor that you can use:

VkOptionMenu(Widget parent,
VkMenuDesc *menuDesc,
XtPointer defaultClientData = NULL)
VkOptionMenu(Widget parent,
const char *name = "optionMenu",
VkMenuDesc *menuDesc = NULL,
XtPointer defaultClientData = NULL)

Note the following considerations:

  • You must provide a parent argument to specify the parent widget of the option menu.
  • The forms of the constructor that do not take a name argument automatically use the name "optionMenu".
  • If you provide the optional menuDesc argument, the constructor creates a menu from the VkMenuDesc structure you provide.

If you provide the optional defaultClientData argument, any menu item that does not provide a client data argument uses this argument instead. This allows menus to be specified statically, while still allowing an instance pointer to be used with callbacks. This is described in "Constructing Menus" .

Setting the option menu label

To specify the string that is displayed as the options menu's label, you must set the XmNlabelString resource for the menu's label widget. To do so you can:

  • Use the VkComponent::setDefaultResources() function to provide default resource values.
  • Set resource values in an external app-defaults resource file. Any values you provide in an external file will override values that you set using the VkComponent::setDefaultResources() function. This is useful when your application must support multiple languages; you can provide a separate resource file for each language supported.
  • Set the resource value directly using the XtSetValues() function. Values you set using this method override any values set using either of the above two methods. You should generally avoid using this method as it "hard codes" the resource values into the code, making them more difficult to change.

Because most option menus will be named "optionMenu", if you set the label through a resource value you should qualify the resource specifications with the name of a parent widget or component so that the X resource database can distinguish between instances of VkOptionMenu. For example, you could use resource specifications such as "*mainWindow*optionMenu*labelString" and "*graphWindow*optionMenu*labelString" to distinguish between an option menu that is a descendant of a "mainWindow" component and one that is a descendant of a "graphWindow" component respectively.

Selecting items in an option menu

You can programmatically set the selected item in an option menu using VkOptionMenu::set():

void set(char* name)
void set(int index)
void set(VkMenuItem *item)

You can specify the selected item either by a pointer to the item, the item's component name, or the item's index (position) in the option menu, where the top item in the menu has an index of zero.

Determining selected items in an option menu

There are two functions that you can use to determine which item is selected in an option menu.

You can retrieve the index (position) of the currently selected menu item using VkOptionMenu::getIndex():

int getIndex()

getIndex() returns the index (position) of the selected item, where the top item in the menu has an index of zero.

You can retrieve a pointer to the currently selected menu item using VkOptionMenu::getItem():

VkMenuItem *getItem()

Option menu utility functions

Usually, the width of the option menu is set to the width of the largest item it contains. You can force the option menu to a different width with VkOptionMenu::forceWidth()

void forceWidth(int width)

forceWidth() sets all items in the option menu to be width pixels wide.

Example 28. shows an example of using a VkOptionMenu class.

Example 28. Using a VkOptionMenu Object

Code

////////////////////////////////////////////////////////////////////
// Demonstrate ObjectPak interface to option menus
///////////////////////////////////////////////////////////////////
#include <Vk/VkApp.h>
#include <Vk/VkSimpleWindow.h>
#include <Vk/VkOptionMenu.h>
#include <stream.h>
#include <Xm/RowColumn.h>
class MyWindow: public VkSimpleWindow {
private:
static void sampleCallback( Widget, XtPointer , XtPointer);
static VkMenuDesc MyWindow::optionPaneDesc[];
protected:
void sample(Widget, XtPointer);
VkOptionMenu *_optionMenu;
public:
MyWindow( const char *name);
~MyWindow( );
virtual const char* className();
};
VkMenuDesc MyWindow::optionPaneDesc[] = {
{ ACTION, "Red", &MyWindow::sampleCallback},
{ ACTION, "Green", &MyWindow::sampleCallback},
{ ACTION, "Blue", &MyWindow::sampleCallback},
{ END},
};
MyWindow::MyWindow( const char *name) : VkSimpleWindow( name)
{
Widget rc = XmCreateRowColumn(mainWindowWidget(), "rc", NULL, 0);
_optionMenu = new VkOptionMenu(rc, optionPaneDesc, (XtPointer) this);
_optionMenu->set("Green");
addView(rc);
}
MyWindow::~MyWindow( )
{
}
const char* MyWindow::className() { return "MyWindow";}
void MyWindow::sampleCallback( Widget w, XtPointer clientData, XtPointer callData)
{
MyWindow *obj = (MyWindow *) clientData;
obj->sample(w, callData);
}
void MyWindow::sample(Widget, XtPointer)
{
cout << "Selected item's index = "
<< _optionMenu->getIndex()
<< ", name = "
<< _optionMenu->getItem()->name()
<< "\n"
<< flush;
}
void main(int argc, char **argv)
{
VkApp *app = new VkApp("Option", &argc, argv);
MyWindow *win = new MyWindow("OptionMenu");
win->show();
app->run();
}

Popup Menus

The VkPopupMenu class supports popup menus. You can attach a ViewKit ObjectPak popup menu to one or more widgets in your application so that it pops up automatically whenever the user clicks on any of those widgets with the right mouse button. You can also pop up the menu programmatically.

Popup menu constructors

There are four different versions of the VkPopupMenu constructor:

VkPopupMenu(VkMenuDesc *menuDesc,
XtPointer defaultClientData = NULL)
VkPopupMenu(const char *name = "popupMenu",
VkMenuDesc *menuDesc = NULL,
XtPointer defaultClientData = NULL)
VkPopupMenu(Widget parent,
VkMenuDesc *menuDesc = NULL,
XtPointer defaultClientData = NULL)
VkPopupMenu(Widget parent,
const char *name = "popupMenu",
VkMenuDesc *menuDesc = NULL,
XtPointer defaultClientData = NULL)

The forms of the constructor that do not take a name argument automatically use the name "popupMenu".

If you provide the optional menuDesc argument, the constructor creates a menu from the VkMenuDesc structure you provide.

If you provide the optional defaultClientData argument, any menu item that does not provide a client data argument uses this argument instead. This allows menus to be specified statically, while still allowing an instance pointer to be used with callbacks. This is described in "Constructing Menus" .

If you use a form of the VkPopupMenu constructor that accepts a parent argument, the constructor automatically attaches the menu to the widget. This builds the menu as a child of the widget and installs an event handler to pop up the menu whenever the user clicks on the widget with the right mouse button. For more information on attaching a popup menu to a widget, see the description of VkPopupMenu::attach() in "Popup Menus" .

Attaching popup menus to widgets

The VkPopupMenu::attach() function attaches a popup menu to a widget:

virtual void attach(Widget w)

The first call to attach() creates all widgets in the popup menu, using the given widget as the parent of the menu. attach() then adds an event handler to post the menu automatically whenever the user clicks on the widget with the right mouse button. Subsequent calls to attach() add the ability to post the menu over additional widgets.

Popping up popup menus

Once you have attached a popup menu to one or more widgets in your application, ObjectPak automatically posts the menu whenever the user clicks on any of those widgets with the right mouse button.

You can also post the menu programmatically even if you have not attached the popup menu to a widget.

If you have not attached the popup menu to a widget, you must first build the menu using VkPopupMenu::build():

virtual void build(Widget parent)

build() builds the menu as a child of the parent widget, but does not install an event handler to post the menu.

Once you have built the menu, you can post it with VkPopupMenu::show():

virtual void show(XEvent *buttonPressEvent)

show() requires an X ButtonPress event as an argument to position the menu on the screen. This requires you to register your own event handler to handle the ButtonPress events.

build() and show() supports applications that wish to control the posting of menus directly. Normally, attach() provides an easier way to use popup menus.

Example 29. shows an example of using a VkPopupMenu class.

Example 29. Using a VkPopupMenu Object

Code

//////////////////////////////////////////////////////////////////
// Sample program that demonstrates how to create a popup menu
/////////////////////////////////////////////////////////////////
#include <Vk/VkApp.h>
#include <Vk/VkWindow.h>
#include <Vk/VkPopupMenu.h>
#include <stream.h>
#include <Xm/Label.h>
class MyWindow: public VkWindow {
private:
VkPopupMenu *_popup;
static void sampleCallback( Widget, XtPointer , XtPointer);
void sample();
static VkMenuDesc subMenu[];
static VkMenuDesc sampleMenuPane[];
protected:
public:
MyWindow( const char *name);
~MyWindow();
virtual const char* className();
};
MyWindow::MyWindow( const char *name) : VkWindow( name)
{
Widget label = XmCreateLabel(mainWindowWidget(), "a menu", NULL, 0);
_popup = new VkPopupMenu(label, sampleMenuPane, (XtPointer) this);
addView(label);
}
MyWindow::~MyWindow( )
{
}
const char* MyWindow::className() { return "MyWindow";}
// The menu bar is essentially a set of cascading menu panes, so the
// top level of the menu tree is always defined as a list of submenus
VkMenuDesc MyWindow::sampleMenuPane[] = {
{ LABEL, "Test Label"},
{ SEPARATOR },
{ ACTION, "An Action", &MyWindow::sampleCallback},
{ ACTION, "Another Action", &MyWindow::sampleCallback},
{ SUBMENU, "A Submenu", NULL, MyWindow::subMenu},
{ END},
};
VkMenuDesc MyWindow::subMenu[] = {
{ ACTION, "foo", &MyWindow::sampleCallback},
{ ACTION, "bar", &MyWindow::sampleCallback},
{ ACTION, "baz", &MyWindow::sampleCallback},
{ END},
};
void MyWindow::sample()
{
cout << "sample callback" << "\n" << flush;
}
void MyWindow::sampleCallback( Widget, XtPointer clientData , XtPointer)
{
MyWindow *obj = (MyWindow *) clientData;
obj->sample();
}
void main(int argc, char **argv)
{
VkApp *myApp = new VkApp("Menudemo", &argc, argv);
MyWindow *menuWin = new MyWindow("MenuWindow");
menuWin->show();
myApp->run();
}

ViewKit Help Menu

The Help menu, implemented by the VkHelpPane class, provides a simple user interface to a help system. VkHelpPane does not actually implement a help system; you must link an external help system to your application. For more information on integrating a help system with your application, refer to Appendix C-- Using a Help System.

Implementation
of the help menu

VkHelpPane is a subclass of VkSubMenu. VkHelpPane automatically provides five standard menu items, as shown in Figure 20.

Figure 20. ViewKit ObjectPak Help Menu

The first four items interface to an external help system. The help system must provide help request handling and appropriate help messages for the menu item selected:

 

 

Help Menu Item

Description

"Click for Help"

Provides context-sensitive help. When the user selects this item, the cursor changes into a question mark. The user can then click on any widget in the application.

"Overview"

Requests request overview help

"Index"

Requests an index of available help topics

"Keys & Shortcuts"

Requests help on keys and shortcuts

"Product Info"

Displays the Product Information dialog described in "Maintaining Product and Version Information" . The Product Information dialog has no connection to the help system.

 

 

Because VkHelpPane is a subclass of VkSubMenu, you can also use the functions provided by VkSubMenu to add custom Help menu items and delete predefined Help menu items.

Adding the help pane to a menu

The VkMenuBar constructor, described in "Menu Bar" , accepts a showHelpPane argument. If this argument is TRUE, the default, then the VkMenuBar constructor automatically creates a VkHelpPane object and installs it in the menu bar.

You can create a VkHelpPane object and add it to another menu, for example a popup menu, but you should rarely need to do this.

X Resources for help pane

The following table describes the X resources that affect the appearance and behavior of the VkHelpPane class:

 

 

X Resource

Description

*helpMenu.labelString

Label for Help menu (default value "Help")

*helpMenu.mnemonic

Help menu mnemonic (default
value "H")

*helpMenu.helpOnContextMenuItem.labelString

Label for context-sensitive help item (default value "Click for Help")

*helpMenu.helpOnContextMenuItem.mnemonic

Context-sensitive help item
mnemonic (default value "C")

*helpMenu.helpOnContextMenuItem.accelerator

Context-sensitive help item accelerator (default value "Shift<Key>F1")

*helpMenu.helpOnContextMenuItem.acceleratorText

Context-sensitive help item accelerator label (default value "Shift+F1")

*helpMenu.helpOverviewMenuItem.labelString

Label for help overview item (default value "Overview")

*helpMenu.helpOverviewMenuItem.mnemonic

Help overview item mnemonic (default value "O")

*helpMenu.helpIndexMenuItem.labelString

Label for help index item (default value "Index")

*helpMenu.helpIndexMenuItem.mnemonic

Help index item mnemonic (default value "I")

*helpMenu.helpKeysMenuItem.labelString

Label for keys and shortcuts item (default value "Keys & Shortcuts")

*helpMenu.helpKeysMenuItem.mnemonic

Keys and shortcuts item mnemonic (default value "K")

*helpMenu.helpVersionMenuItem*labelString

Label for the product information item (default value "Product Info")

*helpMenu.helpVersionMenuItem*mnemonic

Product information item mnemonic (default value "P")