+/* $Header$ */
+
#include <stdio.h>
+#include <string.h>
#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>
#include <X11/Shell.h>
#include <X11/Core.h>
#include <X11/CoreP.h>
+#include <X11/CompositeP.h>
#include <Xm/Xm.h>
#include <Xm/BulletinB.h>
#include <Xm/Label.h>
#include <Xm/Text.h>
+#include <Xm/TextP.h>
#include <Xm/PushB.h>
#include <Xm/PushBG.h>
#include <Xm/CascadeB.h>
#include <Xm/ToggleBG.h>
#include <Xm/RowColumn.h>
#include <Xm/Separator.h>
+#include <Xm/Traversal.h>
#include "mmoira.h"
static char rcsid[] = "$Header$";
-#define PADDING 10
+#ifndef MAX
#define MAX(a,b) ((a > b) ? a : b)
+#endif
+#ifndef MIN
#define MIN(a,b) ((a < b) ? a : b)
+#endif
-Widget entryformwidget;
+int hpad = 10;
+int vpad = 5;
void manage_widget();
Widget CreateForm();
void string_callback();
void boolean_callback();
void menu_callback();
+void newvalue();
+void MoiraFocusOut();
+EntryForm *WidgetToForm();
+extern void UpdateForm();
extern int PopupErrorMessage();
extern void PopupHelpWindow();
extern int AppendToLog();
-extern void UpdateForm();
extern void MakeWatchCursor();
extern void MakeNormalCursor();
extern Widget SetupLogWidget();
+static XtActionsRec myactions[] = {
+ { "MoiraFocusOut", MoiraFocusOut },
+};
+
void
manage_widget(w, widget, call_data)
}
int
-button_callback(w, form, call_data)
-Widget w;
-EntryForm *form;
+button_callback(w, client_data, call_data)
+Widget w;
+EntryForm *client_data;
XmAnyCallbackStruct *call_data;
{
- char output[100];
- MakeWatchCursor();
-/* sprintf (output, "Button %x was hit...\n", w);
- AppendToLog(output);
- PopupErrorMessage("Sorry, no functionality here!\n"); */
- XtUnmanageChild(form->formpointer);
- MakeNormalCursor();
+ XtUnmanageChild(client_data->formpointer);
}
XmSTRING_DEFAULT_CHARSET);
n = 0;
XtSetArg(wargs[n], XmNlabelString, label); n++;
+ if (curmenuitem->accel) {
+ XtSetArg(wargs[n], XmNmnemonic, *(curmenuitem->accel)); n++;
+ }
if (curmenuitem->submenu) {
#ifdef DEBUG
Widget shellparent;
if (spec->formpointer) {
- printf ("Form %s already exists\n", spec->formname);
+ UpdateForm(spec);
return(spec->formpointer);
}
+ height_so_far = vpad;
+
#define GETSIZE(foo) n = 0; \
XtSetArg(wargs[n], XtNwidth, &width); n++; \
XtSetArg(wargs[n], XtNheight, &height); n++; \
XtGetValues (foo, wargs, n); \
#define STORESIZE if (width > width_so_far) width_so_far = width;\
- height_so_far += height + PADDING;
+ height_so_far += height + vpad;
n = 0;
- XtSetArg(wargs[n], XmNautoUnmanage, FALSE); n++;
- bb = XmCreateBulletinBoardDialog(parent, "board", wargs, n);
+ XtSetArg(wargs[n], XmNautoUnmanage, False); n++;
+ bb = XmCreateBulletinBoardDialog(parent, spec->formname, wargs, n);
+ MapWidgetToForm(bb, spec);
spec->formpointer = bb;
+#ifdef FORMTITLES
label = XmStringCreate(spec->formname, XmSTRING_DEFAULT_CHARSET);
n = 0;
XtSetArg(wargs[n], XmNlabelString, label); n++;
bb, wargs, n);
GETSIZE(titleW);
STORESIZE;
+#endif
label = XmStringCreate(spec->instructions, XmSTRING_DEFAULT_CHARSET);
n = 0;
XtSetArg(wargs[n], XmNlabelString, label); n++;
XtSetArg(wargs[n], XtNx, 0); n++;
XtSetArg(wargs[n], XtNy, height_so_far); n++;
- instructionW = XtCreateManagedWidget( "title",
+ instructionW = XtCreateManagedWidget( "instructions",
xmLabelWidgetClass,
bb, wargs, n);
GETSIZE(instructionW);
/*
** Center the title of the form
*/
+#ifdef FORMTITLES
n = 0;
XtSetArg(wargs[n], XtNwidth, &width); n++;
XtGetValues (titleW, wargs, n);
n = 0;
XtSetArg(wargs[n], XtNx, x); n++;
XtSetValues (titleW, wargs, n);
+#endif
+ n = 0;
+ XtSetArg(wargs[n], XtNwidth, &width); n++;
+ XtGetValues (instructionW, wargs, n);
+
+ x = (width_so_far - width) / 2;
+
+ n = 0;
+ XtSetArg(wargs[n], XtNx, x); n++;
+ XtSetValues (instructionW, wargs, n);
return((Widget) bb);
}
UserPrompt **myinputlines = spec->inputlines;
int foo = 30;
Widget children[20];
+ static XtTranslations trans = NULL;
for ( current = (*myinputlines), localy = 0, i = 0;
current;
/*
** First, make the prompt
*/
+ if (current->type == FT_KEYWORD) {
+ char *p;
+
+ p = strchr(current->prompt, '|');
+ if (p) {
+ *p++ = 0;
+ current->keyword_name = p;
+ }
+ }
+
label = XmStringCreate( current->prompt,
XmSTRING_DEFAULT_CHARSET);
n = 0;
if (width > maxleftwidth)
maxleftwidth = width;
+ if (current->type == FT_KEYWORD && current->keyword_name) {
+ label = XmStringCreate("add new value",
+ XmSTRING_DEFAULT_CHARSET);
+ n = 0;
+ XtSetArg(wargs[n], XmNlabelString, label); n++;
+ XtSetArg(wargs[n], XtNy, localy + *pheight + height); n++;
+ XtSetArg(wargs[n], XtNx, height); n++;
+ child = XtCreateManagedWidget("newvalue",
+ xmPushButtonWidgetClass,
+ parent, wargs, n);
+ XtAddCallback(child, XmNactivateCallback,
+ newvalue, current);
+
+ GETSIZE(child);
+ leftheight += height;
+ if (width + height > maxleftwidth)
+ maxleftwidth = width + height;
+ }
/*
** Second, make the input widget
*/
!(current->insensitive)); n++;
switch (current->type) {
case FT_STRING:
- children[i] = XtCreateManagedWidget( "child",
+ children[i] = XtCreateManagedWidget( "textwidget",
xmTextWidgetClass,
parent, wargs, n);
- XtAddCallback( children[i], XmNlosingFocusCallback,
+ XtAddCallback( children[i], XmNvalueChangedCallback,
string_callback, current);
+ if (trans == NULL) {
+ XtAppAddActions(XtWidgetToApplicationContext(children[i]),
+ myactions, XtNumber(myactions));
+
+ trans = XtParseTranslationTable(resources.text_trans);
+ }
+ XtOverrideTranslations(children[i], trans);
if (current->returnvalue.stringvalue) {
XmTextSetString (children[i], current->returnvalue.stringvalue);
}
break;
case FT_BOOLEAN:
- XtSetArg(wargs[n], XmNset, current->returnvalue.booleanvalue); n++;
+ XtSetArg(wargs[n], XmNset,
+ current->returnvalue.booleanvalue ? True : False); n++;
if (current->returnvalue.booleanvalue)
label = XmStringCreate( "(True)", XmSTRING_DEFAULT_CHARSET);
case FT_KEYWORD:
children[i] =
- MakeRadioField(parent, current, &rightheight);
+ MakeRadioField(parent, current,
+ &rightheight, spec);
XtManageChild(children[i]);
XtSetValues(children[i], wargs, n);
GETSIZE (children[i]);
break;
}
XmAddTabGroup(children[i]);
+ MapWidgetToForm(children[i], spec);
+ current->parent = (caddr_t) spec;
+
+ current->mywidget = children[i];
- localy += MAX(rightheight, leftheight) + PADDING;
+ localy += MAX(rightheight, leftheight) + vpad;
}
/*
** Now slide the input widgets right as far as the widest prompt.
*/
n = 0;
- XtSetArg(wargs[n], XtNx, maxleftwidth + PADDING); n++;
+ XtSetArg(wargs[n], XtNx, maxleftwidth + hpad); n++;
for (; i; i--)
XtSetValues (children[i - 1], wargs, n);
- *pheight = localy - PADDING;
- *pwidth = maxleftwidth + maxrightwidth + PADDING;
+ *pheight = localy - vpad;
+ *pwidth = maxleftwidth + maxrightwidth + hpad;
}
/*
*/
Widget
-MakeRadioField(parent, prompt, pheight)
+MakeRadioField(parent, prompt, pheight, spec)
Widget parent;
UserPrompt *prompt;
Dimension *pheight;
+EntryForm *spec;
{
- Widget radioparent, child;
+ Widget radioparent, child = NULL;
char *current;
Arg wargs[10];
int count, n;
XmString label; /* accursed compound string required */
Dimension height, width;
- char **keywords;
+ char **keywords, *null[2];
-
- if (!keywords) {
+ if (!prompt->keywords) {
fprintf (stderr, "Warning: No list of keywords for widget\n");
- return;
+ prompt->keywords = null;
+ null[0] = NULL;
}
for ( count = 0, keywords = prompt->keywords;
*keywords;
XtSetArg(wargs[n], XmNspacing, 0); n++;
if (count > 5) {
- printf ("Special case: Asking for %d columns\n",1 + count/5);
- XtSetArg(wargs[n], XmNnumColumns, 1 + count / 5); n++;
+ XtSetArg(wargs[n], XmNnumColumns, 1 + (count-1) / 5); n++;
XtSetArg(wargs[n], XmNorientation, XmVERTICAL); n++;
XtSetArg(wargs[n], XmNpacking, XmPACK_COLUMN); n++;
}
-
radioparent = XmCreateRadioBox(parent, "radio", wargs, n);
keywords = prompt->keywords;
n = 0;
label = XmStringCreate(current, XmSTRING_DEFAULT_CHARSET);
XtSetArg(wargs[n], XmNlabelString, label); n++;
- if (!strcmp (current, prompt->returnvalue.stringvalue)) {
+ if ((prompt->returnvalue.stringvalue) &&
+ (!strcmp (current, prompt->returnvalue.stringvalue))) {
XtSetArg(wargs[n], XmNset, True); n++;
}
else {
child = XtCreateManagedWidget( current,
xmToggleButtonWidgetClass,
radioparent, wargs, n);
+ MapWidgetToForm(child, spec);
XtAddCallback( child, XmNvalueChangedCallback,
radio_callback, prompt);
** five times this, or the actual number of children, whichever is lesser.
*/
- GETSIZE (child);
- printf ("Reporting height of %d\n", (height * MAX(5, count)));
- *pheight = (height * MIN(5, count));
+ if (child) {
+ GETSIZE (child);
+ } else
+ height = 10;
+ *pheight = (height * MIN(5, count)) + vpad;
-/*
- n = 0;
- XtSetArg(wargs[n], XtNheight, height_so_far); n++;
- XtSetValues (radioparent, wargs, n);
- GETSIZE (radioparent);
- printf ("height of radio parent is now %d\n", height);
+ return(radioparent);
+}
- *pheight = height_so_far;
-*/
- return(radioparent);
+/* This is called when the list of keywords changes. The old radio box
+ * will be destroyed and a new one created.
+ */
+
+RemakeRadioField(form, field)
+EntryForm *form;
+int field;
+{
+ Dimension x, y, parent_y, oldheight, newheight;
+ Arg wargs[4];
+ Widget w;
+ static XtTranslations trans = NULL;
+ extern char form_override_table[];
+ int i;
+
+ XtSetArg(wargs[0], XtNx, &x);
+ XtSetArg(wargs[1], XtNy, &y);
+ XtSetArg(wargs[2], XtNheight, &oldheight);
+ XtGetValues(form->inputlines[field]->mywidget, wargs, 3);
+ XtUnmanageChild(form->inputlines[field]->mywidget);
+ form->inputlines[field]->mywidget = w =
+ MakeRadioField(form->formpointer, form->inputlines[field],
+ &newheight, form);
+ XtSetArg(wargs[0], XtNx, x);
+ XtSetArg(wargs[1], XtNy, y);
+ XtSetValues(w, wargs, 2);
+ MapWidgetToForm(w, form);
+ XmAddTabGroup(w);
+ if (newheight > oldheight) {
+ parent_y = y;
+ for (i = 0; i < NumChildren(form->formpointer); i++) {
+ XtSetArg(wargs[0], XtNy, &y);
+ XtGetValues(NthChild(form->formpointer, i), wargs, 1);
+ if (y > parent_y) {
+ y = (y + newheight) - oldheight;
+ XtSetArg(wargs[0], XtNy, y);
+ XtSetValues(NthChild(form->formpointer, i), wargs, 1);
+ }
+ }
+ }
+
+ if (trans == NULL)
+ trans = XtParseTranslationTable(resources.form_trans);
+ XtOverrideTranslations(w, trans);
+ for (i = 0; i < NumChildren(w); i++)
+ XtOverrideTranslations(NthChild(w, i), trans);
+
+ XtManageChild(w);
}
+
MakeButtons(parent, pheight, pwidth, spec)
Widget parent;
Dimension *pheight;
Widget newbutton;
BottomButton **buttons = spec->buttons;
+ *pheight += vpad;
+
n = 0;
XtSetArg(wargs[n], XtNy, *pheight); n++;
XtSetArg(wargs[n], XtNx, 0); n++;
XtCreateManagedWidget( "separator",
xmSeparatorWidgetClass,
parent, wargs, n);
- *pheight += PADDING;
+ *pheight += vpad;
for ( current=(*buttons);
current;
xmPushButtonWidgetClass,
parent, wargs, n);
- XtAddCallback( newbutton, XmNactivateCallback,
- current->returnfunction, spec);
+ XtAddCallback(newbutton, XmNactivateCallback,
+ (XtCallbackProc) current->returnfunction,
+ spec);
n = 0;
XtSetArg(wargs[n], XtNwidth, &newwidth); n++;
XtGetValues (newbutton, wargs, n);
- width += (newwidth + PADDING);
+ width += (newwidth + hpad);
}
(*pheight) += 100;
** Fortunately, I was smart enough to use the button label as the name
** of the widget, and I can extract it via XtName(). Thanks, Motif!
*/
- if (strcmp(prompt->returnvalue.stringvalue, XtName(w))) {
- printf ("Replacing old value of selection, '%s', with '%s'\n",
- prompt->returnvalue.stringvalue,
- XtName(w));
+ if (prompt->returnvalue.stringvalue &&
+ (strcmp(prompt->returnvalue.stringvalue, XtName(w)))) {
strcpy(prompt->returnvalue.stringvalue, XtName(w));
+ if (prompt->valuechanged)
+ (*prompt->valuechanged)(WidgetToForm(w), prompt);
}
}
XtSetArg(wargs[n], XmNlabelString, label); n++;
XtSetValues (w, wargs, n);
+ if (current->valuechanged)
+ (*current->valuechanged)(WidgetToForm(w), current);
+
#if DEBUG
printf ("boolean_callback: button %x is %s\n",
w, (is_set ? "True" : "False"));
itemhit->label,
itemhit->operation,
itemhit->form);
- XtManageChild(entryformwidget); */
+ XtManageChild(entryformwidget);
+*/
MoiraMenuRequest(itemhit);
}
newvalue = XmTextGetString(w);
if (strcmp(current->returnvalue.stringvalue, newvalue)) {
- printf ("Replacing old value of selection, '%s', with '%s'\n",
+/* printf ("Replacing old value of selection, '%s', with '%s'\n",
current->returnvalue.stringvalue,
newvalue);
strcpy(current->returnvalue.stringvalue, newvalue);
- }
+ if (current->valuechanged)
+ (*current->valuechanged)(WidgetToForm(w), current);
+*/ }
XtFree(newvalue);
}
+
+
+void MoiraFocusOut(w, event, p, n)
+Widget w;
+XEvent *event;
+String *p;
+Cardinal *n;
+{
+ char *newvalue;
+ UserPrompt *current = NULL;
+ EntryForm *f;
+ XmTextRec *tr = (XmTextRec *)w;
+ int i;
+
+ if (!tr || tr->core.self != w || tr->core.widget_class != xmTextWidgetClass)
+ return;
+ newvalue = XmTextGetString(w);
+ f = WidgetToForm(w);
+ for (i = 0; f->inputlines[i]; i++)
+ if (f->inputlines[i]->mywidget == w)
+ current = f->inputlines[i];
+ if (current == NULL) {
+ fprintf(stderr, "Couldn't find prompt structure!\n");
+ return;
+ }
+
+ if (strcmp(current->returnvalue.stringvalue, newvalue)) {
+ strcpy(current->returnvalue.stringvalue, newvalue);
+ if (current->valuechanged)
+ (*current->valuechanged)(f, current);
+ }
+ XtFree(newvalue);
+}
+
+
+void
+newvalue(w, client_data, call_data)
+Widget w;
+XmAnyCallbackStruct *client_data;
+XmAnyCallbackStruct *call_data;
+{
+ UserPrompt *current = (UserPrompt *)client_data;
+ EntryForm *form, *f;
+ int i;
+ static MenuItem mi;
+
+ if (current->keyword_name == NULL) {
+ PopupErrorMessage("Sorry, that keyword cannot be changed.", NULL);
+ return;
+ }
+ form = (EntryForm *)current->parent;
+ for (i = 0; form->inputlines[i]; i++)
+ if (form->inputlines[i] == current)
+ break;
+ f = GetAndClearForm("add_new_value");
+ mi.operation = MM_NEW_VALUE;
+ mi.query = "add_alias";
+ mi.argc = 3;
+ mi.form = form->formname;
+ mi.accel = (char *) i;
+ f->menu = &mi;
+ f->extrastuff = current->keyword_name;
+ DisplayForm(f);
+}
+
+
+/* WARNING: This routine uses Motif internal undocumented routines.
+ * It was the only way to get carriage return to Do The Right Thing.
+ * If you are in a single-item tab group, this routine will call
+ * MoiraFormComplete() (same as pressing OK on the bottom of the form).
+ * otherwise, it advances the focus the same as pressing TAB.
+ */
+
+void EnterPressed(w, event, argv, count)
+Widget w;
+XEvent *event;
+char **argv;
+Cardinal *count;
+{
+ Widget next;
+ EntryForm *form;
+
+ next = _XmFindNextTabGroup(w);
+ if (next == w) {
+ MoiraFocusOut(w, event, argv, count);
+ form = WidgetToForm(w);
+ MoiraFormComplete(NULL, form);
+ } else {
+ _XmMgrTraversal(w, XmTRAVERSE_NEXT_TAB_GROUP);
+ }
+}
+
+
+void CancelForm(w, event, argv, count)
+Widget w;
+XEvent *event;
+char **argv;
+Cardinal *count;
+{
+ EntryForm *form;
+
+ form = WidgetToForm(w);
+ if (form)
+ XtUnmanageChild(form->formpointer);
+}
+
+
+void ExecuteForm(w, event, argv, count)
+Widget w;
+XEvent *event;
+char **argv;
+Cardinal *count;
+{
+ EntryForm *form;
+
+ form = WidgetToForm(w);
+ if (form) {
+ MoiraFocusOut(w, event, argv, count);
+ MoiraFormComplete(NULL, form);
+ }
+}
+
+
+void DoHelp(w, event, argv, count)
+Widget w;
+XEvent *event;
+char **argv;
+Cardinal *count;
+{
+ EntryForm *form;
+
+ form = WidgetToForm(w);
+ if (form)
+ help(form->formname);
+}
+
+
+extern struct hash *create_hash();
+static struct hash *WFmap = NULL;
+
+MapWidgetToForm(w, f)
+Widget *w;
+EntryForm *f;
+{
+ if (WFmap == NULL) {
+ WFmap = create_hash(101);
+ }
+ hash_store(WFmap, w, f);
+}
+
+EntryForm *WidgetToForm(w)
+Widget *w;
+{
+ return((EntryForm *) hash_lookup(WFmap, w));
+}
+
+
+/* Routines to deal with children of composite widgets */
+
+Widget NthChild(w, n)
+CompositeRec *w;
+int n;
+{
+ return(w->composite.children[n]);
+}
+
+int NumChildren(w)
+CompositeRec *w;
+{
+ return(w->composite.num_children);
+}