2 static char Xrcsid
[] = "$XConsortium: StripChart.c,v 1.14 90/02/08 13:49:39 jim Exp $";
5 /***********************************************************
6 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
7 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
11 Permission to use, copy, modify, and distribute this software and its
12 documentation for any purpose and without fee is hereby granted,
13 provided that the above copyright notice appear in all copies and that
14 both that copyright notice and this permission notice appear in
15 supporting documentation, and that the names of Digital or MIT not be
16 used in advertising or publicity pertaining to distribution of the
17 software without specific, written prior permission.
19 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
20 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
21 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
22 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
23 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
24 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
27 ******************************************************************/
30 #include <X11/IntrinsicP.h>
31 #include <X11/StringDefs.h>
32 #include <./Xaw3_1XawInit.h>
33 #include <./Xaw3_1StripCharP.h>
37 #define bcopy(a,b,c) memmove(b,a,c)
43 #define MS_PER_SEC 1000
47 #define offset(field) XtOffset(StripChartWidget,field)
49 static XtResource resources
[] = {
50 {XtNwidth
, XtCWidth
, XtRDimension
, sizeof(Dimension
),
51 offset(core
.width
), XtRImmediate
, (caddr_t
) 120},
52 {XtNheight
, XtCHeight
, XtRDimension
, sizeof(Dimension
),
53 offset(core
.height
), XtRImmediate
, (caddr_t
) 120},
54 {XtNupdate
, XtCInterval
, XtRInt
, sizeof(int),
55 offset(strip_chart
.update
), XtRImmediate
, (caddr_t
) 10},
56 {XtNminScale
, XtCScale
, XtRInt
, sizeof(int),
57 offset(strip_chart
.min_scale
), XtRImmediate
, (caddr_t
) 1},
58 {XtNforeground
, XtCForeground
, XtRPixel
, sizeof(Pixel
),
59 offset(strip_chart
.fgpixel
), XtRString
, XtDefaultForeground
},
60 {XtNhighlight
, XtCForeground
, XtRPixel
, sizeof(Pixel
),
61 offset(strip_chart
.hipixel
), XtRString
, XtDefaultForeground
},
62 {XtNgetValue
, XtCCallback
, XtRCallback
, sizeof(caddr_t
),
63 offset(strip_chart
.get_value
), XtRImmediate
, (caddr_t
) NULL
},
64 {XtNjumpScroll
, XtCJumpScroll
, XtRInt
, sizeof(int),
65 offset(strip_chart
.jump_val
), XtRImmediate
, (caddr_t
) DEFAULT_JUMP
},
70 static void Initialize(), Destroy(), Redisplay(), MoveChart(), SetPoints();
71 static Boolean
SetValues();
72 static int repaint_window();
74 StripChartClassRec stripChartClassRec
= {
76 /* superclass */ (WidgetClass
) &simpleClassRec
,
77 /* class_name */ "StripChart",
78 /* size */ sizeof(StripChartRec
),
79 /* class_initialize */ XawInitializeWidgetSet
,
80 /* class_part_initialize */ NULL
,
81 /* class_inited */ FALSE
,
82 /* initialize */ Initialize
,
83 /* initialize_hook */ NULL
,
84 /* realize */ XtInheritRealize
,
87 /* resources */ resources
,
88 /* num_resources */ XtNumber(resources
),
90 /* compress_motion */ TRUE
,
91 /* compress_exposure */ XtExposeCompressMultiple
|
92 XtExposeGraphicsExposeMerged
,
93 /* compress_enterleave */ TRUE
,
94 /* visible_interest */ FALSE
,
95 /* destroy */ Destroy
,
96 /* resize */ SetPoints
,
97 /* expose */ Redisplay
,
98 /* set_values */ SetValues
,
99 /* set_values_hook */ NULL
,
100 /* set_values_almost */ NULL
,
101 /* get_values_hook */ NULL
,
102 /* accept_focus */ NULL
,
103 /* version */ XtVersion
,
104 /* callback_private */ NULL
,
106 /* query_geometry */ XtInheritQueryGeometry
,
107 /* display_accelerator */ XtInheritDisplayAccelerator
,
110 { /* Simple class fields */
111 /* change_sensitive */ XtInheritChangeSensitive
115 WidgetClass stripChartWidgetClass
= (WidgetClass
) &stripChartClassRec
;
117 /****************************************************************
121 ****************************************************************/
123 static void draw_it();
125 /* Function Name: CreateGC
126 * Description: Creates the GC's
127 * Arguments: w - the strip chart widget.
128 * which - which GC's to create.
139 if (which
& FOREGROUND
) {
140 myXGCV
.foreground
= w
->strip_chart
.fgpixel
;
141 w
->strip_chart
.fgGC
= XtGetGC((Widget
) w
, GCForeground
, &myXGCV
);
144 if (which
& HIGHLIGHT
) {
145 myXGCV
.foreground
= w
->strip_chart
.hipixel
;
146 w
->strip_chart
.hiGC
= XtGetGC((Widget
) w
, GCForeground
, &myXGCV
);
150 /* Function Name: DestroyGC
151 * Description: Destroys the GC's
152 * Arguments: w - the strip chart widget.
153 * which - which GC's to destroy.
162 if (which
& FOREGROUND
)
163 XtReleaseGC((Widget
) w
, w
->strip_chart
.fgGC
);
165 if (which
& HIGHLIGHT
)
166 XtReleaseGC((Widget
) w
, w
->strip_chart
.hiGC
);
170 static void Initialize (greq
, gnew
)
173 StripChartWidget w
= (StripChartWidget
)gnew
;
175 if (w
->strip_chart
.update
> 0)
176 w
->strip_chart
.interval_id
= XtAppAddTimeOut(
177 XtWidgetToApplicationContext(gnew
),
178 w
->strip_chart
.update
* MS_PER_SEC
,
179 (XtTimerCallbackProc
)draw_it
,
182 w
->strip_chart
.interval_id
= NULL
;
184 CreateGC(w
, (unsigned int) ALL_GCS
);
186 w
->strip_chart
.scale
= w
->strip_chart
.min_scale
;
187 w
->strip_chart
.interval
= 0;
188 w
->strip_chart
.max_value
= 0.0;
189 w
->strip_chart
.points
= NULL
;
193 static void Destroy (gw
)
196 StripChartWidget w
= (StripChartWidget
)gw
;
198 if (w
->strip_chart
.interval_id
!= NULL
)
199 XtRemoveTimeOut (w
->strip_chart
.interval_id
);
201 DestroyGC(w
, (unsigned int) ALL_GCS
);
205 * NOTE: This function really needs to recieve graphics exposure
206 * events, but since this is not easily supported until R4 I am
207 * going to hold off until then.
211 static void Redisplay(w
, event
, region
)
216 if (event
->type
== GraphicsExpose
)
217 (void) repaint_window ((StripChartWidget
)w
, event
->xgraphicsexpose
.x
,
218 event
->xgraphicsexpose
.width
);
220 (void) repaint_window ((StripChartWidget
)w
, event
->xexpose
.x
,
221 event
->xexpose
.width
);
226 draw_it(client_data
, id
)
228 XtIntervalId id
; /* unused */
230 StripChartWidget w
= (StripChartWidget
)client_data
;
233 if (w
->strip_chart
.update
> 0)
234 w
->strip_chart
.interval_id
=
235 XtAppAddTimeOut(XtWidgetToApplicationContext( (Widget
) w
),
236 w
->strip_chart
.update
* MS_PER_SEC
,
237 (XtTimerCallbackProc
)draw_it
, client_data
);
239 if (w
->strip_chart
.interval
>= w
->core
.width
)
240 MoveChart( (StripChartWidget
) w
, TRUE
);
242 /* Get the value, stash the point and draw corresponding line. */
244 if (w
->strip_chart
.get_value
== NULL
)
247 XtCallCallbacks( (Widget
)w
, XtNgetValue
, (caddr_t
)&value
);
250 * Keep w->strip_chart.max_value up to date, and if this data
251 * point is off the graph, change the scale to make it fit.
254 if (value
> w
->strip_chart
.max_value
) {
255 w
->strip_chart
.max_value
= value
;
256 if (w
->strip_chart
.max_value
> w
->strip_chart
.scale
) {
257 XClearWindow( XtDisplay (w
), XtWindow (w
));
258 w
->strip_chart
.interval
= repaint_window(w
, 0, (int) w
->core
.width
);
262 w
->strip_chart
.valuedata
[w
->strip_chart
.interval
] = value
;
263 if (XtIsRealized((Widget
)w
)) {
264 int y
= (int) (w
->core
.height
- (w
->core
.height
* value
) /
265 w
->strip_chart
.scale
);
267 XFillRectangle(XtDisplay(w
), XtWindow(w
), w
->strip_chart
.fgGC
,
268 w
->strip_chart
.interval
, y
,
269 (unsigned int) 1, w
->core
.height
- y
);
271 * Fill in the graph lines we just painted over.
274 if (w
->strip_chart
.points
!= NULL
) {
275 w
->strip_chart
.points
[0].x
= w
->strip_chart
.interval
;
276 XDrawPoints(XtDisplay(w
), XtWindow(w
), w
->strip_chart
.hiGC
,
277 w
->strip_chart
.points
, w
->strip_chart
.scale
- 1,
281 XFlush(XtDisplay(w
)); /* Flush output buffers */
283 w
->strip_chart
.interval
++; /* Next point */
286 /* Blts data according to current size, then redraws the stripChart window.
287 * Next represents the number of valid points in data. Returns the (possibly)
288 * adjusted value of next. If next is 0, this routine draws an empty window
289 * (scale - 1 lines for graph). If next is less than the current window width,
290 * the returned value is identical to the initial value of next and data is
291 * unchanged. Otherwise keeps half a window's worth of data. If data is
292 * changed, then w->strip_chart.max_value is updated to reflect the
293 * largest data point.
297 repaint_window(w
, left
, width
)
302 register int next
= w
->strip_chart
.interval
;
303 int scale
= w
->strip_chart
.scale
;
306 /* Compute the minimum scale required to graph the data, but don't go
307 lower than min_scale. */
308 if (w
->strip_chart
.interval
!= 0 || scale
<= (int)w
->strip_chart
.max_value
)
309 scale
= ((int) (w
->strip_chart
.max_value
)) + 1;
310 if (scale
< w
->strip_chart
.min_scale
)
311 scale
= w
->strip_chart
.min_scale
;
313 if (scale
!= w
->strip_chart
.scale
) {
314 w
->strip_chart
.scale
= scale
;
317 scalewidth
= w
->core
.width
;
321 if (XtIsRealized ((Widget
) w
))
322 XClearWindow (XtDisplay (w
), XtWindow (w
));
326 if (XtIsRealized((Widget
)w
)) {
327 Display
*dpy
= XtDisplay(w
);
328 Window win
= XtWindow(w
);
331 if (!scalewidth
) scalewidth
= width
;
333 if (next
< ++width
) width
= next
;
335 /* Draw data point lines. */
336 for (i
= left
; i
< width
; i
++) {
337 int height
= (int) (w
->strip_chart
.valuedata
[i
] *
338 w
->core
.height
) / w
->strip_chart
.scale
;
340 XFillRectangle(dpy
, win
, w
->strip_chart
.fgGC
,
341 i
, ((int) w
->core
.height
) - height
,
342 (unsigned int) 1, (unsigned int) w
->core
.height
);
345 /* Draw graph reference lines */
346 for (i
= 1; i
< w
->strip_chart
.scale
; i
++) {
347 j
= i
* (w
->core
.height
/ w
->strip_chart
.scale
);
348 XDrawLine(dpy
, win
, w
->strip_chart
.hiGC
, left
, j
, scalewidth
, j
);
354 /* Function Name: MoveChart
355 * Description: moves the chart over when it would run off the end.
356 * Arguments: w - the load widget.
357 * blit - blit the bits? (TRUE/FALSE).
368 register int next
= w
->strip_chart
.interval
;
370 if (!XtIsRealized((Widget
) w
)) return;
372 if (w
->strip_chart
.jump_val
== DEFAULT_JUMP
)
373 j
= w
->core
.width
>> 1; /* Half the window width. */
375 j
= w
->core
.width
- w
->strip_chart
.jump_val
;
379 bcopy((char *)(w
->strip_chart
.valuedata
+ next
- j
),
380 (char *)(w
->strip_chart
.valuedata
), j
* sizeof(double));
381 next
= w
->strip_chart
.interval
= j
;
384 * Since we just lost some data, recompute the
385 * w->strip_chart.max_value.
388 old_max
= w
->strip_chart
.max_value
;
389 w
->strip_chart
.max_value
= 0.0;
390 for (i
= 0; i
< next
; i
++) {
391 if (w
->strip_chart
.valuedata
[i
] > w
->strip_chart
.max_value
)
392 w
->strip_chart
.max_value
= w
->strip_chart
.valuedata
[i
];
395 if (!blit
) return; /* we are done... */
397 if ( ((int) old_max
) != ( (int) w
->strip_chart
.max_value
) ) {
398 XClearWindow(XtDisplay(w
), XtWindow(w
));
399 repaint_window(w
, 0, (int) w
->core
.width
);
403 XCopyArea(XtDisplay((Widget
)w
), XtWindow((Widget
)w
), XtWindow((Widget
)w
),
404 w
->strip_chart
.hiGC
, (int) w
->core
.width
- j
, 0,
405 (unsigned int) j
, (unsigned int) w
->core
.height
,
408 XClearArea(XtDisplay((Widget
)w
), XtWindow((Widget
)w
),
410 (unsigned int) w
->core
.width
- j
, (unsigned int)w
->core
.height
,
413 /* Draw graph reference lines */
415 for (i
= 1; i
< w
->strip_chart
.scale
; i
++) {
416 j
= i
* (w
->core
.height
/ w
->strip_chart
.scale
);
417 XDrawLine(XtDisplay((Widget
) w
), XtWindow( (Widget
) w
),
418 w
->strip_chart
.hiGC
, left
, j
, (int)w
->core
.width
, j
);
424 static Boolean
SetValues (current
, request
, new)
425 Widget current
, request
, new;
427 StripChartWidget old
= (StripChartWidget
)current
;
428 StripChartWidget w
= (StripChartWidget
)new;
429 Boolean ret_val
= FALSE
;
430 unsigned int new_gc
= NO_GCS
;
432 if (w
->strip_chart
.update
!= old
->strip_chart
.update
) {
433 XtRemoveTimeOut (old
->strip_chart
.interval_id
);
434 w
->strip_chart
.interval_id
=
435 XtAppAddTimeOut(XtWidgetToApplicationContext(new),
436 w
->strip_chart
.update
* MS_PER_SEC
,
437 (XtTimerCallbackProc
)draw_it
, (caddr_t
)w
);
440 if ( w
->strip_chart
.min_scale
> (int) ((w
->strip_chart
.max_value
) + 1) )
443 if ( w
->strip_chart
.fgpixel
!= old
->strip_chart
.fgpixel
)
444 new_gc
|= FOREGROUND
;
446 if ( w
->strip_chart
.hipixel
!= old
->strip_chart
.hipixel
)
449 DestroyGC(old
, new_gc
);
455 /* Function Name: SetPoints
456 * Description: Sets up the polypoint that will be used to draw in
458 * Arguments: w - the StripChart widget.
462 #define HEIGHT ( (unsigned int) w->core.height)
472 if (w
->strip_chart
.scale
<= 1) { /* no scale lines. */
473 XtFree ((char *) w
->strip_chart
.points
);
474 w
->strip_chart
.points
= NULL
;
478 size
= sizeof(XPoint
) * (w
->strip_chart
.scale
- 1);
480 points
= (XPoint
*) XtRealloc( (XtPointer
) w
->strip_chart
.points
, size
);
481 w
->strip_chart
.points
= points
;
483 /* Draw graph reference lines into clip mask */
485 for (i
= 1; i
< w
->strip_chart
.scale
; i
++) {
487 points
[i
- 1].y
= HEIGHT
/ w
->strip_chart
.scale
;