ncsa-mosaic/libXmx/Xmx2.c

500 lines
17 KiB
C

/****************************************************************************
* NCSA Mosaic for the X Window System *
* Software Development Group *
* National Center for Supercomputing Applications *
* University of Illinois at Urbana-Champaign *
* 605 E. Springfield, Champaign IL 61820 *
* mosaic@ncsa.uiuc.edu *
* *
* Copyright (C) 1993, Board of Trustees of the University of Illinois *
* *
* NCSA Mosaic software, both binary and source (hereafter, Software) is *
* copyrighted by The Board of Trustees of the University of Illinois *
* (UI), and ownership remains with the UI. *
* *
* The UI grants you (hereafter, Licensee) a license to use the Software *
* for academic, research and internal business purposes only, without a *
* fee. Licensee may distribute the binary and source code (if released) *
* to third parties provided that the copyright notice and this statement *
* appears on all copies and that no charge is associated with such *
* copies. *
* *
* Licensee may make derivative works. However, if Licensee distributes *
* any derivative work based on or derived from the Software, then *
* Licensee will (1) notify NCSA regarding its distribution of the *
* derivative work, and (2) clearly notify users that such derivative *
* work is a modified version and not the original NCSA Mosaic *
* distributed by the UI. *
* *
* Any Licensee wishing to make commercial use of the Software should *
* contact the UI, c/o NCSA, to negotiate an appropriate license for such *
* commercial use. Commercial use includes (1) integration of all or *
* part of the source code into a product for sale or license by or on *
* behalf of Licensee to third parties, or (2) distribution of the binary *
* code or source code to third parties that need it to utilize a *
* commercial product sold or licensed by or on behalf of Licensee. *
* *
* UI MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR *
* ANY PURPOSE. IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED *
* WARRANTY. THE UI SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY THE *
* USERS OF THIS SOFTWARE. *
* *
* By using or copying this Software, Licensee agrees to abide by the *
* copyright law and all other applicable laws of the U.S. including, but *
* not limited to, export control laws, and the terms of this license. *
* UI shall have the right to terminate this license immediately by *
* written notice upon Licensee's breach of, or non-compliance with, any *
* of its terms. Licensee may be held legally responsible for any *
* copyright infringement that is caused or encouraged by Licensee's *
* failure to abide by the terms of this license. *
* *
* Comments and questions are welcome and can be sent to *
* mosaic-x@ncsa.uiuc.edu. *
****************************************************************************/
#include <stdlib.h>
#include "../config.h"
#include "XmxP.h"
/* ------------------------------------------------------------------------ */
/* --------------------------- PRIVATE ROUTINES --------------------------- */
/* ------------------------------------------------------------------------ */
/* ----------------------- _XmxMenuAddEntryToRecord ----------------------- */
/* Create a new MenuEntry and add it to the head of a MenuRecord list. */
private void
_XmxMenuAddEntryToRecord (XmxMenuRecord *rec, Widget w, int token)
{
XmxMenuEntry *_ent;
/* Create new menu entry. */
_ent = (XmxMenuEntry *)malloc (sizeof (XmxMenuEntry));
_ent->w = w;
_ent->token = token;
/* Add rest of list to tail of this entry. */
_ent->next = rec->first_entry;
/* Make this entry head of list. */
rec->first_entry = _ent;
return;
}
/* ---------------------- _XmxMenuGetEntryFromRecord ---------------------- */
private XmxMenuEntry *
_XmxMenuGetEntryFromRecord (XmxMenuRecord *rec, int token)
{
/* Given token, fetch the corresponding entry. */
XmxMenuEntry *_ent = NULL;
int _done;
/* Search the linked list. */
_ent = rec->first_entry;
_done = 0;
while (_ent != NULL && !_done)
{
if (_ent->token == token)
_done = 1;
else
_ent = _ent->next;
}
/* Punish the application for asking for a nonexistent entry. */
/* assert (_done); */
return _ent;
}
/* ------------------------- _XmxMenuCreateRecord ------------------------- */
/* Create a new MenuRecord and clear out its list. */
private XmxMenuRecord *
_XmxMenuCreateRecord (Widget base)
{
XmxMenuRecord *_rec;
/* Create the new XmxMenuRecord. */
_rec = (XmxMenuRecord *)malloc (sizeof (XmxMenuRecord));
_rec->base = base;
_rec->first_entry = NULL;
return _rec;
}
/* ------------------------------------------------------------------------ */
/* --------------------------- PUBLIC ROUTINES ---------------------------- */
/* ------------------------------------------------------------------------ */
/* --------------------------- XmxRSetSensitive --------------------------- */
/* args NOT used on Widget */
public void
XmxRSetSensitive (XmxMenuRecord *rec, int token, int state)
{
XmxMenuEntry *_entry;
assert (state == XmxSensitive || state == XmxUnsensitive);
_entry = _XmxMenuGetEntryFromRecord (rec, XmxExtractToken (token));
/* XtSetSensitive propagates down Widget hierarchy. */
if (_entry)
XtSetSensitive (_entry->w, (state == XmxSensitive) ? True : False);
return;
}
/* -------------------------- XmxRSetToggleState -------------------------- */
/* args not used */
public void
XmxRSetToggleState (XmxMenuRecord *rec, int token, int state)
{
XmxMenuEntry *_entry;
assert (state == XmxSet || state == XmxUnset);
_entry = _XmxMenuGetEntryFromRecord (rec, XmxExtractToken (token));
if (_entry)
XmToggleButtonGadgetSetState
(_entry->w, (state == XmxSet) ? True : False, False);
return;
}
/* ------------------------- XmxRUnsetAllToggles -------------------------- */
/* args not used */
public void
XmxRUnsetAllToggles (XmxMenuRecord *rec)
{
XmxMenuEntry *_ent;
for (_ent = rec->first_entry; _ent != NULL; _ent = _ent->next)
XmToggleButtonGadgetSetState
(_ent->w, False, False);
return;
}
/* ----------------------- XmxRSetOptionMenuHistory ----------------------- */
/* args used on Widget */
public void
XmxRSetOptionMenuHistory (XmxMenuRecord *rec, int token)
{
XmxMenuEntry *_entry;
_entry = _XmxMenuGetEntryFromRecord (rec, XmxExtractToken (token));
if (_entry)
{
XmxSetArg (XmNmenuHistory, (XtArgVal)(_entry->w));
XtSetValues (rec->base, Xmx_wargs, Xmx_n);
}
Xmx_n = 0;
return;
}
/* ---------------------------- XmxRSetValues ----------------------------- */
/* args used on Widget */
public void
XmxRSetValues (XmxMenuRecord *rec, int token)
{
XmxMenuEntry *_entry;
/* Strip out uniqid, if present. */
_entry = _XmxMenuGetEntryFromRecord (rec, XmxExtractToken (token));
if (_entry)
XtSetValues (_entry->w, Xmx_wargs, Xmx_n);
Xmx_n = 0;
return;
}
/* ---------------------------- XmxRGetWidget ----------------------------- */
/* args irrelevant */
public Widget
XmxRGetWidget (XmxMenuRecord *rec, int token)
{
XmxMenuEntry *_entry;
/* Strip out uniqid, if present. */
_entry = _XmxMenuGetEntryFromRecord (rec, XmxExtractToken (token));
if (_entry)
return _entry->w;
else
return NULL;
}
/* -------------------------- XmxRMakeOptionMenu -------------------------- */
/* args apply to pulldown menu */
public XmxMenuRecord *
XmxRMakeOptionMenu (Widget parent, String name, XtCallbackProc cb,
XmxOptionMenuStruct *opts)
{
XmxMenuRecord *_rec;
Widget _pulldown, _button, _menuhist = (Widget)NULL;
int _i;
/* Create a pulldown menupane to attach to the option menu;
preloaded wargs affect this. */
_pulldown = XmCreatePulldownMenu (parent, "pulldownmenu", Xmx_wargs, Xmx_n);
/* menuHistory will not be applied to _pulldown, so we'll modify
_rec directly after creating the option menu. */
_rec = _XmxMenuCreateRecord (_pulldown);
/* Create pushbutton gadgets as childen of the pulldown menu. */
_i = 0;
while (opts[_i].namestr)
{
Xmx_n = 0;
XmxSetArg (XmNlabelString,
(XtArgVal)XmStringCreateLtoR (opts[_i].namestr,
XmSTRING_DEFAULT_CHARSET));
_button = XmCreatePushButtonGadget (_pulldown, "pushbutton",
Xmx_wargs, Xmx_n);
XtManageChild (_button);
XtAddCallback (_button, XmNactivateCallback, cb,
(XtPointer)_XmxMakeClientData (opts[_i].data));
if (opts[_i].set_state == XmxSet)
_menuhist = _button;
_XmxMenuAddEntryToRecord (_rec, _button, opts[_i].data);
_i++;
}
/* Create the option menu itself; tie in the pulldown menu. */
Xmx_n = 0;
XmxSetArg (XmNsubMenuId, (XtArgVal)_pulldown);
if (_menuhist != (Widget)NULL)
XmxSetArg (XmNmenuHistory, (XtArgVal)_menuhist);
Xmx_w = XmCreateOptionMenu (parent, "optionmenu", Xmx_wargs, Xmx_n);
XtManageChild (Xmx_w);
XmxSetArg (XmNalignment, (XtArgVal)XmALIGNMENT_BEGINNING);
XmxSetValues (XmOptionButtonGadget (Xmx_w));
if (name)
{
XmxSetArg (XmNlabelString,
(XtArgVal)XmStringCreateLtoR (name, XmSTRING_DEFAULT_CHARSET));
XmxSetValues (XmOptionLabelGadget (Xmx_w));
}
else
{
XmxSetArg (XmNspacing, (XtArgVal)0);
XmxSetArg (XmNmarginWidth, (XtArgVal)0);
XmxSetValues (Xmx_w);
XmxSetArg (XmNlabelString, (XtArgVal)NULL);
XmxSetValues (XmOptionLabelGadget (Xmx_w));
}
/* Explicitly set base Widget of record. */
_rec->base = Xmx_w;
Xmx_n = 0;
return _rec;
}
/* -------------------------- XmxRMakeToggleMenu -------------------------- */
/* args apply to radiobox or optionbox */
public XmxMenuRecord *
XmxRMakeToggleMenu (Widget parent, int behavior, XtCallbackProc cb,
XmxToggleMenuStruct *opts)
{
XmxMenuRecord *_rec;
Widget _box;
int _i;
assert (behavior == XmxOneOfMany || behavior == XmxNOfMany);
switch (behavior)
{
case XmxOneOfMany:
_box = XmxMakeRadioBox (parent);
break;
case XmxNOfMany:
_box = XmxMakeOptionBox (parent);
break;
}
_rec = _XmxMenuCreateRecord (_box);
_i = 0;
while (opts[_i].namestr)
{
XmxMakeToggleButton (_box, opts[_i].namestr, cb, opts[_i].data);
XmxSetToggleButton (Xmx_w, opts[_i].set_state);
_XmxMenuAddEntryToRecord (_rec, Xmx_w, opts[_i].data);
_i++;
}
Xmx_w = _box;
Xmx_n = 0;
return _rec;
}
/* -------------------------- _XmxRCreateMenubar -------------------------- */
/* Possible deficiency: will not be able to grey out a submenu
(cascade button). */
private void
_XmxRCreateMenubar (Widget menu, XmxMenubarStruct *menulist,
XmxMenuRecord *rec)
{
int _i;
Widget *_buttons;
int _separators = 0, _nitems;
_nitems = 0;
while (menulist[_nitems].namestr)
_nitems++;
_buttons = (Widget *)XtMalloc (_nitems * sizeof (Widget));
for (_i = 0; _i < _nitems; _i++)
{
/* Name of "----" means make a separator. */
if (strcmp(menulist[_i].namestr, "----") == 0)
{
XtCreateManagedWidget ("separator", xmSeparatorGadgetClass,
menu, NULL, 0);
_separators++;
}
/* A function means it's an ordinary entry with callback. */
else if (menulist[_i].func)
{
Xmx_n = 0;
if (menulist[_i].mnemonic)
XmxSetArg (XmNmnemonic, (XtArgVal)(menulist[_i].mnemonic));
if (menulist[_i].namestr[0] == '#' ||
menulist[_i].namestr[0] == '<') /* option/toggle button */
{
XmString xmstr;
/* A toggle button is diamond-shaped. */
if (menulist[_i].namestr[0] == '<')
XmxSetArg (XmNindicatorType, (XtArgVal)XmONE_OF_MANY);
/* Make sure the button shows up even when toggled off. */
if (menulist[_i].namestr[0] == '#')
XmxSetArg (XmNvisibleWhenOff, (XtArgVal)True);
/* Ignore first character of label. */
xmstr = XmxMakeXmstrFromString (&(menulist[_i].namestr[1]));
XmxSetArg (XmNlabelString, (XtArgVal)xmstr);
_buttons[_i - _separators] = XtCreateManagedWidget
("togglebutton", xmToggleButtonGadgetClass,
menu, Xmx_wargs, Xmx_n);
XmStringFree (xmstr);
XtAddCallback
(_buttons[_i - _separators], XmNvalueChangedCallback,
menulist[_i].func,
(XtPointer)_XmxMakeClientData (menulist[_i].data));
/* Add thie button to the menu record. */
_XmxMenuAddEntryToRecord
(rec, _buttons[_i - _separators], menulist[_i].data);
}
else /* regular button */
{
XmString xmstr =
XmStringCreateLtoR
(menulist[_i].namestr, XmSTRING_DEFAULT_CHARSET);
XmxSetArg (XmNlabelString, (XtArgVal)xmstr);
_buttons[_i - _separators] = XtCreateManagedWidget
("pushbutton", xmPushButtonGadgetClass,
menu, Xmx_wargs, Xmx_n);
XmStringFree (xmstr);
XtAddCallback
(_buttons[_i - _separators], XmNactivateCallback,
menulist[_i].func,
(XtPointer)_XmxMakeClientData (menulist[_i].data));
/* Add thie button to the menu record. */
_XmxMenuAddEntryToRecord
(rec, _buttons[_i - _separators], menulist[_i].data);
}
}
/* No function and no submenu entry means it's just a label. */
else if (menulist[_i].sub_menu == (XmxMenubarStruct *)NULL)
{
Xmx_n = 0;
XmxSetArg (XmNlabelString, (XtArgVal)XmStringCreateLtoR
(menulist[_i].namestr, XmSTRING_DEFAULT_CHARSET));
_buttons[_i - _separators] = XtCreateManagedWidget
("label", xmLabelGadgetClass, menu, Xmx_wargs, Xmx_n);
}
/* If all else fails, it's a submenu. */
else
{
XmString xmstr;
Widget _sub_menu;
_sub_menu = XmCreatePulldownMenu (menu, "pulldownmenu", NULL, 0);
Xmx_n = 0;
XmxSetArg (XmNsubMenuId, (XtArgVal)_sub_menu);
if (menulist[_i].mnemonic)
XmxSetArg (XmNmnemonic, (XtArgVal)(menulist[_i].mnemonic));
xmstr = XmStringCreateLtoR
(menulist[_i].namestr, XmSTRING_DEFAULT_CHARSET);
XmxSetArg (XmNlabelString, (XtArgVal)xmstr);
_buttons[_i - _separators] = XtCreateWidget
("cascadebutton", xmCascadeButtonGadgetClass,
menu, Xmx_wargs, Xmx_n);
XmStringFree (xmstr);
/* If name is "Help", put on far right. */
if (strcmp (menulist[_i].namestr, "Help") == 0)
{
Xmx_n = 0;
XmxSetArg (XmNmenuHelpWidget, (XtArgVal)_buttons[_i - _separators]);
XtSetValues (menu, Xmx_wargs, Xmx_n);
}
/* Recursively create new submenu. */
_XmxRCreateMenubar (_sub_menu, menulist[_i].sub_menu, rec);
}
}
XtManageChildren (_buttons, _nitems - _separators);
XtFree ((char *)_buttons);
return;
}
/* --------------------------- XmxRMakeMenubar ---------------------------- */
/* args apply to menubar */
public XmxMenuRecord *
XmxRMakeMenubar (Widget parent, XmxMenubarStruct *mainmenu)
{
Widget _menubar;
XmxMenuRecord *_rec;
/* Preset resources applied to main menubar only. */
_menubar = XmCreateMenuBar (parent, "menubar", Xmx_wargs, Xmx_n);
XtManageChild (_menubar);
/* Create the new XmxMenuRecord. */
_rec = _XmxMenuCreateRecord (_menubar);
Xmx_n = 0;
_XmxRCreateMenubar (_menubar, mainmenu, _rec);
Xmx_n = 0;
Xmx_w = _menubar;
return _rec;
}