File: [Development] / inventor / apps / samples / motif / menu.c++ (download)
Revision 1.4, Fri Jun 22 22:06:56 2001 UTC (16 years, 4 months ago) by jlim
Branch: MAIN
CVS Tags: release-2_1_5-9, release-2_1_5-8, release-2_1_5-10, HEAD Changes since 1.3: +0 -5
lines
Made several changes:
1. Removed unreferenced variables.
2. Fixed miscellaneous warnings (typedefs and function declarations).
3. Moved MENUS_IN_POPUP from various files to make/ivcommondefs.
4. Fixed IRIX build problems.
|
/*
*
* Copyright (C) 2000 Silicon Graphics, Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* Further, this software is distributed without any warranty that it is
* free of the rightful claim of any third person regarding infringement
* or the like. Any license provided herein, whether implied or
* otherwise, applies only to this software file. Patent licenses, if
* any, provided herein do not apply to combinations of this program with
* other software, or any other product whatsoever.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Contact information: Silicon Graphics, Inc., 1600 Amphitheatre Pkwy,
* Mountain View, CA 94043, or:
*
* http://www.sgi.com
*
* For further information regarding this notice, see:
*
* http://oss.sgi.com/projects/GenInfo/NoticeExplan/
*
*/
//
// This demonstrates how to set up and use a Motif pulldown menu.
//
// There are two menus, File and Edit.
// The File menu has several items, including a separator line,
// and keyboard accelerators for the menu items.
// The Edit menu also has several items, but rather than simple push
// button items, this menu has a toggle button and three radio buttons.
//
// A toggle button has an on/off state.
// A set of radio buttons has the property that only one can be on
// at a time, the others are off.
//
#include <stdlib.h>
#include <X11/Intrinsic.h>
#include <Xm/Xm.h>
#include <Xm/CascadeBG.h>
#include <Xm/Form.h>
#include <Xm/RowColumn.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/Separator.h>
#include <Xm/SeparatoG.h>
#include <Xm/ToggleB.h>
#include <Xm/ToggleBG.h>
#include <Inventor/So.h>
#include <Inventor/Xt/SoXt.h>
#include <Inventor/Xt/SoXtRenderArea.h>
#include <Inventor/nodes/SoDirectionalLight.h>
#include <Inventor/nodes/SoPerspectiveCamera.h>
#include <Inventor/nodes/SoSeparator.h>
#include <Inventor/nodes/SoCone.h>
#define SCREEN(w) XScreenNumberOfScreen(XtScreen(w))
//
// Macros to set Motif toggle buttons on or off
//
#define TOGGLE_ON(BUTTON) \
XmToggleButtonSetState((Widget) BUTTON, TRUE, FALSE)
#define TOGGLE_OFF(BUTTON) \
XmToggleButtonSetState((Widget) BUTTON, FALSE, FALSE)
//
// Menu item constants - each item in a menu gets a unique id
//
#define k_OPEN_ITEM 0
#define k_SAVE_ITEM 1
#define k_PRINT_ITEM 2
#define k_QUIT_ITEM 3
#define k_ONOFF_ITEM 0
#define k_ONE_ITEM 1
#define k_TWO_ITEM 2
#define k_THREE_ITEM 3
//
// The edit menu has radio buttons. Rather than use the radio
// buttons which Motif supplies, we handle things ourselves.
//
typedef struct EditMenuItems {
Widget *items; // all the items in this menu
int which; // specifies which radio button is on
} EditMenuItems;
////////////////////////////////////////////////////////////////////////
//
// This is called by Xt when a menu item is picked from the File menu.
// The first and last parameters are not used by this routine.
// userData is specified when the menu items are created - we set it
// to be the unique id of the menu item.
//
static void
fileMenuPick(
Widget, // parameter not listed because it's not used
void *userData, // userData, specified in buildPulldownMenu
XmAnyCallbackStruct *) // parameter not listed because it's not used
//
////////////////////////////////////////////////////////////////////////
{
int which = (long) userData;
switch (which) {
case k_OPEN_ITEM: printf("Open...\n"); break;
case k_SAVE_ITEM: printf("Save...\n"); break;
case k_PRINT_ITEM: printf("Print...\n"); break;
case k_QUIT_ITEM: printf("Quit\n"); exit(0);
default: printf("UNKNOWN file menu item!!!\n"); break;
}
}
////////////////////////////////////////////////////////////////////////
//
// This is called by Xt when a menu item is picked from the Edit menu.
// w is the menu item chosen.
// cb is the callback data supplied by motif; in this case, toggle
// button data
// userData is specified when the menu items are created - we set it
// to be the unique id of the menu item.
//
static void
editMenuPick(
Widget w, // menu item chosen
void *userData, // userData, specified in buildPulldownMenu
XmAnyCallbackStruct *cb)// callback data
//
////////////////////////////////////////////////////////////////////////
{
XmToggleButtonCallbackStruct *toggle = (XmToggleButtonCallbackStruct *)cb;
int which = (long) userData;
// get the user data for this menu item.
// we expect it to be an array of widgets for this menu.
Arg args[1];
EditMenuItems *menuItems;
XtSetArg(args[0], XmNuserData, &menuItems);
XtGetValues(w, args, 1);
switch (which) {
case k_ONOFF_ITEM:
printf("On off - ");
if (toggle->set)
printf("ON\n");
else printf("OFF\n");
break;
case k_ONE_ITEM:
printf("One\n");
menuItems->which = k_ONE_ITEM;
break;
case k_TWO_ITEM:
printf("Two\n");
menuItems->which = k_TWO_ITEM;
break;
case k_THREE_ITEM:
printf("Three\n");
menuItems->which = k_THREE_ITEM;
break;
default:
printf("UNKNOWN edit menu item!!!\n");
break;
}
}
////////////////////////////////////////////////////////////////////////
//
// This is called by Xt just before the Edit menu is displayed.
// It allows us to update the radio button toggles so the currently
// selected button is toggled on.
//
static void
editMenuDisplay(Widget, void *userData, XtPointer)
//
////////////////////////////////////////////////////////////////////////
{
EditMenuItems *menuItems = (EditMenuItems *) userData;
// toggle all radio buttons off...
TOGGLE_OFF(menuItems->items[k_ONE_ITEM]);
TOGGLE_OFF(menuItems->items[k_TWO_ITEM]);
TOGGLE_OFF(menuItems->items[k_THREE_ITEM]);
// then turn the current one on...
TOGGLE_ON(menuItems->items[menuItems->which]);
}
//
// These macros assume that 'pulldown' is the variable for the menu,
// and 'menuPick' is the callback function. They are merely for convenience.
//
// A push item has no on/off state - it merely gets selected
#define PUSH_ITEM(ITEM,NAME,KONST,FUNC) \
ITEM = XtCreateManagedWidget(NAME, \
xmPushButtonGadgetClass, pulldown, args, n); \
XtAddCallback(ITEM, XmNactivateCallback,\
(XtCallbackProc) FUNC, \
(XtPointer) KONST)
// A toggle item has on/off state
#define TOGGLE_ITEM(ITEM,NAME,KONST,FUNC) \
ITEM = XtCreateManagedWidget(NAME, \
xmToggleButtonGadgetClass, pulldown, args, n); \
XtAddCallback(ITEM, XmNvalueChangedCallback,\
(XtCallbackProc) FUNC, \
(XtPointer) KONST)
// A separator draws a line between menu items
#define SEP_ITEM(NAME) \
(void) XtCreateManagedWidget("separator", \
xmSeparatorGadgetClass, pulldown, NULL, 0)
////////////////////////////////////////////////////////////////////////
//
// This creates the File menu and all its items.
// The items in this menu have accelerators (keyboard shortcuts).
//
Widget
buildFileMenu(Widget menubar)
//
////////////////////////////////////////////////////////////////////////
{
Widget items[4];
Widget pulldown;
Arg args[4];
int n;
// Tell motif to create the menu in the popup plane
Arg popupargs[4];
int popupn = 0;
#ifdef MENUS_IN_POPUP
SoXt::getPopupArgs(XtDisplay(menubar), SCREEN(menubar),
popupargs, &popupn);
#endif
pulldown = XmCreatePulldownMenu(menubar, "fileMenu", popupargs, popupn);
#ifdef MENUS_IN_POPUP
// register callbacks to load/unload the pulldown colormap when the
// pulldown menu is posted.
SoXt::registerColormapLoad(pulldown, SoXt::getShellWidget(menubar));
#endif
// Accelerators are keyboard shortcuts for the menu items
char *openAccel = "Alt <Key> o";
char *saveAccel = "Alt <Key> s";
char *printAccel = "Alt <Key> p";
char *quitAccel = "Alt <Key> q";
XmString openAccelText = XmStringCreate("Alt+o", XmSTRING_DEFAULT_CHARSET);
XmString saveAccelText = XmStringCreate("Alt+s", XmSTRING_DEFAULT_CHARSET);
XmString printAccelText = XmStringCreate("Alt+p", XmSTRING_DEFAULT_CHARSET);
XmString quitAccelText = XmStringCreate("Alt+q", XmSTRING_DEFAULT_CHARSET);
// The "..." in "Open..." signifies that choosing this menu item
// will bring up a dialog. (No dialog comes up in this demo,
// but one could conceivably bring up a file browser).
n = 0;
XtSetArg(args[n], XmNaccelerator, openAccel); n++;
XtSetArg(args[n], XmNacceleratorText, openAccelText); n++;
PUSH_ITEM(items[0], "Open...", k_OPEN_ITEM, fileMenuPick);
n = 0;
XtSetArg(args[n], XmNaccelerator, saveAccel); n++;
XtSetArg(args[n], XmNacceleratorText, saveAccelText); n++;
PUSH_ITEM(items[1], "Save...", k_SAVE_ITEM, fileMenuPick);
n = 0;
XtSetArg(args[n], XmNaccelerator, printAccel); n++;
XtSetArg(args[n], XmNacceleratorText, printAccelText); n++;
PUSH_ITEM(items[2], "Print...", k_PRINT_ITEM, fileMenuPick);
SEP_ITEM("separator");
// Quit has no "..." like the other menu items, because it
// simply executes a command - it does not bring up a dialog.
n = 0;
XtSetArg(args[n], XmNaccelerator, quitAccel); n++;
XtSetArg(args[n], XmNacceleratorText, quitAccelText); n++;
PUSH_ITEM(items[3], "Quit", k_QUIT_ITEM, fileMenuPick);
XtManageChildren(items, 4);
return pulldown;
}
////////////////////////////////////////////////////////////////////////
//
// This creates the Edit menu and all its items.
//
Widget
buildEditMenu(Widget menubar)
//
////////////////////////////////////////////////////////////////////////
{
Widget pulldown;
Arg args[4];
int n;
// items is malloced and passed as userData with the pulldown menu items.
// this way we can make sure the toggles keep up to date.
EditMenuItems *menuItems = new EditMenuItems;
menuItems->items = new Widget[4];
menuItems->which = k_ONE_ITEM;
// Tell motif to create the menu in the popup plane
Arg popupargs[4];
int popupn = 0;
#ifdef MENUS_IN_POPUP
SoXt::getPopupArgs(XtDisplay(menubar), SCREEN(menubar),
popupargs, &popupn);
#endif
pulldown = XmCreatePulldownMenu(menubar, "editMenu", popupargs, popupn);
#ifdef MENUS_IN_POPUP
// register callbacks to load/unload the pulldown colormap when the
// pulldown menu is posted.
SoXt::registerColormapLoad(pulldown, SoXt::getShellWidget(menubar));
#endif
// this callback is invoked just before the menu is displayed.
// this gives us a chance to update the radio button toggles.
XtAddCallback(pulldown, XmNmapCallback,
(XtCallbackProc) editMenuDisplay, (XtPointer) menuItems);
n = 0;
XtSetArg(args[n], XmNuserData, menuItems); n++;
TOGGLE_ITEM(menuItems->items[0], "On off", k_ONOFF_ITEM, editMenuPick);
SEP_ITEM("separator");
// the next three items are radio buttons - only one of the three
// will be toggled on at any time.
n = 0;
XtSetArg(args[n], XmNuserData, menuItems); n++;
XtSetArg(args[n], XmNindicatorType, XmONE_OF_MANY); n++;
TOGGLE_ITEM(menuItems->items[1], "One", k_ONE_ITEM, editMenuPick);
TOGGLE_ITEM(menuItems->items[2], "Two", k_TWO_ITEM, editMenuPick);
TOGGLE_ITEM(menuItems->items[3], "Three", k_THREE_ITEM, editMenuPick);
XtManageChildren(menuItems->items, 4);
return pulldown;
}
////////////////////////////////////////////////////////////////////////
//
// This creates the pulldown menu bar and its menus.
//
Widget
buildPulldownMenu(Widget parent)
//
////////////////////////////////////////////////////////////////////////
{
Widget menuButtons[2];
Widget pulldown1, pulldown2;
Arg args[8];
int n;
// menu bar
Widget menubar = XmCreateMenuBar(parent, "menuBar", NULL, 0);
pulldown1 = buildFileMenu(menubar);
pulldown2 = buildEditMenu(menubar);
// the text in the menubar for these menus
n = 0;
XtSetArg(args[n], XmNsubMenuId, pulldown1); n++;
menuButtons[0] = XtCreateManagedWidget("File",
xmCascadeButtonGadgetClass,
menubar, args, n);
n = 0;
XtSetArg(args[n], XmNsubMenuId, pulldown2); n++;
menuButtons[1] = XtCreateManagedWidget("Edit",
xmCascadeButtonGadgetClass,
menubar, args, n);
// manage the menu buttons
XtManageChildren(menuButtons, 2);
return menubar;
}
////////////////////////////////////////////////////////////////////////
//
// This creates the main window contents. In this case, we have a
// menubar at the top of the window, and a render area filling out
// the remainder. These widgets are layed out with a Motif form widget.
//
SoXtRenderArea *
buildMainWindow(Widget parent, SoNode *sceneGraph)
//
////////////////////////////////////////////////////////////////////////
{
Widget form;
Widget menubar;
SoXtRenderArea *renderArea;
Arg args[8];
int n;
// build the widgets
form = XtCreateWidget("form", xmFormWidgetClass, parent, NULL, 0);
menubar = buildPulldownMenu(form);
renderArea = new SoXtRenderArea(form);
renderArea->setSceneGraph(sceneGraph);
// layout
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_NONE); n++;
XtSetValues(menubar, args, n);
n = 0;
XtSetArg(args[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
XtSetArg(args[n], XmNtopWidget, menubar); n++;
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
XtSetValues(renderArea->getWidget(), args, n);
// manage the children
XtManageChild(menubar);
renderArea->show();
// manage the form widget
XtManageChild(form);
return renderArea;
}
////////////////////////////////////////////////////////////////////////
//
// main - init Inventor and Xt, set up a scene graph and the main window,
// display this window, and loop forever...
//
void
main(unsigned int /*argc*/, char *argv[])
//
////////////////////////////////////////////////////////////////////////
{
Widget mainWindow;
// Initialize Inventor and Xt.
mainWindow = SoXt::init(argv[0]);
if (mainWindow != NULL) {
// set up a scene graph to display
SoSeparator *root = new SoSeparator;
SoPerspectiveCamera *camera = new SoPerspectiveCamera;
SoDirectionalLight *light = new SoDirectionalLight;
root->ref();
root->addChild(camera);
root->addChild(light);
root->addChild(new SoCone);
// set up the pulldown menu with a render area
SoXtRenderArea *ra = buildMainWindow(mainWindow, root);
camera->viewAll(root, ra->getViewportRegion());
SoXt::show(mainWindow);
SoXt::mainLoop();
}
}