]> andersk Git - moira.git/blobdiff - clients/mmoira/formup.c
Used /bin/sh format instead of /bin/csh format, by accident.
[moira.git] / clients / mmoira / formup.c
index 1c169a8cff2cbb627ace0b417ef4d45b7ef39183..cabf9265b5d9f34e8e1ac9a1d7cdf7f2ca0e6204 100644 (file)
@@ -1,13 +1,18 @@
+/* $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();
@@ -35,15 +45,22 @@ void        radio_callback();
 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)
@@ -54,18 +71,12 @@ XmAnyCallbackStruct *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);
 }
 
 
@@ -120,6 +131,9 @@ int         orientation;
                                        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
@@ -170,25 +184,29 @@ EntryForm *spec;
        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++;
@@ -199,13 +217,14 @@ EntryForm *spec;
                                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);
@@ -224,6 +243,7 @@ EntryForm   *spec;
 /*
 ** Center the title of the form
 */
+#ifdef FORMTITLES
        n = 0;
        XtSetArg(wargs[n], XtNwidth, &width);                   n++;
        XtGetValues (titleW, wargs, n);
@@ -233,6 +253,16 @@ EntryForm  *spec;
        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);
 }
@@ -263,6 +293,7 @@ EntryForm   *spec;
        UserPrompt      **myinputlines = spec->inputlines;
        int             foo = 30;
        Widget          children[20];
+       static XtTranslations trans = NULL;
 
        for (   current = (*myinputlines), localy = 0,  i = 0;
                current; 
@@ -276,6 +307,16 @@ EntryForm  *spec;
 /*
 ** 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;
@@ -290,6 +331,24 @@ EntryForm  *spec;
                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
 */
@@ -300,11 +359,18 @@ EntryForm *spec;
                        !(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);
                        }
@@ -315,7 +381,8 @@ EntryForm   *spec;
                        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);
@@ -338,7 +405,8 @@ EntryForm   *spec;
 
                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]);
@@ -351,20 +419,24 @@ EntryForm *spec;
                        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;
 }
 
 /*
@@ -374,23 +446,24 @@ EntryForm *spec;
 */
 
 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; 
@@ -408,12 +481,10 @@ Dimension *pheight;
        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;
@@ -421,7 +492,8 @@ Dimension   *pheight;
                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 {
@@ -430,6 +502,7 @@ Dimension   *pheight;
                child = XtCreateManagedWidget(  current,
                                                xmToggleButtonWidgetClass,
                                                radioparent, wargs, n);
+               MapWidgetToForm(child, spec);
 
                XtAddCallback(  child, XmNvalueChangedCallback,
                                radio_callback, prompt);
@@ -440,23 +513,67 @@ Dimension *pheight;
 ** 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;
@@ -471,6 +588,8 @@ EntryForm   *spec;
        Widget          newbutton;
        BottomButton    **buttons = spec->buttons;
 
+       *pheight += vpad;
+
        n = 0;
        XtSetArg(wargs[n], XtNy, *pheight);                     n++;
        XtSetArg(wargs[n], XtNx, 0);                            n++;
@@ -478,7 +597,7 @@ EntryForm   *spec;
        XtCreateManagedWidget(  "separator",
                                xmSeparatorWidgetClass,
                                parent, wargs, n);
-       *pheight += PADDING;
+       *pheight += vpad;
 
        for (   current=(*buttons); 
                current; 
@@ -498,13 +617,14 @@ EntryForm *spec;
                                                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;
@@ -538,11 +658,11 @@ XmAnyCallbackStruct       *call_data;
 ** 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);
        }
 
 }
@@ -573,6 +693,9 @@ XmAnyCallbackStruct *call_data;
        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"));
@@ -591,7 +714,8 @@ XmAnyCallbackStruct *call_data;
                        itemhit->label, 
                        itemhit->operation, 
                        itemhit->form);
-       XtManageChild(entryformwidget);  */
+       XtManageChild(entryformwidget); 
+*/
        MoiraMenuRequest(itemhit);
 }
 
@@ -608,10 +732,183 @@ XmAnyCallbackStruct      *call_data;
        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);
+}
This page took 0.059714 seconds and 4 git commands to generate.