home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / x / xtici.zip / xtici / widgets / TriText.c < prev    next >
C/C++ Source or Header  |  1991-08-28  |  28KB  |  904 lines

  1. /*
  2.  * Code and supporting documentation (c) Copyright 1990 1991 Tektronix, Inc.
  3.  *     All Rights Reserved
  4.  * 
  5.  * This file is a component of an X Window System client which uses the Xcms 
  6.  * Color Management System.  TekColor is a trademark of Tektronix, Inc.  The
  7.  * TekColor Editor is the subject of U.S. and foreign patents pending.  The
  8.  * term "TekHVC" designates a particular color space that is the subject of
  9.  * U.S. Patent No. 4,985,853 (equivalent foreign patents pending).
  10.  * Permission is hereby granted to use, copy, modify, sell, and otherwise
  11.  * distribute this software and its documentation for the X Window System
  12.  * environment, for any purpose and without fee, provided that:
  13.  * 
  14.  * 1.    The code and documentation are only used to implement a 
  15.  *      TekColor Editor in an X Window System environment; and
  16.  * 2.    This copyright and permission notice is reproduced in all copies
  17.  *     of the code and in supporting documentation.
  18.  * 
  19.  * Permission is granted to modify this code as required to allow it to
  20.  * be compiled on any host computer, provided that the functionality of
  21.  * the TekColor Editor is not modified in any way.  A description of any 
  22.  * modifications must be sent to Tektronix, Inc.  Contact 
  23.  * Tektronix Inc., P.O. Box 1000, Mail Station 60-850, 
  24.  * Network Displays Division Engineering, Wilsonville, OR 97070.
  25.  *  
  26.  * Tektronix makes no representation about the suitability of this software
  27.  * for any purpose.  It is provided "as is" and with all faults.
  28.  * 
  29.  * TEKTRONIX DISCLAIMS ALL WARRANTIES APPLICABLE TO THIS SOFTWARE,
  30.  * INCLUDING THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
  31.  * PARTICULAR PURPOSE.  IN NO EVENT SHALL TEKTRONIX BE LIABLE FOR ANY
  32.  * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
  33.  * RESULTING FROM LOSS OF USE, DATA, OR PROFITS, WHETHER IN AN ACTION OF
  34.  * CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
  35.  * CONNECTION WITH THE USE OR THE PERFORMANCE OF THIS SOFTWARE.
  36.  *
  37.  *    NAME
  38.  *        TriText.c -- the TriText widget
  39.  *
  40.  *    DESCRIPTION
  41.  *        I needed to do my own layout and text management.
  42.  *
  43.  *    HISTORY
  44.  *
  45.  *    HISTORY END
  46.  *
  47.  */
  48.  
  49. #ifndef LINT
  50. static char *copy_notice = "Copyright 1991 Tektronix, Inc.";
  51. #ifdef RCS_ID
  52. static char *rcsid=  "$Header: TriText.c,v 1.2 91/08/22 11:36:39 adamsc Exp $";
  53. #endif /* RCS_ID */
  54. #endif /* LINT */
  55.  
  56. #include <stdio.h>
  57. #include <X11/IntrinsicP.h>
  58. #include <X11/CoreP.h>
  59. #include <X11/StringDefs.h>
  60. #include <X11/Xmu/Misc.h>
  61. #include <X11/Xaw/XawInit.h>
  62. #include <X11/Xaw/AsciiTextP.h>
  63. #include <X11/Xaw/Form.h>
  64. #include <X11/Xaw/Label.h>
  65. #include "TriTextP.h"
  66.  
  67. static XtResource resources[] = {
  68. #define offset(field) XtOffset(TriTextWidget, tritext.field)
  69.     /* {name, class, type, size, offset, default_type, default_addr}, */
  70.     { XtNblinkRate, XtCBlinkRate, XtRInt, sizeof(int),
  71.       offset(blink), XtRImmediate, (XtPointer)0 },
  72.     { XtNlength, XtCLength, XtRInt, sizeof(int),
  73.       offset(length), XtRImmediate, (XtPointer)7 },
  74.     { XtNlabelList, XtCLabelList, XtRLabelList, sizeof(String *),
  75.       offset(labels), XtRImmediate, (XtPointer)NULL},
  76.     { XtNformat, XtCFormat, XtRString, sizeof(String),
  77.     offset(format), XtRImmediate, (XtPointer)NULL },
  78.     { XtNfloatList, XtCFloatList, XtRFloatList, sizeof(XcmsFloat *),
  79.       offset(values), XtRImmediate, (XtPointer)NULL },
  80.     { XtNactivateCallback, XtCActivateCallback, XtRCallback, 
  81.     sizeof(XtCallbackList), offset(activate), XtRCallback, NULL },
  82.     { XtNfocusCallback, XtCFocusCallback, XtRCallback, 
  83.     sizeof(XtCallbackList), offset(gain), XtRCallback, NULL },
  84.     { XtNlosingFocusCallback, XtCLosingFocusCallback, XtRCallback, 
  85.     sizeof(XtCallbackList), offset(lose), XtRCallback, NULL },
  86.     { XtNmodifyVerifyCallback, XtCModifyVerifyCallback, XtRCallback, 
  87.     sizeof(XtCallbackList), offset(verify), XtRCallback, NULL },
  88. #undef offset
  89. };
  90.  
  91. /* forward declarations for the class struct */
  92. static void ChangeManaged();
  93. static void Destroy();
  94. /* static void Focus(); */
  95. static void Initialize();
  96. /* static void LoseFocus(); */
  97. static void Resize();
  98. static Boolean SetValues();
  99. static XtGeometryResult GeometryManager();
  100. static XtGeometryResult QueryGeometry();
  101.  
  102. TriTextClassRec triTextClassRec = {
  103.   { /* core_class fields */
  104.     /* superclass        */    (WidgetClass) &compositeClassRec,
  105.     /* class_name        */    "TriText",
  106.     /* widget_size        */    sizeof(TriTextRec),
  107.     /* class_initialize        */    XawInitializeWidgetSet,
  108.     /* class_part_initialize    */    NULL,
  109.     /* class_inited        */    FALSE,
  110.     /* initialize        */    Initialize,
  111.     /* initialize_hook        */    NULL,
  112.     /* realize            */    XtInheritRealize,
  113.     /* actions            */    NULL,
  114.     /* num_actions        */    0,
  115.     /* resources        */    resources,
  116.     /* num_resources        */    XtNumber(resources),
  117.     /* xrm_class        */    NULLQUARK,
  118.     /* compress_motion        */    TRUE,
  119.     /* compress_exposure    */    TRUE,
  120.     /* compress_enterleave    */    FALSE,
  121.     /* visible_interest        */    FALSE,
  122.     /* destroy            */    Destroy,
  123.     /* resize            */    Resize,
  124.     /* expose            */    NULL,
  125.     /* set_values        */    SetValues,
  126.     /* set_values_hook        */    NULL,
  127.     /* set_values_almost    */    XtInheritSetValuesAlmost,
  128.     /* get_values_hook        */    NULL,
  129.     /* accept_focus        */    NULL,
  130.     /* version            */    XtVersion,
  131.     /* callback_private        */    NULL,
  132.     /* tm_table            */    NULL,
  133.     /* query_geometry        */    QueryGeometry,
  134.     /* display_accelerator    */    NULL,
  135.     /* extension        */    NULL
  136.   },
  137.   { /* composite fields */
  138.     /* geometry manager        */    GeometryManager,
  139.     /* change managed        */    ChangeManaged,
  140.     /* insert child        */    XtInheritInsertChild,
  141.     /* delete child        */    XtInheritDeleteChild,
  142.     /* extension        */    NULL
  143.   },
  144.   { /* tri-text fields */
  145.     /* extension        */    NULL
  146.   },
  147. };
  148.  
  149. WidgetClass triTextWidgetClass = (WidgetClass)&triTextClassRec;
  150.  
  151. /****************************************************************
  152.  *
  153.  * Private Procedures
  154.  *
  155.  ****************************************************************/
  156.  
  157. /* forward declarations of utility functions */
  158. static void CreateChildren();
  159. static void NewValue();
  160. /* static void Verify(); */
  161.  
  162. static char *warning1 = "Length of text must be positive";
  163. static char *warning2 = "Blink rate must be non-negative";
  164.  
  165. /*
  166.  *  Sometime in the future this geometry management could be simplified
  167.  *  for now just use the box routines.
  168.  *
  169.  * Do a layout, either actually assigning positions, or just calculating size.
  170.  * Returns minimum width and height that will preserve the same layout.
  171.  *
  172.  */
  173.  
  174. static void DoLayout(ttw, width, height, reply_width, reply_height, position)
  175.     TriTextWidget ttw;
  176.     Dimension      width, height;
  177.     Dimension      *reply_width, *reply_height; /* bounding box */
  178.     Boolean      position;    /* actually reposition the windows? */
  179. {
  180.     Cardinal  i;
  181.     Dimension w, h;    /* Width and height needed for widget         */
  182.     Dimension lw, lh;    /* Width and height needed for current line     */
  183.     Dimension bw, bh;    /* Width and height needed for current widget     */
  184.     register Widget widget;    /* Current widget             */
  185.     int num_mapped_children = 0;
  186.  
  187.     /* TriText width and height */
  188.     w = 0;
  189.     h = 0;
  190.    
  191.     /* Line width and height */
  192.     lh = 0;
  193.     lw = 0;
  194.   
  195.     for (i = 0; i < ttw->composite.num_children; i++) {
  196.     widget = ttw->composite.children[i];
  197.     if (widget->core.managed) {
  198.         if (widget->core.mapped_when_managed) num_mapped_children++;
  199.         /* Compute widget width */
  200.         bw = widget->core.width + 2*widget->core.border_width;
  201.         if (lw + bw > width) {
  202.         if (lw != 0) {
  203.             /* At least one widget on this line, and
  204.              * can't fit any more.  Start new line.
  205.              */
  206.             AssignMax(w, lw);
  207.             h += lh;
  208.             lh = 0;
  209.             lw = 0;
  210.         } else if (!position) {
  211.             /* too narrow for this widget; we'll assume we can grow */
  212.             DoLayout(ttw, lw + bw, height, reply_width,
  213.                  reply_height, position);
  214.             return;
  215.         }
  216.         }
  217.         if (position && (lw != widget->core.x || h != widget->core.y)) {
  218.         /* It would be nice to use window gravity, but there isn't
  219.          * sufficient fine-grain control to nicely handle all
  220.          * situations (e.g. when only the height changes --
  221.          * a common case).  Explicit unmapping is a cheap hack
  222.          * to speed things up & avoid the visual jitter as
  223.          * things slide around.
  224.          *
  225.          * %%% perhaps there should be a client resource to
  226.          * control this.  If so, we'll have to optimize to
  227.          * perform the moves from the correct end so we don't
  228.          * force extra exposures as children occlude each other.
  229.          */
  230.         if (XtIsRealized(widget) && widget->core.mapped_when_managed)
  231.             XUnmapWindow( XtDisplay(widget), XtWindow(widget) );
  232.         XtMoveWidget(widget, (int)lw, (int)h);
  233.         }
  234.         lw += bw;
  235.         bh = widget->core.height + 2*widget->core.border_width;
  236.         AssignMax(lh, bh);
  237.     } /* if managed */
  238.     } /* for */
  239.  
  240.     if (position && XtIsRealized((Widget)ttw)) {
  241.     if (ttw->composite.num_children == num_mapped_children)
  242.         XMapSubwindows( XtDisplay((Widget)ttw), XtWindow((Widget)ttw) );
  243.     else {
  244.         int i = ttw->composite.num_children;
  245.         register Widget *childP = ttw->composite.children;
  246.         for (; i > 0; childP++, i--)
  247.         if (XtIsRealized(*childP) && XtIsManaged(*childP) &&
  248.             (*childP)->core.mapped_when_managed)
  249.             XtMapWidget(*childP);
  250.     }
  251.     }
  252.  
  253.     /* Finish off last line */
  254.     if (lw != 0) {
  255.     AssignMax(w, lw);
  256.         h += lh;
  257.     }
  258.  
  259.     *reply_width = Max(w, 1);
  260.     *reply_height = Max(h, 1);
  261. }
  262.  
  263. /*
  264.  *
  265.  * Calculate preferred size, given constraining box, caching it in the widget.
  266.  *
  267.  */
  268.  
  269. static XtGeometryResult QueryGeometry(widget, constraint, preferred)
  270.     Widget widget;
  271.     XtWidgetGeometry *constraint, *preferred;
  272. {
  273.     TriTextWidget w = (TriTextWidget)widget;
  274.     Dimension width /*, height */;
  275.     Dimension preferred_width = w->tritext.preferred_width;
  276.     Dimension preferred_height = w->tritext.preferred_height;
  277.  
  278.     constraint->request_mode &= CWWidth | CWHeight;
  279.  
  280.     if (constraint->request_mode == 0)
  281.     /* parent isn't going to change w or h, so nothing to re-compute */
  282.     return XtGeometryYes;
  283.  
  284.     if (constraint->request_mode == w->tritext.last_query_mode &&
  285.     (!(constraint->request_mode & CWWidth) ||
  286.      constraint->width == w->tritext.last_query_width) &&
  287.     (!(constraint->request_mode & CWHeight) ||
  288.      constraint->height == w->tritext.last_query_height)) {
  289.     /* same query; current preferences are still valid */
  290.     preferred->request_mode = CWWidth | CWHeight;
  291.     preferred->width = preferred_width;
  292.     preferred->height = preferred_height;
  293.     if (constraint->request_mode == (CWWidth | CWHeight) &&
  294.         constraint->width == preferred_width &&
  295.         constraint->height == preferred_height)
  296.         return XtGeometryYes;
  297.     else
  298.         return XtGeometryAlmost;
  299.     }
  300.     
  301.     /* else gotta do it the long way...
  302.        I have a preference for tall and narrow, so if my width is
  303.        constrained, I'll accept it; otherwise, I'll compute the minimum
  304.        width that will fit me within the height constraint */
  305.  
  306.     w->tritext.last_query_mode = constraint->request_mode;
  307.     w->tritext.last_query_width = constraint->width;
  308.     w->tritext.last_query_height= constraint->height;
  309.  
  310.     if (constraint->request_mode & CWWidth)
  311.     width = constraint->width;
  312.     else { /* if (constraint->request_mode & CWHeight) */
  313.        /* let's see if I can become any narrower */
  314.     width = 0;
  315.     constraint->width = 65535;
  316.     }
  317.  
  318.     /* height is currently ignored by DoLayout.
  319.        height = (constraint->request_mode & CWHeight) ? constraint->height
  320.                : *preferred_height;
  321.      */
  322.     DoLayout(w, width, (Dimension)0, &preferred_width, &preferred_height, 
  323.         FALSE);
  324.  
  325.     if (constraint->request_mode & CWHeight &&
  326.     preferred_height > constraint->height) {
  327.     /* find minimum width for this height */
  328.     if (preferred_width > constraint->width) {
  329.         /* punt; over-constrained */
  330.     } else {
  331.         width = preferred_width;
  332.         do { /* find some width big enough to stay within this height */
  333.         width *= 2;
  334.         if (width > constraint->width) 
  335.             width = constraint->width;
  336.         DoLayout(w, width, (Dimension)0, 
  337.              &preferred_width, &preferred_height, FALSE);
  338.         } while (preferred_height > constraint->height &&
  339.              width < constraint->width);
  340.         if (width != constraint->width) {
  341.         do { /* find minimum width */
  342.             width = preferred_width;
  343.             DoLayout(w, preferred_width - 1, (Dimension)0,
  344.                  &preferred_width, &preferred_height, FALSE);
  345.         } while (preferred_height < constraint->height);
  346.         /* one last time */
  347.         DoLayout(w, width, (Dimension)0, 
  348.              &preferred_width, &preferred_height, FALSE);
  349.         }
  350.     }
  351.     }
  352.  
  353.     preferred->request_mode = CWWidth | CWHeight;
  354.     preferred->width = w->tritext.preferred_width = preferred_width;
  355.     preferred->height = w->tritext.preferred_height = preferred_height;
  356.  
  357.     if (constraint->request_mode == (CWWidth|CWHeight)
  358.     && constraint->width == preferred_width
  359.     && constraint->height == preferred_height)
  360.     return XtGeometryYes;
  361.     else
  362.     return XtGeometryAlmost;
  363. }
  364.  
  365. /*
  366.  *
  367.  * Actually layout the widget
  368.  *
  369.  */
  370.  
  371. static void Resize(w)
  372.     Widget    w;
  373. {
  374.     Dimension junk;
  375.  
  376.     DoLayout((TriTextWidget)w, w->core.width, w->core.height, &junk, &junk, 
  377.         TRUE);
  378. } /* Resize */
  379.  
  380. /*
  381.  *
  382.  * Try to do a new layout within the current width and height;
  383.  * if that fails try to resize and do it within the size returned
  384.  * by QueryGeometry.
  385.  *
  386.  * TryNewLayout just says if it's possible, and doesn't actually move the kids
  387.  */
  388.  
  389. static Boolean TryNewLayout(ttw)
  390.     TriTextWidget    ttw;
  391. {
  392.     Dimension     preferred_width, preferred_height;
  393.     Dimension    proposed_width, proposed_height;
  394.     int        iterations;
  395.  
  396.     DoLayout(ttw, ttw->core.width, ttw->core.height,
  397.           &preferred_width, &preferred_height, FALSE);
  398.  
  399.     /* at this point, preferred_width is guaranteed to not be greater
  400.        than ttw->core.width unless some child is larger, so there's no
  401.        point in re-computing another layout */
  402.  
  403.     if ((ttw->core.width == preferred_width) &&
  404.     (ttw->core.height == preferred_height)) {
  405.         /* Same size */
  406.     return (TRUE);
  407.     }
  408.  
  409.     /* let's see if our parent will go for a new size. */
  410.     iterations = 0;
  411.     proposed_width = preferred_width;
  412.     proposed_height = preferred_height;
  413.     do {
  414.     switch (XtMakeResizeRequest((Widget)ttw,proposed_width,proposed_height,
  415.                      &proposed_width, &proposed_height))
  416.     {
  417.         case XtGeometryYes:
  418.         return (TRUE);
  419.  
  420.         case XtGeometryNo:
  421.         if (iterations > 0)
  422.             /* protect from malicious parents who change their minds */
  423.             DoLayout(ttw, ttw->core.width, ttw->core.height,
  424.                   &preferred_width, &preferred_height, FALSE);
  425.         if ((preferred_width <= ttw->core.width) &&
  426.             (preferred_height <= ttw->core.height))
  427.             return (TRUE);
  428.         else
  429.             return (FALSE);
  430.  
  431.         case XtGeometryAlmost:
  432.         if (proposed_height >= preferred_height &&
  433.             proposed_width >= preferred_width) {
  434.  
  435.             /*
  436.              * Take it, and assume the parent knows what it is doing.
  437.              *
  438.              * The parent must accept this since it was returned in
  439.              * almost.
  440.              *
  441.              */
  442.             (void) XtMakeResizeRequest( (Widget)ttw,
  443.                        proposed_width, proposed_height,
  444.                        &proposed_width, &proposed_height);
  445.             return(TRUE);
  446.         }
  447.         else if (proposed_width != preferred_width) {
  448.             /* recalc bounding box; height might change */
  449.             DoLayout(ttw, proposed_width, (Dimension)0,
  450.                  &preferred_width, &preferred_height, FALSE);
  451.             proposed_height = preferred_height;
  452.         }
  453.         else { /* proposed_height != preferred_height */
  454.             XtWidgetGeometry constraints, reply;
  455.             constraints.request_mode = CWHeight;
  456.             constraints.height = proposed_height;
  457.             (void)QueryGeometry((Widget)ttw, &constraints, &reply);
  458.             proposed_width = preferred_width;
  459.         }
  460.     }
  461.     iterations++;
  462.     } while (iterations < 10);
  463.     return (FALSE);
  464. }
  465.  
  466. /*
  467.  *
  468.  * Geometry Manager
  469.  *
  470.  * 'reply' is unused; we say only yeay or nay, never almost.
  471.  *
  472.  */
  473.  
  474. /*ARGSUSED*/
  475. static XtGeometryResult GeometryManager(w, request, reply)
  476.     Widget        w;
  477.     XtWidgetGeometry    *request;
  478.     XtWidgetGeometry    *reply;    /* RETURN */
  479.  
  480. {
  481.     Dimension    width, height, borderWidth;
  482.     TriTextWidget ttw;
  483.  
  484.     /* Position request always denied */
  485.     if ((request->request_mode & CWX && request->x != w->core.x) ||
  486.     (request->request_mode & CWY && request->y != w->core.y))
  487.         return (XtGeometryNo);
  488.  
  489.     /* Size changes must see if the new size can be accomodated */
  490.     if (request->request_mode & (CWWidth | CWHeight | CWBorderWidth)) {
  491.     /* Make all three fields in the request valid */
  492.     if ((request->request_mode & CWWidth) == 0)
  493.         request->width = w->core.width;
  494.     if ((request->request_mode & CWHeight) == 0)
  495.         request->height = w->core.height;
  496.         if ((request->request_mode & CWBorderWidth) == 0)
  497.         request->border_width = w->core.border_width;
  498.  
  499.     /* Save current size and set to new size */
  500.     width = w->core.width;
  501.     height = w->core.height;
  502.     borderWidth = w->core.border_width;
  503.     w->core.width = request->width;
  504.     w->core.height = request->height;
  505.     w->core.border_width = request->border_width;
  506.  
  507.     /* Decide if new layout works: (1) new widget is smaller,
  508.        (2) new widget fits in existing TriText, (3) TriText can be
  509.        expanded to allow new widget to fit */
  510.     ttw = (TriTextWidget) w->core.parent;
  511.  
  512.     if (TryNewLayout(ttw)) {
  513.         /* Fits in existing or new space, relayout */
  514.         (*XtClass((Widget)ttw)->core_class.resize)((Widget)ttw);
  515.         return (XtGeometryYes);
  516.     } else {
  517.         /* Cannot satisfy request, change back to original geometry */
  518.         w->core.width = width;
  519.         w->core.height = height;
  520.         w->core.border_width = borderWidth;
  521.         return (XtGeometryNo);
  522.     }
  523.     } /* if any size changes requested */
  524.  
  525.     /* Any stacking changes don't make a difference, so allow if that's all */
  526.     return (XtGeometryYes);
  527. }
  528.  
  529. static void ChangeManaged(w)
  530.     Widget w;
  531. {
  532.     /* Reconfigure the widget */
  533.     (void) TryNewLayout((TriTextWidget)w);
  534.     Resize(w);
  535. }
  536.  
  537. /*
  538.  * A superclass for this class could allow any number of rows, just not 3.
  539.  * I don't want to deal with additional complexity, fix this if you need it.
  540.  */
  541. #define RowCt    3
  542.  
  543. static void Warning(widget, message)
  544. Widget widget;
  545. char *message;
  546. {
  547.     /*  R4 says use XtAppWarningMsg but no information on how to set
  548.      *  the parameters.
  549.      */
  550.     if (!widget)
  551.     XtWarning(message);
  552.     else
  553.     XtAppWarning(XtWidgetToApplicationContext(widget), message);
  554. }
  555.  
  556. static void Destroy(tri)
  557. TriTextWidget tri;
  558. {
  559.     int i;
  560.  
  561.     for (i = 0; i < RowCt; i++) {
  562.     if (tri->tritext.plabel[i])
  563.         XtFree(tri->tritext.plabel[i]);
  564.     }
  565.  
  566.     if (tri->tritext.pformat)
  567.     XtFree(tri->tritext.pformat);
  568. }
  569.  
  570. /* ARGSUSED */
  571. static void Initialize(req, new)
  572. TriTextWidget req, new;
  573. {
  574.     int i;
  575.     int len;
  576.  
  577.     /*    Validate input resources */
  578.     if (new->tritext.length <= 0) {
  579.     Warning(new, warning1);
  580.     new->tritext.length = 7;
  581.     }
  582.     if (new->tritext.blink < 0) {  /* 0 is valid, means no buttons */
  583.     Warning(new, warning2);
  584.     new->tritext.blink = 0;
  585.     }
  586.  
  587.     if (new->tritext.labels) {
  588.     for (i = 0; i < RowCt; i++) {
  589.         len = strlen(new->tritext.labels[i]) + 1;
  590.         new->tritext.plabel[i] = XtMalloc(len);
  591.         strcpy(new->tritext.plabel[i], new->tritext.labels[i]);
  592.     }
  593.     } else {
  594.     for (i = 0; i < RowCt; i++)
  595.         new->tritext.plabel[i] = NULL;
  596.     }
  597.     if (new->tritext.format) {
  598.     len = strlen(new->tritext.format) + 1;
  599.     new->tritext.pformat = (String)XtMalloc(len);
  600.     strcpy(new->tritext.pformat, new->tritext.format);
  601.     } else {
  602.     len = 3;
  603.     new->tritext.pformat = (String)XtMalloc(len);
  604.     strcpy(new->tritext.pformat, "%f");
  605.     }
  606.  
  607.     /* create all of the widgets */
  608.     CreateChildren(new);
  609. }
  610.  
  611. #define BUFLEN 512
  612.  
  613. /* Most values are passed on to one child or another */
  614. /* ARGSUSED */
  615. static Boolean SetValues(cur, req, new)
  616. TriTextWidget cur, req, new;
  617. {
  618.     Arg args[5];
  619.     int cnt = 0;
  620.     int i;
  621.     char buf[BUFLEN];    /* danger, this could overflow */
  622.  
  623.     if (new->tritext.length <= 0) {
  624.     Warning(new, warning1);
  625.     new->tritext.length = cur->tritext.length;
  626.     } else if (new->tritext.length != cur->tritext.length) {
  627.     XtSetArg(args[cnt], XtNlength, new->tritext.length);    cnt++;
  628.     }
  629.  
  630.  
  631.     if (new->tritext.blink < 0) {
  632.     Warning(new, warning2);
  633.     new->tritext.blink = cur->tritext.blink;
  634.     } else if (new->tritext.blink != cur->tritext.blink) {
  635.     XtSetArg(args[cnt], XtNblinkRate, new->tritext.blink);    cnt++;
  636.     }
  637.  
  638.     /* TODO: probably should allow this */
  639.     if (new->tritext.labels != cur->tritext.labels)
  640.     Warning(new, "Cannot change labels");
  641.     if (new->tritext.format != cur->tritext.format)
  642.     Warning(new, "Cannot change format");
  643.  
  644.     if (cnt > 0) {
  645.     for (i = 0; i < RowCt; i++)
  646.         XtSetValues(new->tritext.wlist[i+RowCt], args, cnt);
  647.     }
  648.  
  649.     if (new->tritext.values) {
  650.     for (i = 0; i < RowCt; i++) {
  651.         /* set the string in each ascii text widget */
  652.         bzero (buf, BUFLEN);
  653.         sprintf(buf, new->tritext.pformat, new->tritext.values[i]);
  654.         XtSetArg (args[0], XtNstring, buf);
  655.         XtSetValues (new->tritext.wlist[i+RowCt], args, 1);
  656.     }
  657.     }
  658.  
  659.     /* possibly set some new values */
  660.  
  661.     return(False);    /* there is nothing for this widget to redraw */
  662. }
  663.  
  664. static void CreateChildren(tri)
  665. TriTextWidget tri;
  666. {
  667.     int cnt;
  668.     Widget form;
  669.     WidgetList wlist = tri->tritext.wlist;
  670.     Arg args[15];
  671.     XcmsFloat val;
  672.     char buf[BUFLEN];    /* danger, this could overflow */
  673.  
  674.     cnt = 0;
  675.     XtSetArg(args[cnt], XtNborderWidth, 0);            cnt++;
  676.     form = XtCreateManagedWidget ("form", formWidgetClass, (Widget)tri,
  677.                   args, cnt);
  678.     tri->tritext.form = form;
  679.  
  680.     /* this is label 1 in the upper left hand corner */
  681.     cnt = 0;
  682.     if (tri->tritext.plabel[0]) {
  683.     XtSetArg(args[cnt], XtNlabel, tri->tritext.plabel[0]);    cnt++;
  684.     } 
  685.     wlist[0] = XtCreateWidget("item1", labelWidgetClass, form, args, cnt);
  686.  
  687.     /* this is label 2 just below label 1 */
  688.     cnt = 0;
  689.     if (tri->tritext.plabel[1]) {
  690.     XtSetArg(args[cnt], XtNlabel, tri->tritext.plabel[1]);    cnt++;
  691.     }
  692.     XtSetArg(args[cnt], XtNfromVert, wlist[0]);            cnt++;
  693.     wlist[1] = XtCreateWidget("item2", labelWidgetClass, form, args, cnt);
  694.  
  695.     /* this is label 3 just below label 2 */
  696.     cnt = 0;
  697.     if (tri->tritext.plabel[2]) {
  698.     XtSetArg(args[cnt], XtNlabel, tri->tritext.plabel[2]);    cnt++;
  699.     }
  700.     XtSetArg(args[cnt], XtNfromVert, wlist[1]);            cnt++;
  701.     wlist[2] = XtCreateWidget("item3", labelWidgetClass, form, args, cnt);
  702.  
  703.     /* this is text widget 1 just to the right of label 1 */
  704.     cnt = 0;
  705.     if (tri->tritext.length > 0) {
  706.     XtSetArg(args[cnt], XtNlength, tri->tritext.length);    cnt++;
  707.     }
  708.     if (tri->tritext.values)
  709.     val = tri->tritext.values[0];
  710.     else
  711.     val = 0.0;
  712.     bzero (buf, BUFLEN);
  713.     sprintf(buf, tri->tritext.pformat, val);
  714.     XtSetArg(args[cnt], XtNstring, buf);            cnt++;
  715.     XtSetArg(args[cnt], XtNtype, XawAsciiString);               cnt++;
  716.     XtSetArg(args[cnt], XtNeditType, XawtextEdit);        cnt++;
  717.     XtSetArg(args[cnt], XtNuseStringInPlace, False);        cnt++;
  718.     XtSetArg(args[cnt], XtNresize, XawtextResizeBoth);        cnt++;    
  719.     XtSetArg(args[cnt], XtNfromHoriz, wlist[0]);        cnt++;
  720.     wlist[3] = XtCreateWidget("text1", asciiTextWidgetClass, form, args, cnt);
  721.     XtAddCallback (XawTextGetSource(wlist[3]), XtNcallback, NewValue,
  722.             (XtPointer)RowCt);
  723.  
  724.     /* this is text widget 2 just to the right of label 2 */
  725.     /* Note the repition of the first 4 args from above */
  726.     cnt = 0;
  727.     if (tri->tritext.length > 0) {
  728.     XtSetArg(args[cnt], XtNlength, tri->tritext.length);    cnt++;
  729.     }
  730.     if (tri->tritext.values)
  731.     val = tri->tritext.values[1];
  732.     else
  733.     val = 0.0;
  734.     bzero (buf, BUFLEN);
  735.     sprintf(buf, tri->tritext.pformat, val);
  736.     XtSetArg(args[cnt], XtNstring, buf);            cnt++;
  737.     XtSetArg(args[cnt], XtNeditType, XawtextEdit);        cnt++;
  738.     XtSetArg(args[cnt], XtNuseStringInPlace, False);        cnt++;
  739.     XtSetArg(args[cnt], XtNresize, XawtextResizeBoth);        cnt++;    
  740.     XtSetArg(args[cnt], XtNfromVert, wlist[3]);            cnt++;
  741.     XtSetArg(args[cnt], XtNfromHoriz, wlist[1]);        cnt++;
  742.     wlist[4] = XtCreateWidget("text2", asciiTextWidgetClass, form, args, cnt);
  743.     XtAddCallback (XawTextGetSource(wlist[4]), XtNcallback, NewValue,
  744.             (XtPointer)(RowCt + 1));
  745.  
  746.     /* this is text widget 3 just to the right of label 3 */
  747.     /* Note the repitition of the first 4 args from above */
  748.     cnt = 0;
  749.     if (tri->tritext.length > 0) {
  750.     XtSetArg(args[cnt], XtNlength, tri->tritext.length);    cnt++;
  751.     }
  752.     if (tri->tritext.values)
  753.     val = tri->tritext.values[2];
  754.     else
  755.     val = 0.0;
  756.     bzero (buf, BUFLEN);
  757.     sprintf(buf, tri->tritext.pformat, val);
  758.     XtSetArg(args[cnt], XtNstring, buf);            cnt++;
  759.     XtSetArg(args[cnt], XtNeditType, XawtextEdit);        cnt++;
  760.     XtSetArg(args[cnt], XtNuseStringInPlace, False);        cnt++;
  761.     XtSetArg(args[cnt], XtNresize, XawtextResizeBoth);        cnt++;    
  762.     XtSetArg(args[cnt], XtNfromVert, wlist[4]);            cnt++;
  763.     XtSetArg(args[cnt], XtNfromHoriz, wlist[2]);        cnt++;
  764.     wlist[5] = XtCreateWidget("text3", asciiTextWidgetClass, form, args, cnt);
  765.     XtAddCallback (XawTextGetSource(wlist[5]), XtNcallback, NewValue,
  766.             (XtPointer)(RowCt + 2));
  767.  
  768.     XtManageChildren(wlist, TriTextChildCt);
  769.  
  770.     tri->tritext.numchildren = TriTextChildCt;
  771.     /* may need to set the translations on the text widgets. */
  772. /*    mytranslations = XtParseTranslationTable(myTranslations);
  773.  *    XtOverrideTranslations(wlist[3], mytranslations);
  774.  *    XtOverrideTranslations(wlist[4], mytranslations);
  775.  *    XtOverrideTranslations(wlist[5], mytranslations);
  776.  */
  777. }
  778.  
  779. /*
  780.  * Callback for focus change; just record which widget is changing,
  781.  * then pass through.
  782.  */
  783. /* static void Focus(w, which, call)
  784.  * Widget w;
  785.  * int which;
  786.  * TriCallbackStruct *call;
  787.  * {
  788.  *     TriCallbackStruct tmp;
  789.  * 
  790.  *     /* value is not valid for this callback */
  791. /*    tmp.value = -1.0;
  792.  *    tmp.reason = call->reason;
  793.  *    tmp.event = call->event;
  794.  *    tmp.index = which - RowCt;
  795.  * 
  796.  *     XtCallCallbacks(w, XtNfocusCallback, &tmp);
  797.  * }
  798.  * 
  799. /*
  800.  * Callback for focus change; just record which widget is changing,
  801.  * then pass through.
  802.  */
  803. /* static void LoseFocus(w, which, call)
  804.  * Widget w;
  805.  * int which;
  806.  * TriCallbackStruct *call;
  807.  * {
  808.  *     TriCallbackStruct tmp;
  809.  * 
  810.  *     /* value is not valid for this callback */
  811. /*    tmp.value = -1.0;
  812.  *    tmp.reason = call->reason;
  813.  *    tmp.event = call->event;
  814.  *    tmp.index = which - RowCt;
  815.  * 
  816.  *     XtCallCallbacks(w, XtNlosingFocusCallback, tmp);
  817.  * }
  818.  */
  819. /*
  820.  * This callback sets the widget which was modified.
  821.  * The change is not effected until the cursor leaves the window.
  822.  */
  823. /* ARGSUSED */
  824. static void NewValue(w, which, call)
  825. Widget w;
  826. int which;
  827. XtPointer call;
  828. {
  829.     /* Arg args[1]; */
  830.     /* String new; */
  831.     TriTextWidget tri = GetTriTextWidget (w);
  832.     TriCallbackStruct tmp;
  833.     /* double atof(); */
  834.  
  835.     if (!tri)
  836.     return;
  837.  
  838.     tmp.reason = CR_ACTIVATE;
  839.     tmp.event = NULL;
  840.     tmp.index = which - RowCt;
  841.     tmp.value = -1.0;       /* For now use an illegal value */
  842.     /*    XtSetArg (args[0], XtNstring, &new); */
  843.     /*    XtGetValues (w, args, 1); */
  844.  
  845.     /*    tmp.value = atof(new); */
  846.  
  847.     XtCallCallbacks((Widget)tri, XtNactivateCallback, &tmp);
  848.     /* May want to adjust text widget values based on return value */
  849. }
  850.  
  851. /*
  852.  * Callback for text verify; just pass this through back to the application
  853.  */
  854. /* static void Verify(w, which, call)
  855.  * Widget w;
  856.  * int which;
  857.  * ScaleCallbackStruct *call;
  858.  * {
  859.  *     TriTextWidget tri = (TriTextWidget)XtParent(w);
  860.  * 
  861.  *     XtCallCallbacks(tri, XtNmodifyVerifyCallback, call);
  862.  * }
  863.  */
  864.  
  865. void TriTextGetList(tri, list)
  866. TriTextWidget tri;
  867. XcmsFloat *list;
  868. {
  869.     Arg arg;
  870.     int i;
  871.     char *new;
  872.     double atof();
  873.  
  874.     for (i = 0; i < RowCt; i++) {
  875.     XtSetArg (arg, XtNstring, (XtPointer)&new);
  876.     XtGetValues (tri->tritext.wlist[i+RowCt], &arg, 1);
  877.     list[i] = atof(new);
  878.     }
  879. }
  880.  
  881. void TriTextSetList(tri, list)
  882. TriTextWidget tri;
  883. XcmsFloat *list;
  884. {
  885.     Arg arg;
  886.     int i;
  887.     char buf[BUFLEN];
  888.  
  889.     for (i = 0; i < RowCt; i++) {
  890.     bzero (buf, BUFLEN);
  891.     sprintf(buf, tri->tritext.pformat, list[i]);
  892.     XtSetArg (arg, XtNstring, buf);
  893.     XtSetValues(tri->tritext.wlist[i+RowCt], &arg, 1);
  894.     }
  895. }
  896.  
  897. TriTextWidget GetTriTextWidget(wid)
  898. Widget wid;
  899. {
  900.     if (!wid || IsTriText(wid))
  901.     return ((TriTextWidget)wid);
  902.     return (GetTriTextWidget(XtParent(wid)));
  903. }
  904.