home *** CD-ROM | disk | FTP | other *** search
/ vsiftp.vmssoftware.com / VSIPUBLIC@vsiftp.vmssoftware.com.tar / FREEWARE / FREEWARE40.ZIP / xpaint-247 / help.c < prev    next >
C/C++ Source or Header  |  1997-01-03  |  16KB  |  616 lines

  1. /* +-------------------------------------------------------------------+ */
  2. /* | Copyright 1993, David Koblas (koblas@netcom.com)                  | */
  3. /* |                                                                   | */
  4. /* | Permission to use, copy, modify, and to distribute this software  | */
  5. /* | and its documentation for any purpose is hereby granted without   | */
  6. /* | fee, provided that the above copyright notice appear in all       | */
  7. /* | copies and that both that copyright notice and this permission    | */
  8. /* | notice appear in supporting documentation.  There is no           | */
  9. /* | representations about the suitability of this software for        | */
  10. /* | any purpose.  this software is provided "as is" without express   | */
  11. /* | or implied warranty.                                              | */
  12. /* |                                                                   | */
  13. /* +-------------------------------------------------------------------+ */
  14.  
  15. /* $Id: help.c,v 1.4 1996/04/19 07:59:10 torsten Exp $ */
  16.  
  17. #include <X11/Intrinsic.h>
  18. #include <X11/Shell.h>
  19. #ifndef VMS
  20. #include <X11/Xaw/Command.h>
  21. #include <X11/Xaw/Toggle.h>
  22. #include <X11/Xaw/Form.h>
  23. #include <X11/Xaw/Label.h>
  24. #include <X11/Xaw/List.h>
  25. #include <X11/Xaw/AsciiText.h>
  26. #include <X11/Xaw/Text.h>
  27. #include <X11/Xaw/Viewport.h>
  28. #include <X11/Xaw/Scrollbar.h>
  29. #else
  30. #include <X11Xaw/Command.h>
  31. #include <X11Xaw/Toggle.h>
  32. #include <X11Xaw/Form.h>
  33. #include <X11Xaw/Label.h>
  34. #include <X11Xaw/List.h>
  35. #include <X11Xaw/AsciiText.h>
  36. #include <X11Xaw/Text.h>
  37. #include <X11Xaw/Viewport.h>
  38. #include <X11Xaw/Scrollbar.h>
  39. #endif
  40. #include <X11/StringDefs.h>
  41. #include <stdio.h>
  42. #include <ctype.h>
  43.  
  44. #include "Paint.h"
  45. #include "misc.h"
  46. #include "protocol.h"
  47.  
  48. #define TAB_DISTANCE    4
  49.  
  50. static String helpText[] =
  51. {
  52. #ifndef VMS
  53. #include "Help.txt.h"
  54. #else
  55. #include "Help_txt.h"
  56. #endif
  57. };
  58.  
  59. typedef struct HelpInfo_s {
  60.     char *name, *topic;
  61.     int index;
  62.     int start, stop;
  63.     struct HelpInfo_s *next;
  64. } HelpInfo;
  65.  
  66. typedef struct {
  67.     Widget shell;
  68.     int curTopic;
  69.     Widget topicList, topicPort;
  70.     Widget textText, textTitle;
  71.     Widget nextButton, prevButton;
  72.     Widget scrollbar;
  73.     int ninfo;
  74.     String *topics;
  75.     HelpInfo *info;
  76. } LocalInfo;
  77.  
  78. static Widget toplevel;
  79.  
  80. /*
  81. **  Build hierarchical help information structures.
  82.  */
  83.  
  84. /*
  85.  * If the string 'pat' matches the beginning of 'line', skip
  86.  * any following spaces and return the following word.
  87.  */
  88. char *
  89. matchGet(char *line, char *pat)
  90. {
  91.     static char buf[256];
  92.     int len = strlen(pat);
  93.     char *sp, *ep;
  94.  
  95.     if (strncmp(line, pat, len) != 0)
  96.     return NULL;
  97.  
  98.     for (sp = line + len; isspace(*sp); sp++);
  99.     for (ep = sp; isalnum(*ep); ep++);
  100.     strncpy(buf, sp, ep - sp);
  101.     buf[ep - sp] = '\0';
  102.  
  103.     return buf;
  104. }
  105.  
  106. static HelpInfo *
  107. buildInfo(int *count)
  108. {
  109.     Boolean nc, flg;
  110.     int depth = 0, stop = -1;
  111.     int i, j;
  112.     char parts[10][20];
  113.     HelpInfo *head = NULL, **nxt = &head, *cur = NULL;
  114.     char *cp, *tp = NULL;
  115.     int idx = 0;
  116.  
  117.     if (count != NULL)
  118.     *count = 0;
  119.  
  120.     for (i = 0; i < XtNumber(helpText); i++) {
  121.     flg = nc = False;
  122.     if ((cp = matchGet(helpText[i], "#BEGIN")) != NULL) {
  123.         int argc;
  124.         char *argv[128];
  125.         char buf[256];
  126.  
  127.         nc = True;
  128.         strcpy(buf, helpText[i]);    /* Need R&W buffer */
  129.         StrToArgv(buf, &argc, argv);
  130.         strcpy(parts[depth], argv[1]);
  131.         tp = (argc > 2) ? argv[2] : argv[1];
  132.     } else if ((cp = matchGet(helpText[i], "#PUSH")) != NULL) {
  133.         depth++;
  134.         flg = True;
  135.     } else if ((cp = matchGet(helpText[i], "#POP")) != NULL) {
  136.         if (depth > 0)
  137.         depth--;
  138.         flg = True;
  139.     } else if ((cp = matchGet(helpText[i], "#NL")) != NULL) {
  140.         stop = i;
  141.     } else {
  142.         stop = i;
  143.     }
  144.  
  145.     if (nc) {        /* saw #BEGIN */
  146.         int len;
  147.  
  148.         if (cur != NULL) {
  149.         cur->stop = stop + 1;
  150.         *nxt = cur;
  151.         nxt = &cur->next;
  152.         }
  153.         cur = XtNew(HelpInfo);
  154.         cur->index = idx++;
  155.         cur->start = i + 1;
  156.         cur->next = NULL;
  157.  
  158.         if (count != NULL)
  159.         (*count)++;
  160.  
  161.         len = 0;
  162.         for (j = 0; j <= depth; j++)
  163.         len += strlen(parts[j]) + 1;
  164.         cur->name = (char *) XtMalloc(len + 1);
  165.         cur->name[0] = '\0';
  166.         for (j = 0; j <= depth; j++) {
  167.         strcat(cur->name, parts[j]);
  168.         strcat(cur->name, ".");
  169.         }
  170.         cur->name[strlen(cur->name) - 1] = '\0';
  171.         cur->topic = (char *) XtMalloc(strlen(tp) + 7 + 2 * depth);
  172.         for (j = 0; j < depth * 2; j++)
  173.         cur->topic[j] = ' ';
  174.         cur->topic[j] = '\0';
  175.         strcat(cur->topic, tp);
  176.         strcat(cur->topic, "  ");
  177.     } else if (flg) {
  178.         if (cur->start == i)
  179.         cur->start++;
  180.     }
  181.     }
  182.  
  183.     if (cur != NULL) {
  184.     cur->stop = i;
  185.     *nxt = cur;
  186.     nxt = &cur->next;
  187.     }
  188.     return head;
  189. }
  190.  
  191.  
  192. static void 
  193. doneCB(Widget w, XtPointer lArg, XtPointer junk)
  194. {
  195.     LocalInfo *l = (LocalInfo *) lArg;
  196.  
  197.     XtPopdown(l->shell);
  198. }
  199.  
  200. static char *
  201. buildText(HelpInfo * cur)
  202. {
  203.     int i, len;
  204.     char *txt;
  205.     char *tp, *cp;
  206.  
  207.     len = 0;
  208.     for (i = cur->start; i < cur->stop; i++)
  209.     len += strlen(helpText[i]) + 2;
  210.  
  211.     tp = txt = (char *) XtCalloc(len + 8, sizeof(char));
  212.     for (i = cur->start; i < cur->stop; i++) {
  213.     /*
  214.     **  Line of all whitespace is a paragraph break.
  215.      */
  216.     for (cp = helpText[i]; *cp != '\0'; cp++)
  217.         if (!isspace(*cp))
  218.         break;
  219.     if (*cp == '\0') {
  220.         *tp++ = '\n';
  221.         *tp++ = '\n';
  222.         continue;
  223.     }
  224.     if (strncmp(helpText[i], "#NL", 3) == 0) {
  225.         *tp++ = '\n';
  226.         continue;
  227.     }
  228.     for (cp = helpText[i]; *cp != '\0'; *tp++ = *cp++);
  229.     *tp++ = ' ';
  230.     }
  231.     *tp++ = '\n';
  232.     *tp = '\0';
  233.  
  234.     return txt;
  235. }
  236.  
  237. static void 
  238. display(LocalInfo * l, HelpInfo * cur)
  239. {
  240.     char *txt;
  241.     float self, top, shown;
  242.  
  243.     if (cur == NULL)
  244.     cur = l->info;
  245.  
  246.     l->curTopic = cur->index;
  247.  
  248.     txt = buildText(cur);
  249.  
  250.     XtVaSetValues(l->textText, XtNstring, txt, NULL);
  251.     XtVaSetValues(l->textTitle, XtNlabel, cur->topic, NULL);
  252.  
  253.     XtFree((XtPointer) txt);
  254.  
  255.     XtVaSetValues(l->nextButton, XtNsensitive, (cur->next != NULL), NULL);
  256.     XtVaSetValues(l->prevButton, XtNsensitive, (cur->index != 0), NULL);
  257.  
  258.     XtCallActionProc(l->textText, "beginning-of-file", NULL, NULL, 0);
  259.  
  260.     /*
  261.     **  Now position the scrollbar to be visible
  262.      */
  263.  
  264.     XtVaGetValues(l->scrollbar, XtNtopOfThumb, &top,
  265.           XtNshown, &shown,
  266.           NULL);
  267.     self = (float) cur->index / (float) l->ninfo;
  268.     if (self < top || self > top + shown) {
  269.     top = self - shown / 2.0;
  270.     if (top < 0.0)
  271.         top = 0.0;
  272.     if (top + shown > 1.0)
  273.         top = 1.0 - shown;
  274.  
  275.     /*
  276.     **  Scrollbar doesn't notify on a SetThumb()
  277.     **    So we must do it
  278.      */
  279.     XawScrollbarSetThumb(l->scrollbar, top, -1.0);
  280.     XtCallCallbacks(l->scrollbar, XtNjumpProc, (XtPointer) & top);
  281.     }
  282. }
  283.  
  284. static void 
  285. topicCB(Widget w, LocalInfo * l, XawListReturnStruct * list)
  286. {
  287.     HelpInfo *cur = l->info;
  288.     int i;
  289.  
  290.     for (i = 0; i < list->list_index; i++)
  291.     cur = cur->next;
  292.  
  293.     display(l, cur);
  294. }
  295. static void 
  296. downCB(Widget w, LocalInfo * l, XtPointer junk)
  297. {
  298.     XtCallActionProc(l->textText, "next-page", NULL, NULL, 0);
  299. }
  300. static void 
  301. upCB(Widget w, LocalInfo * l, XtPointer junk)
  302. {
  303.     XtCallActionProc(l->textText, "previous-page", NULL, NULL, 0);
  304. }
  305. static void 
  306. prevCB(Widget w, LocalInfo * l, XtPointer junk)
  307. {
  308.     XawListReturnStruct lrs;
  309.  
  310.     if (l->curTopic == 0)
  311.     return;
  312.  
  313.     lrs.list_index = l->curTopic - 1;
  314.     XawListHighlight(l->topicList, lrs.list_index);
  315.     topicCB(w, l, &lrs);
  316. }
  317. static void 
  318. nextCB(Widget w, LocalInfo * l, XtPointer junk)
  319. {
  320.     XawListReturnStruct lrs;
  321.  
  322.     if (l->curTopic == l->ninfo - 1)
  323.     return;
  324.  
  325.     lrs.list_index = l->curTopic + 1;
  326.     XawListHighlight(l->topicList, lrs.list_index);
  327.     topicCB(w, l, &lrs);
  328. }
  329.  
  330. static LocalInfo *
  331. buildPopup(LocalInfo * l, Widget parent)
  332. {
  333.     Widget shell, form;
  334.     Widget title;
  335.     Widget topicList, topicPort;
  336.     Widget textTitle, textList;
  337.     Widget done, prev, next;
  338.     Widget pgDown, pgUp;
  339.  
  340.     if (l == NULL) {
  341.     HelpInfo *cur;
  342.     int i;
  343.  
  344.     l = XtNew(LocalInfo);
  345.     l->info = buildInfo(&l->ninfo);
  346.  
  347.     l->topics = (String *) XtCalloc(l->ninfo + 1, sizeof(String));
  348.     for (i = 0, cur = l->info; cur != NULL; cur = cur->next, i++)
  349.         l->topics[i] = cur->topic;
  350.     l->topics[i] = NULL;
  351.     l->shell = None;
  352.     }
  353.     if (l->shell != None)
  354.     return l;
  355.  
  356.     shell = XtVaCreatePopupShell("helpDialog",
  357.                   topLevelShellWidgetClass, GetShell(parent),
  358.                  NULL);
  359.  
  360.     form = XtVaCreateManagedWidget("form",
  361.                    formWidgetClass, shell,
  362.                    XtNborderWidth, 0,
  363.                    NULL);
  364.  
  365.     title = XtVaCreateManagedWidget("title",
  366.                     labelWidgetClass, form,
  367.                     XtNborderWidth, 0,
  368.                     XtNtop, XtChainTop,
  369.                     XtNbottom, XtChainTop,
  370.                     XtNleft, XtChainLeft,
  371.                     XtNright, XtChainLeft,
  372.                     NULL);
  373.  
  374.     /*
  375.     **
  376.      */
  377.     topicPort = XtVaCreateManagedWidget("topicPort",
  378.                     viewportWidgetClass, form,
  379.                     XtNtop, XtChainTop,
  380.                     XtNbottom, XtChainBottom,
  381.                     XtNleft, XtChainLeft,
  382.                     XtNright, XtChainLeft,
  383.                     XtNfromVert, title,
  384.                     XtNallowVert, True,
  385.                     XtNforceBars, True,
  386.                     NULL);
  387.     topicList = XtVaCreateManagedWidget("topic",
  388.                     listWidgetClass, topicPort,
  389.                     XtNverticalList, True,
  390.                     XtNforceColumns, True,
  391.                     XtNdefaultColumns, 1,
  392.                     NULL);
  393.  
  394.     /*
  395.     **
  396.      */
  397.     textTitle = XtVaCreateManagedWidget("textTitle",
  398.                     labelWidgetClass, form,
  399.                     XtNborderWidth, 0,
  400.                     XtNfromHoriz, topicPort,
  401.                     XtNfromVert, title,
  402.                     XtNleft, XtChainLeft,
  403.                     XtNright, XtChainRight,
  404.                     XtNtop, XtChainTop,
  405.                     XtNbottom, XtChainTop,
  406.                     XtNresize, False,
  407.                     NULL);
  408.  
  409.     textList = XtVaCreateManagedWidget("textText",
  410.                        asciiTextWidgetClass, form,
  411.                        XtNwrap, XawtextWrapWord,
  412.                        XtNtop, XtChainTop,
  413.                        XtNbottom, XtChainBottom,
  414.                        XtNleft, XtChainLeft,
  415.                        XtNright, XtChainRight,
  416.                        XtNfromVert, textTitle,
  417.                        XtNfromHoriz, topicPort,
  418.                   XtNscrollVertical, XawtextScrollAlways,
  419.                        XtNdisplayCaret, False,
  420.                        NULL);
  421.     {
  422.     Widget sink;
  423.     int tabs[10];
  424.     int i;
  425.  
  426.     for (i = 0; i < XtNumber(tabs); i++)
  427.         tabs[i] = i * TAB_DISTANCE;
  428.  
  429.     XtVaGetValues(textList, XtNtextSink, &sink, NULL);
  430.  
  431.     XawTextSinkSetTabs(sink, XtNumber(tabs), tabs);
  432.     }
  433.  
  434.     /*
  435.     **
  436.      */
  437.     done = XtVaCreateManagedWidget("done",
  438.                    commandWidgetClass, form,
  439.                    XtNfromVert, textList,
  440.                    XtNtop, XtChainBottom,
  441.                    XtNbottom, XtChainBottom,
  442.                    XtNleft, XtChainLeft,
  443.                    XtNright, XtChainLeft,
  444.                    NULL);
  445.     next = XtVaCreateManagedWidget("next",
  446.                    commandWidgetClass, form,
  447.                    XtNfromVert, textList,
  448.                    XtNfromHoriz, done,
  449.                    XtNtop, XtChainBottom,
  450.                    XtNbottom, XtChainBottom,
  451.                    XtNleft, XtChainLeft,
  452.                    XtNright, XtChainLeft,
  453.                    NULL);
  454.     prev = XtVaCreateManagedWidget("prev",
  455.                    commandWidgetClass, form,
  456.                    XtNfromVert, textList,
  457.                    XtNfromHoriz, next,
  458.                    XtNtop, XtChainBottom,
  459.                    XtNbottom, XtChainBottom,
  460.                    XtNleft, XtChainLeft,
  461.                    XtNright, XtChainLeft,
  462.                    NULL);
  463.     pgDown = XtVaCreateManagedWidget("down",
  464.                      commandWidgetClass, form,
  465.                      XtNfromVert, textList,
  466.                      XtNfromHoriz, topicPort,
  467.                      XtNtop, XtChainBottom,
  468.                      XtNbottom, XtChainBottom,
  469.                      XtNleft, XtChainLeft,
  470.                      XtNright, XtChainLeft,
  471.                      NULL);
  472.     pgUp = XtVaCreateManagedWidget("up",
  473.                    commandWidgetClass, form,
  474.                    XtNfromVert, textList,
  475.                    XtNfromHoriz, pgDown,
  476.                    XtNtop, XtChainBottom,
  477.                    XtNbottom, XtChainBottom,
  478.                    XtNleft, XtChainLeft,
  479.                    XtNright, XtChainLeft,
  480.                    NULL);
  481.  
  482.     l->shell = shell;
  483.     l->textText = textList;
  484.     l->textTitle = textTitle;
  485.     l->topicPort = topicPort;
  486.     l->topicList = topicList;
  487.     l->nextButton = next;
  488.     l->prevButton = prev;
  489.     l->scrollbar = XtNameToWidget(topicPort, "vertical");
  490.  
  491.     XawListChange(topicList, l->topics, 0, 0, True);
  492.  
  493.     XtAddCallback(topicList, XtNcallback,
  494.           (XtCallbackProc) topicCB, (XtPointer) l);
  495.     XtAddCallback(pgDown, XtNcallback, (XtCallbackProc) downCB, (XtPointer) l);
  496.     XtAddCallback(pgUp, XtNcallback, (XtCallbackProc) upCB, (XtPointer) l);
  497.     XtAddCallback(next, XtNcallback, (XtCallbackProc) nextCB, (XtPointer) l);
  498.     XtAddCallback(prev, XtNcallback, (XtCallbackProc) prevCB, (XtPointer) l);
  499.  
  500.     XtAddCallback(done, XtNcallback, doneCB, (XtPointer) l);
  501.     AddDestroyCallback(shell, (DestroyCallbackFunc) doneCB, (XtPointer) l);
  502.  
  503.     return l;
  504. }
  505.  
  506. void 
  507. HelpDialog(Widget parent, String name)
  508. {
  509.     static LocalInfo *l = NULL;
  510.     int i;
  511.     HelpInfo *cur;
  512.  
  513.     l = buildPopup(l, toplevel);
  514.  
  515.     for (i = 0, cur = l->info; cur != NULL; cur = cur->next, i++)
  516.     if (strcmp(name, cur->name) == 0)
  517.         break;
  518.  
  519.     if (!XtIsRealized(l->shell))
  520.     display(l, cur);
  521.  
  522.     XawListHighlight(l->topicList, cur == NULL ? 0 : i);
  523.  
  524.     XtPopup(l->shell, XtGrabNone);
  525.  
  526.     display(l, cur);
  527.     XMapRaised(XtDisplay(l->shell), XtWindow(l->shell));
  528. }
  529.  
  530. /*
  531.  * This is only called from usage().
  532.  */
  533. void 
  534. HelpTextOutput(FILE * fd, String name)
  535. {
  536.     char *txt;
  537.     int col, wlen, i;
  538.     char *tp, *wstart;
  539.     HelpInfo *head, *cur;
  540.  
  541.     head = buildInfo(NULL);
  542.  
  543.     for (i = 0, cur = head; cur != NULL; cur = cur->next, i++)
  544.     if (strcmp(name, cur->name) == 0)
  545.         break;
  546.  
  547.     if (cur == NULL)
  548.     return;
  549.  
  550.     txt = buildText(cur);
  551.  
  552.     col = wlen = 0;
  553.     for (tp = txt; *tp != '\0'; tp++) {
  554.     if (isspace(*tp) || *tp == '\n') {
  555.         for (i = 0; i < wlen; i++, wstart++)
  556.         putc(*wstart, fd);
  557.         col += wlen;
  558.         wlen = 0;
  559.         if (*tp == '\t') {
  560.         do {
  561.             putc(' ', fd);
  562.             col++;
  563.         }
  564.         while (col % TAB_DISTANCE != 0);
  565.         } else if (*tp == '\n') {
  566.         putc(*tp, fd);
  567.         col = 0;
  568.         } else {
  569.         putc(*tp, fd);
  570.         col++;
  571.         }
  572.  
  573.         if (col > 75) {
  574.         putc('\n', fd);
  575.         col = 0;
  576.         }
  577.     } else if (wlen != 0) {
  578.         if (col != 0 && (wlen + col > 75)) {
  579.         putc('\n', fd);
  580.         col = 0;
  581.         }
  582.         wlen++;
  583.     } else {
  584.         wlen = 1;
  585.         wstart = tp;
  586.     }
  587.     }
  588.     for (i = 0; i < wlen; i++, wstart++)
  589.     putc(*wstart, fd);
  590.     if (col != 0)
  591.     putc('\n', fd);
  592.  
  593.     XtFree((XtPointer) txt);
  594. }
  595.  
  596. static void 
  597. helpAction(Widget w, XEvent * event, String * prms, Cardinal * nprms)
  598. {
  599.     if (*nprms != 1) {
  600.     fprintf(stderr, "Help called with wrong number of params\n");
  601.     return;
  602.     }
  603.     HelpDialog(w, prms[0]);
  604. }
  605.  
  606. void 
  607. HelpInit(Widget top)
  608. {
  609.     static XtActionsRec act =
  610.     {"PaintHelp", (XtActionProc) helpAction};
  611.  
  612.     XtAppAddActions(XtWidgetToApplicationContext(top), &act, 1);
  613.  
  614.     toplevel = top;
  615. }