StripChart.c

Go to the documentation of this file.
00001 /* $XConsortium: StripChart.c,v 1.25 94/04/17 20:12:56 kaleb Exp $ */
00002 
00003 /***********************************************************
00004 
00005 Copyright (c) 1987, 1988, 1994  X Consortium
00006 
00007 Permission is hereby granted, free of charge, to any person obtaining a copy
00008 of this software and associated documentation files (the "Software"), to deal
00009 in the Software without restriction, including without limitation the rights
00010 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
00011 copies of the Software, and to permit persons to whom the Software is
00012 furnished to do so, subject to the following conditions:
00013 
00014 The above copyright notice and this permission notice shall be included in
00015 all copies or substantial portions of the Software.
00016 
00017 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
00018 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
00019 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
00020 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
00021 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
00022 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00023 
00024 Except as contained in this notice, the name of the X Consortium shall not be
00025 used in advertising or otherwise to promote the sale, use or other dealings
00026 in this Software without prior written authorization from the X Consortium.
00027 
00028 
00029 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
00030 
00031                         All Rights Reserved
00032 
00033 Permission to use, copy, modify, and distribute this software and its 
00034 documentation for any purpose and without fee is hereby granted, 
00035 provided that the above copyright notice appear in all copies and that
00036 both that copyright notice and this permission notice appear in 
00037 supporting documentation, and that the name of Digital not be
00038 used in advertising or publicity pertaining to distribution of the
00039 software without specific, written prior permission.  
00040 
00041 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00042 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00043 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00044 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00045 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00046 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00047 SOFTWARE.
00048 
00049 ******************************************************************/
00050 
00051 #include <stdio.h>
00052 #include <X11/IntrinsicP.h>
00053 #include <X11/StringDefs.h>
00054 #include <X11/Xaw3d/XawInit.h>
00055 #include <X11/Xaw3d/StripCharP.h>
00056 #include <X11/Xfuncs.h>
00057 
00058 #define MS_PER_SEC 1000
00059 
00060 /* Private Data */
00061 
00062 #define offset(field) XtOffsetOf(StripChartRec, field)
00063 
00064 static XtResource resources[] = {
00065     {XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
00066         offset(core.width), XtRImmediate, (XtPointer) 120},
00067     {XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
00068         offset(core.height), XtRImmediate, (XtPointer) 120},
00069     {XtNupdate, XtCInterval, XtRInt, sizeof(int),
00070         offset(strip_chart.update), XtRImmediate, (XtPointer) 10},
00071     {XtNminScale, XtCScale, XtRInt, sizeof(int),
00072         offset(strip_chart.min_scale), XtRImmediate, (XtPointer) 1},
00073     {XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
00074         offset(strip_chart.fgpixel), XtRString, XtDefaultForeground},
00075     {XtNhighlight, XtCForeground, XtRPixel, sizeof(Pixel),
00076         offset(strip_chart.hipixel), XtRString, XtDefaultForeground},
00077     {XtNgetValue, XtCCallback, XtRCallback, sizeof(XtPointer),
00078         offset(strip_chart.get_value), XtRImmediate, (XtPointer) NULL},
00079     {XtNjumpScroll, XtCJumpScroll, XtRInt, sizeof(int),
00080         offset(strip_chart.jump_val), XtRImmediate, (XtPointer) DEFAULT_JUMP},
00081 };
00082 
00083 #undef offset
00084 
00085 static void Initialize(), Destroy(), Redisplay(), MoveChart(), SetPoints();
00086 static Boolean SetValues();
00087 static int repaint_window();
00088 
00089 StripChartClassRec stripChartClassRec = {
00090     { /* core fields */
00091     /* superclass               */      (WidgetClass) &threeDClassRec,
00092     /* class_name               */      "StripChart",
00093     /* size                     */      sizeof(StripChartRec),
00094     /* class_initialize         */      XawInitializeWidgetSet,
00095     /* class_part_initialize    */      NULL,
00096     /* class_inited             */      FALSE,
00097     /* initialize               */      Initialize,
00098     /* initialize_hook          */      NULL,
00099     /* realize                  */      XtInheritRealize,
00100     /* actions                  */      NULL,
00101     /* num_actions              */      0,
00102     /* resources                */      resources,
00103     /* num_resources            */      XtNumber(resources),
00104     /* xrm_class                */      NULLQUARK,
00105     /* compress_motion          */      TRUE,
00106     /* compress_exposure        */      XtExposeCompressMultiple |
00107                                         XtExposeGraphicsExposeMerged,
00108     /* compress_enterleave      */      TRUE,
00109     /* visible_interest         */      FALSE,
00110     /* destroy                  */      Destroy,
00111     /* resize                   */      SetPoints,
00112     /* expose                   */      Redisplay,
00113     /* set_values               */      SetValues,
00114     /* set_values_hook          */      NULL,
00115     /* set_values_almost        */      NULL,
00116     /* get_values_hook          */      NULL,
00117     /* accept_focus             */      NULL,
00118     /* version                  */      XtVersion,
00119     /* callback_private         */      NULL,
00120     /* tm_table                 */      NULL,
00121     /* query_geometry           */      XtInheritQueryGeometry,
00122     /* display_accelerator      */      XtInheritDisplayAccelerator,
00123     /* extension                */      NULL
00124     },
00125     { /* Simple class fields */
00126     /* change_sensitive         */      XtInheritChangeSensitive
00127     },
00128     { /* ThreeD fields */
00129     /* shadowdraw               */      XtInheritXaw3dShadowDraw
00130     },
00131     { /* Stripchart fields */
00132     /* ignore                   */      0
00133     }
00134 };
00135 
00136 WidgetClass stripChartWidgetClass = (WidgetClass) &stripChartClassRec;
00137 
00138 /****************************************************************
00139  *
00140  * Private Procedures
00141  *
00142  ****************************************************************/
00143 
00144 static void draw_it();
00145 
00146 /*      Function Name: CreateGC
00147  *      Description: Creates the GC's
00148  *      Arguments: w - the strip chart widget.
00149  *                 which - which GC's to create.
00150  *      Returns: none
00151  */
00152 
00153 static void
00154 CreateGC(w, which)
00155 StripChartWidget w;
00156 unsigned int which;
00157 {
00158   XGCValues     myXGCV;
00159 
00160   if (which & FOREGROUND) {
00161     myXGCV.foreground = w->strip_chart.fgpixel;
00162     w->strip_chart.fgGC = XtGetGC((Widget) w, GCForeground, &myXGCV);
00163   }
00164 
00165   if (which & HIGHLIGHT) {
00166     myXGCV.foreground = w->strip_chart.hipixel;
00167     w->strip_chart.hiGC = XtGetGC((Widget) w, GCForeground, &myXGCV);
00168   }
00169 }
00170 
00171 /*      Function Name: DestroyGC
00172  *      Description: Destroys the GC's
00173  *      Arguments: w - the strip chart widget.
00174  *                 which - which GC's to destroy.
00175  *      Returns: none
00176  */
00177 
00178 static void
00179 DestroyGC(w, which)
00180 StripChartWidget w;
00181 unsigned int which;
00182 {
00183   if (which & FOREGROUND) 
00184     XtReleaseGC((Widget) w, w->strip_chart.fgGC);
00185 
00186   if (which & HIGHLIGHT) 
00187     XtReleaseGC((Widget) w, w->strip_chart.hiGC);
00188 }
00189 
00190 /* ARGSUSED */
00191 static void Initialize (greq, gnew, args, num_args)
00192     Widget greq, gnew;
00193     ArgList args;
00194     Cardinal *num_args;
00195 {
00196     StripChartWidget w = (StripChartWidget)gnew;
00197 
00198     if (w->strip_chart.update > 0)
00199         w->strip_chart.interval_id = 
00200             XtAppAddTimeOut( XtWidgetToApplicationContext(gnew),
00201                              (unsigned long) w->strip_chart.update * MS_PER_SEC, 
00202                              draw_it, (XtPointer) gnew);
00203     CreateGC(w, (unsigned int) ALL_GCS);
00204 
00205     w->strip_chart.scale = w->strip_chart.min_scale;
00206     w->strip_chart.interval = 0;
00207     w->strip_chart.max_value = 0.0;
00208     w->strip_chart.points = NULL;
00209     SetPoints((Widget)w);
00210 }
00211  
00212 static void Destroy (gw)
00213      Widget gw;
00214 {
00215      StripChartWidget w = (StripChartWidget)gw;
00216 
00217      if (w->strip_chart.update > 0)
00218          XtRemoveTimeOut (w->strip_chart.interval_id);
00219      if (w->strip_chart.points)
00220          XtFree((char *) w->strip_chart.points);
00221      DestroyGC(w, (unsigned int) ALL_GCS);
00222 }
00223 
00224 /*
00225  * NOTE: This function really needs to recieve graphics exposure 
00226  *       events, but since this is not easily supported until R4 I am
00227  *       going to hold off until then.
00228  */
00229 
00230 /* ARGSUSED */
00231 static void Redisplay(gw, event, region)
00232      Widget gw;
00233      XEvent *event;
00234      Region region;
00235 {
00236 
00237     StripChartWidget w = (StripChartWidget)gw;
00238     StripChartWidgetClass swclass = (StripChartWidgetClass) XtClass (gw);
00239     Dimension x, width, s = w->threeD.shadow_width;
00240 
00241     (*swclass->threeD_class.shadowdraw) (gw, event, region, FALSE);
00242 
00243     if (event->type == GraphicsExpose) {
00244         x = event->xgraphicsexpose.x;
00245         width = event->xgraphicsexpose.width;
00246     } else {
00247         x = event->xexpose.x;
00248         width = event->xexpose.width;
00249     }
00250     if (x > s) x -= s; /* respect shadow width, but don't become negative */
00251     else x = 0;
00252     if (x + width > w->core.width - 2 * s) /* ditto for right boundary */
00253         width = w->core.width - 2 * s - x;
00254 
00255     (void) repaint_window (gw, x, width);
00256 }
00257 
00258 /* ARGSUSED */
00259 static void 
00260 draw_it(client_data, id)
00261 XtPointer client_data;
00262 XtIntervalId *id;               /* unused */
00263 {
00264    StripChartWidget w = (StripChartWidget)client_data;
00265    StripChartWidgetClass swclass = (StripChartWidgetClass) XtClass ((Widget) w);
00266    Dimension s = w->threeD.shadow_width;
00267    double value;
00268    
00269    if (w->strip_chart.update > 0)
00270        w->strip_chart.interval_id =
00271        XtAppAddTimeOut(XtWidgetToApplicationContext( (Widget) w),
00272                        (unsigned long) w->strip_chart.update * MS_PER_SEC,
00273                        draw_it, client_data);
00274 
00275    if (w->strip_chart.interval >= (int)( w->core.width - 2 * s))
00276        MoveChart( (StripChartWidget) w, TRUE);
00277 
00278    /* Get the value, stash the point and draw corresponding line. */
00279 
00280    if (w->strip_chart.get_value == NULL)
00281        return;
00282 
00283    XtCallCallbacks( (Widget)w, XtNgetValue, (XtPointer)&value );
00284 
00285    /* 
00286     * Keep w->strip_chart.max_value up to date, and if this data 
00287     * point is off the graph, change the scale to make it fit. 
00288     */
00289    
00290    if (value > w->strip_chart.max_value) {
00291        w->strip_chart.max_value = value;
00292        if (XtIsRealized((Widget)w) && 
00293            w->strip_chart.max_value > w->strip_chart.scale) {
00294            XClearWindow(XtDisplay ((Widget) w), XtWindow ((Widget) w));
00295            w->strip_chart.interval = repaint_window((Widget)w, 0, (int) w->core.width - 2 * s);
00296            (*swclass->threeD_class.shadowdraw) ((Widget) w, 
00297                                                 (XEvent *)0, (Region)0, 
00298                                                 FALSE);
00299        }
00300    }
00301 
00302    w->strip_chart.valuedata[w->strip_chart.interval] = value;
00303    if (XtIsRealized((Widget)w)) {
00304        int y = (int) (( w->core.height - 2 * s)
00305                       - (int)(( w->core.height - 2 * s) * value) / w->strip_chart.scale);
00306 
00307         XFillRectangle(XtDisplay((Widget) w), XtWindow((Widget) w), w->strip_chart.fgGC,
00308                        w->strip_chart.interval + s, 
00309                        y + s, (unsigned int) 1, 
00310                        (w->core.height - 2 * s) - y);
00311        /*
00312         * Fill in the graph lines we just painted over.
00313         */
00314 
00315        if (w->strip_chart.points != NULL) {
00316            w->strip_chart.points[0].x = w->strip_chart.interval + s;
00317            XDrawPoints(XtDisplay(w), XtWindow(w), w->strip_chart.hiGC,
00318                        w->strip_chart.points, w->strip_chart.scale,
00319                        CoordModePrevious);
00320        }
00321 
00322        XFlush(XtDisplay(w));                /* Flush output buffers */
00323    }
00324    w->strip_chart.interval++;               /* Next point */
00325 } /* draw_it */
00326 
00327 /* Blts data according to current size, then redraws the stripChart window.
00328  * Next represents the number of valid points in data.  Returns the (possibly)
00329  * adjusted value of next.  If next is 0, this routine draws an empty window
00330  * (scale - 1 lines for graph).  If next is less than the current window width,
00331  * the returned value is identical to the initial value of next and data is
00332  * unchanged.  Otherwise keeps half a window's worth of data.  If data is
00333  * changed, then w->strip_chart.max_value is updated to reflect the
00334  * largest data point.
00335  */
00336 
00337 static int 
00338 repaint_window(gw, left, width)
00339 Widget gw;
00340 int left, width;
00341 {
00342     StripChartWidget w = (StripChartWidget) gw;
00343     Dimension s = w->threeD.shadow_width;
00344     StripChartWidgetClass swclass = (StripChartWidgetClass) XtClass ((Widget) w);
00345     int i, j;
00346     int next = w->strip_chart.interval;
00347     int scale = w->strip_chart.scale;
00348     int scalewidth = 0;
00349 
00350     /* Compute the minimum scale required to graph the data, but don't go
00351        lower than min_scale. */
00352     if (w->strip_chart.interval != 0 || scale <= (int)w->strip_chart.max_value)
00353       scale = ((int) (w->strip_chart.max_value)) + 1;
00354     if (scale < w->strip_chart.min_scale)
00355       scale = w->strip_chart.min_scale;
00356 
00357     if (scale != w->strip_chart.scale) {
00358       w->strip_chart.scale = scale;
00359       left = 0;
00360       width = next;                             /* check this */
00361       scalewidth = w->core.width - 2 * s;
00362 
00363       SetPoints(gw);
00364 
00365       if (XtIsRealized (gw)) {
00366         XClearWindow (XtDisplay (gw), XtWindow (gw));
00367         (*swclass->threeD_class.shadowdraw) (gw, (XEvent *)0, (Region)0, FALSE);
00368       }
00369 
00370     }
00371 
00372     if (XtIsRealized(gw)) {
00373         Display *dpy = XtDisplay(gw);
00374         Window win = XtWindow(gw);
00375 
00376         width += left - 1;
00377         if (!scalewidth) scalewidth = width;
00378 
00379         if (next < (++width - s)) width = next + s;
00380 
00381         /* Draw data point lines. */
00382         for (i = left; i < width; i++) {
00383             int y = (int) (( w->core.height - 2 * s) -
00384                            (int)(( w->core.height - 2 * s) * w->strip_chart.valuedata[i]) / 
00385                            w->strip_chart.scale);
00386 
00387             XFillRectangle(dpy, win, w->strip_chart.fgGC, 
00388                            i + s, y + s, (unsigned int) 1,
00389                            (unsigned int) (w->core.height - 2 * s - y ));
00390         }
00391 
00392         /* Draw graph reference lines */
00393         for (i = 1; i < w->strip_chart.scale; i++) {
00394             j = i * ((w->core.height - 2 * s) / w->strip_chart.scale);
00395             XDrawLine(dpy, win, w->strip_chart.hiGC, 
00396                 left + s, j + s, scalewidth + s, j + s);
00397         }
00398     }
00399     return(next);
00400 }
00401 
00402 /*      Function Name: MoveChart
00403  *      Description: moves the chart over when it would run off the end.
00404  *      Arguments: w - the load widget.
00405  *                 blit - blit the bits? (TRUE/FALSE).
00406  *      Returns: none.
00407  */
00408 
00409 static void
00410 MoveChart(w, blit)
00411 StripChartWidget w;
00412 Boolean blit;
00413 {
00414     Dimension s = w->threeD.shadow_width;
00415     double old_max;
00416     int left, i, j;
00417     int next = w->strip_chart.interval;
00418 
00419     if (!XtIsRealized((Widget) w)) return;
00420 
00421     if (w->strip_chart.jump_val < 0) w->strip_chart.jump_val = DEFAULT_JUMP;
00422     if (w->strip_chart.jump_val == DEFAULT_JUMP)
00423         j = ( w->core.width - 2 * s) / 2; /* Half the window width. */
00424     else {
00425         j = ( w->core.width - 2 * s) - w->strip_chart.jump_val;
00426         if (j < 0) j = 0;
00427     }
00428 
00429     (void) memmove((char *)(w->strip_chart.valuedata), 
00430                    (char *)(w->strip_chart.valuedata + next - j),
00431                    j * sizeof(double));
00432     next = w->strip_chart.interval = j;
00433         
00434     /*
00435      * Since we just lost some data, recompute the 
00436      * w->strip_chart.max_value. 
00437      */
00438 
00439     old_max = w->strip_chart.max_value;
00440     w->strip_chart.max_value = 0.0;
00441     for (i = 0; i < next; i++) {
00442       if (w->strip_chart.valuedata[i] > w->strip_chart.max_value) 
00443         w->strip_chart.max_value = w->strip_chart.valuedata[i];
00444     }
00445 
00446     if (!blit) return;          /* we are done... */
00447 
00448     if ( ((int) old_max) != ( (int) w->strip_chart.max_value) ) {
00449       XClearWindow(XtDisplay(w), XtWindow(w));
00450       repaint_window((Widget)w, 0, w->core.width - 2 * s);
00451       return;
00452     }
00453 
00454     XCopyArea(XtDisplay((Widget)w), XtWindow((Widget)w), XtWindow((Widget)w),
00455               w->strip_chart.hiGC, 
00456               (int) ((w->strip_chart.jump_val == DEFAULT_JUMP) ?
00457                      (j + s) : (w->strip_chart.jump_val + s)), s,
00458               (unsigned int) j, (unsigned int) ( w->core.height - 2 * s),
00459               s, s);
00460 
00461     XClearArea(XtDisplay((Widget)w), XtWindow((Widget)w), 
00462                (int) j + s, s, 
00463                (unsigned int) ((w->strip_chart.jump_val == DEFAULT_JUMP) ?
00464                                j : w->strip_chart.jump_val),
00465                (unsigned int) ( w->core.height - 2 * s),
00466                FALSE);
00467 
00468     /* Draw graph reference lines */
00469     left = j;
00470     for (i = 1; i < w->strip_chart.scale; i++) {
00471         j = i * ((w->core.height - 2 * s) / w->strip_chart.scale);
00472         XDrawLine(XtDisplay((Widget) w), XtWindow( (Widget) w),
00473             w->strip_chart.hiGC, 
00474             left, j + s, ((int)w->core.width - s - 1), j + s);
00475     }
00476     return;
00477 }
00478 
00479 /* ARGSUSED */
00480 static Boolean SetValues (current, request, new, args, num_args)
00481     Widget current, request, new;
00482     ArgList args;
00483     Cardinal *num_args;
00484 {
00485     StripChartWidget old = (StripChartWidget)current;
00486     StripChartWidget w = (StripChartWidget)new;
00487     Boolean ret_val = FALSE;
00488     unsigned int new_gc = NO_GCS;
00489 
00490     if (w->strip_chart.update != old->strip_chart.update) {
00491         if (old->strip_chart.update > 0)
00492             XtRemoveTimeOut (old->strip_chart.interval_id);
00493         if (w->strip_chart.update > 0)
00494             w->strip_chart.interval_id =
00495                 XtAppAddTimeOut(XtWidgetToApplicationContext(new),
00496                                 (unsigned long) w->strip_chart.update * MS_PER_SEC,
00497                                 draw_it, (XtPointer)w);
00498     }
00499 
00500     if ( w->strip_chart.min_scale > (int) ((w->strip_chart.max_value) + 1) )
00501       ret_val = TRUE;
00502      
00503     if ( w->strip_chart.fgpixel != old->strip_chart.fgpixel ) {
00504       new_gc |= FOREGROUND;
00505       ret_val = True;
00506     }
00507     
00508     if ( w->strip_chart.hipixel != old->strip_chart.hipixel ) {
00509       new_gc |= HIGHLIGHT;
00510       ret_val = True;
00511     }
00512     
00513     DestroyGC(old, new_gc);
00514     CreateGC(w, new_gc);
00515 
00516     return( ret_val );
00517 }
00518 
00519 /*      Function Name: SetPoints
00520  *      Description: Sets up the polypoint that will be used to draw in
00521  *                   the graph lines.
00522  *      Arguments: w - the StripChart widget.
00523  *      Returns: none.
00524  */
00525 
00526 #define HEIGHT ( (unsigned int) w->core.height)
00527 
00528 static void
00529 SetPoints(widget)
00530 Widget widget;
00531 {
00532     StripChartWidget w = (StripChartWidget) widget;
00533     Dimension s = w->threeD.shadow_width;
00534     XPoint * points;
00535     Cardinal size;
00536     int i;
00537 
00538     if (w->strip_chart.scale <= 1) { /* no scale lines. */
00539         XtFree ((char *) w->strip_chart.points);
00540         w->strip_chart.points = NULL;
00541         return;
00542     }
00543     
00544     size = sizeof(XPoint) * (w->strip_chart.scale - 1);
00545 
00546     points = (XPoint *) XtRealloc( (XtPointer) w->strip_chart.points, size);
00547     w->strip_chart.points = points;
00548 
00549     /* Draw graph reference lines into clip mask */
00550 
00551     for (i = 1; i < w->strip_chart.scale; i++) {
00552         points[i - 1].x = 0;
00553         points[i - 1].y = ( short)(((double)w->core.height - 2.0 * (double) s) / (double) w->strip_chart.scale );
00554     }
00555     points[0].y += (short)s;
00556 }

Generated on Sun Mar 4 15:03:55 2007 for Scilab [trunk] by  doxygen 1.5.1