1
/* $XConsortium: StripChart.c,v 1.20 91/05/24 17:20:42 converse Exp $ */
3
/***********************************************************
4
Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
5
and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
9
Permission to use, copy, modify, and distribute this software and its
10
documentation for any purpose and without fee is hereby granted,
11
provided that the above copyright notice appear in all copies and that
12
both that copyright notice and this permission notice appear in
13
supporting documentation, and that the names of Digital or MIT not be
14
used in advertising or publicity pertaining to distribution of the
15
software without specific, written prior permission.
17
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
18
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
19
DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
20
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
25
******************************************************************/
28
#include <X11/IntrinsicP.h>
29
#include <X11/StringDefs.h>
30
#include <X11/Xaw/XawInit.h>
31
#include <X11/Xaw/StripCharP.h>
32
#include <X11/Xfuncs.h>
34
#define MS_PER_SEC 1000
38
#define offset(field) XtOffsetOf(StripChartRec, field)
40
static XtResource resources[] = {
41
{XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
42
offset(core.width), XtRImmediate, (XtPointer) 120},
43
{XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
44
offset(core.height), XtRImmediate, (XtPointer) 120},
45
{XtNupdate, XtCInterval, XtRInt, sizeof(int),
46
offset(strip_chart.update), XtRImmediate, (XtPointer) 10},
47
{XtNminScale, XtCScale, XtRInt, sizeof(int),
48
offset(strip_chart.min_scale), XtRImmediate, (XtPointer) 1},
49
{XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
50
offset(strip_chart.fgpixel), XtRString, XtDefaultForeground},
51
{XtNhighlight, XtCForeground, XtRPixel, sizeof(Pixel),
52
offset(strip_chart.hipixel), XtRString, XtDefaultForeground},
53
{XtNgetValue, XtCCallback, XtRCallback, sizeof(XtPointer),
54
offset(strip_chart.get_value), XtRImmediate, (XtPointer) NULL},
55
{XtNjumpScroll, XtCJumpScroll, XtRInt, sizeof(int),
56
offset(strip_chart.jump_val), XtRImmediate, (XtPointer) DEFAULT_JUMP},
61
static void Initialize(), Destroy(), Redisplay(), MoveChart(), SetPoints();
62
static Boolean SetValues();
63
static int repaint_window();
65
StripChartClassRec stripChartClassRec = {
67
/* superclass */ (WidgetClass) &simpleClassRec,
68
/* class_name */ "StripChart",
69
/* size */ sizeof(StripChartRec),
70
/* class_initialize */ XawInitializeWidgetSet,
71
/* class_part_initialize */ NULL,
72
/* class_inited */ FALSE,
73
/* initialize */ Initialize,
74
/* initialize_hook */ NULL,
75
/* realize */ XtInheritRealize,
78
/* resources */ resources,
79
/* num_resources */ XtNumber(resources),
80
/* xrm_class */ NULLQUARK,
81
/* compress_motion */ TRUE,
82
/* compress_exposure */ XtExposeCompressMultiple |
83
XtExposeGraphicsExposeMerged,
84
/* compress_enterleave */ TRUE,
85
/* visible_interest */ FALSE,
86
/* destroy */ Destroy,
87
/* resize */ SetPoints,
88
/* expose */ Redisplay,
89
/* set_values */ SetValues,
90
/* set_values_hook */ NULL,
91
/* set_values_almost */ NULL,
92
/* get_values_hook */ NULL,
93
/* accept_focus */ NULL,
94
/* version */ XtVersion,
95
/* callback_private */ NULL,
97
/* query_geometry */ XtInheritQueryGeometry,
98
/* display_accelerator */ XtInheritDisplayAccelerator,
101
{ /* Simple class fields */
102
/* change_sensitive */ XtInheritChangeSensitive
106
WidgetClass stripChartWidgetClass = (WidgetClass) &stripChartClassRec;
108
/****************************************************************
112
****************************************************************/
114
static void draw_it();
116
/* Function Name: CreateGC
117
* Description: Creates the GC's
118
* Arguments: w - the strip chart widget.
119
* which - which GC's to create.
130
if (which & FOREGROUND) {
131
myXGCV.foreground = w->strip_chart.fgpixel;
132
w->strip_chart.fgGC = XtGetGC((Widget) w, GCForeground, &myXGCV);
135
if (which & HIGHLIGHT) {
136
myXGCV.foreground = w->strip_chart.hipixel;
137
w->strip_chart.hiGC = XtGetGC((Widget) w, GCForeground, &myXGCV);
141
/* Function Name: DestroyGC
142
* Description: Destroys the GC's
143
* Arguments: w - the strip chart widget.
144
* which - which GC's to destroy.
153
if (which & FOREGROUND)
154
XtReleaseGC((Widget) w, w->strip_chart.fgGC);
156
if (which & HIGHLIGHT)
157
XtReleaseGC((Widget) w, w->strip_chart.hiGC);
161
static void Initialize (greq, gnew)
164
StripChartWidget w = (StripChartWidget)gnew;
166
if (w->strip_chart.update > 0)
167
w->strip_chart.interval_id = XtAppAddTimeOut(
168
XtWidgetToApplicationContext(gnew),
169
w->strip_chart.update * MS_PER_SEC,
170
draw_it, (XtPointer) gnew);
171
CreateGC(w, (unsigned int) ALL_GCS);
173
w->strip_chart.scale = w->strip_chart.min_scale;
174
w->strip_chart.interval = 0;
175
w->strip_chart.max_value = 0.0;
176
w->strip_chart.points = NULL;
180
static void Destroy (gw)
183
StripChartWidget w = (StripChartWidget)gw;
185
if (w->strip_chart.update > 0)
186
XtRemoveTimeOut (w->strip_chart.interval_id);
187
if (w->strip_chart.points)
188
XtFree((char *) w->strip_chart.points);
189
DestroyGC(w, (unsigned int) ALL_GCS);
193
* NOTE: This function really needs to recieve graphics exposure
194
* events, but since this is not easily supported until R4 I am
195
* going to hold off until then.
199
static void Redisplay(w, event, region)
204
if (event->type == GraphicsExpose)
205
(void) repaint_window ((StripChartWidget)w, event->xgraphicsexpose.x,
206
event->xgraphicsexpose.width);
208
(void) repaint_window ((StripChartWidget)w, event->xexpose.x,
209
event->xexpose.width);
214
draw_it(client_data, id)
215
XtPointer client_data;
216
XtIntervalId *id; /* unused */
218
StripChartWidget w = (StripChartWidget)client_data;
221
if (w->strip_chart.update > 0)
222
w->strip_chart.interval_id =
223
XtAppAddTimeOut(XtWidgetToApplicationContext( (Widget) w),
224
w->strip_chart.update * MS_PER_SEC,draw_it,client_data);
226
if (w->strip_chart.interval >= (int)w->core.width)
227
MoveChart( (StripChartWidget) w, TRUE);
229
/* Get the value, stash the point and draw corresponding line. */
231
if (w->strip_chart.get_value == NULL)
234
XtCallCallbacks( (Widget)w, XtNgetValue, (XtPointer)&value );
237
* Keep w->strip_chart.max_value up to date, and if this data
238
* point is off the graph, change the scale to make it fit.
241
if (value > w->strip_chart.max_value) {
242
w->strip_chart.max_value = value;
243
if (w->strip_chart.max_value > w->strip_chart.scale) {
244
XClearWindow( XtDisplay (w), XtWindow (w));
245
w->strip_chart.interval = repaint_window(w, 0, (int) w->core.width);
249
w->strip_chart.valuedata[w->strip_chart.interval] = value;
250
if (XtIsRealized((Widget)w)) {
251
int y = (int) (w->core.height
252
- (int)(w->core.height * value) / w->strip_chart.scale);
254
XFillRectangle(XtDisplay(w), XtWindow(w), w->strip_chart.fgGC,
255
w->strip_chart.interval, y,
256
(unsigned int) 1, w->core.height - y);
258
* Fill in the graph lines we just painted over.
261
if (w->strip_chart.points != NULL) {
262
w->strip_chart.points[0].x = w->strip_chart.interval;
263
XDrawPoints(XtDisplay(w), XtWindow(w), w->strip_chart.hiGC,
264
w->strip_chart.points, w->strip_chart.scale - 1,
268
XFlush(XtDisplay(w)); /* Flush output buffers */
270
w->strip_chart.interval++; /* Next point */
273
/* Blts data according to current size, then redraws the stripChart window.
274
* Next represents the number of valid points in data. Returns the (possibly)
275
* adjusted value of next. If next is 0, this routine draws an empty window
276
* (scale - 1 lines for graph). If next is less than the current window width,
277
* the returned value is identical to the initial value of next and data is
278
* unchanged. Otherwise keeps half a window's worth of data. If data is
279
* changed, then w->strip_chart.max_value is updated to reflect the
280
* largest data point.
284
repaint_window(w, left, width)
289
register int next = w->strip_chart.interval;
290
int scale = w->strip_chart.scale;
293
/* Compute the minimum scale required to graph the data, but don't go
294
lower than min_scale. */
295
if (w->strip_chart.interval != 0 || scale <= (int)w->strip_chart.max_value)
296
scale = ((int) (w->strip_chart.max_value)) + 1;
297
if (scale < w->strip_chart.min_scale)
298
scale = w->strip_chart.min_scale;
300
if (scale != w->strip_chart.scale) {
301
w->strip_chart.scale = scale;
304
scalewidth = w->core.width;
308
if (XtIsRealized ((Widget) w))
309
XClearWindow (XtDisplay (w), XtWindow (w));
313
if (XtIsRealized((Widget)w)) {
314
Display *dpy = XtDisplay(w);
315
Window win = XtWindow(w);
318
if (!scalewidth) scalewidth = width;
320
if (next < ++width) width = next;
322
/* Draw data point lines. */
323
for (i = left; i < width; i++) {
324
int y = (int) (w->core.height -
325
(int)(w->core.height * w->strip_chart.valuedata[i]) /
326
w->strip_chart.scale);
328
XFillRectangle(dpy, win, w->strip_chart.fgGC,
329
i, y, (unsigned int) 1,
330
(unsigned int) (w->core.height - y));
333
/* Draw graph reference lines */
334
for (i = 1; i < w->strip_chart.scale; i++) {
335
j = i * ((int)w->core.height / w->strip_chart.scale);
336
XDrawLine(dpy, win, w->strip_chart.hiGC, left, j, scalewidth, j);
342
/* Function Name: MoveChart
343
* Description: moves the chart over when it would run off the end.
344
* Arguments: w - the load widget.
345
* blit - blit the bits? (TRUE/FALSE).
356
register int next = w->strip_chart.interval;
358
if (!XtIsRealized((Widget) w)) return;
360
if (w->strip_chart.jump_val == DEFAULT_JUMP)
361
j = w->core.width >> 1; /* Half the window width. */
363
j = w->core.width - w->strip_chart.jump_val;
367
bcopy((char *)(w->strip_chart.valuedata + next - j),
368
(char *)(w->strip_chart.valuedata), j * sizeof(double));
369
next = w->strip_chart.interval = j;
372
* Since we just lost some data, recompute the
373
* w->strip_chart.max_value.
376
old_max = w->strip_chart.max_value;
377
w->strip_chart.max_value = 0.0;
378
for (i = 0; i < next; i++) {
379
if (w->strip_chart.valuedata[i] > w->strip_chart.max_value)
380
w->strip_chart.max_value = w->strip_chart.valuedata[i];
383
if (!blit) return; /* we are done... */
385
if ( ((int) old_max) != ( (int) w->strip_chart.max_value) ) {
386
XClearWindow(XtDisplay(w), XtWindow(w));
387
repaint_window(w, 0, (int) w->core.width);
391
XCopyArea(XtDisplay((Widget)w), XtWindow((Widget)w), XtWindow((Widget)w),
392
w->strip_chart.hiGC, (int) w->core.width - j, 0,
393
(unsigned int) j, (unsigned int) w->core.height,
396
XClearArea(XtDisplay((Widget)w), XtWindow((Widget)w),
398
(unsigned int) w->core.width - j, (unsigned int)w->core.height,
401
/* Draw graph reference lines */
403
for (i = 1; i < w->strip_chart.scale; i++) {
404
j = i * ((int)w->core.height / w->strip_chart.scale);
405
XDrawLine(XtDisplay((Widget) w), XtWindow( (Widget) w),
406
w->strip_chart.hiGC, left, j, (int)w->core.width, j);
412
static Boolean SetValues (current, request, new)
413
Widget current, request, new;
415
StripChartWidget old = (StripChartWidget)current;
416
StripChartWidget w = (StripChartWidget)new;
417
Boolean ret_val = FALSE;
418
unsigned int new_gc = NO_GCS;
420
if (w->strip_chart.update != old->strip_chart.update) {
421
if (old->strip_chart.update > 0)
422
XtRemoveTimeOut (old->strip_chart.interval_id);
423
if (w->strip_chart.update > 0)
424
w->strip_chart.interval_id =
425
XtAppAddTimeOut(XtWidgetToApplicationContext(new),
426
w->strip_chart.update * MS_PER_SEC,
427
draw_it, (XtPointer)w);
430
if ( w->strip_chart.min_scale > (int) ((w->strip_chart.max_value) + 1) )
433
if ( w->strip_chart.fgpixel != old->strip_chart.fgpixel ) {
434
new_gc |= FOREGROUND;
438
if ( w->strip_chart.hipixel != old->strip_chart.hipixel ) {
443
DestroyGC(old, new_gc);
449
/* Function Name: SetPoints
450
* Description: Sets up the polypoint that will be used to draw in
452
* Arguments: w - the StripChart widget.
456
#define HEIGHT ( (unsigned int) w->core.height)
466
if (w->strip_chart.scale <= 1) { /* no scale lines. */
467
XtFree ((char *) w->strip_chart.points);
468
w->strip_chart.points = NULL;
472
size = sizeof(XPoint) * (w->strip_chart.scale - 1);
474
points = (XPoint *) XtRealloc( (XtPointer) w->strip_chart.points, size);
475
w->strip_chart.points = points;
477
/* Draw graph reference lines into clip mask */
479
for (i = 1; i < w->strip_chart.scale; i++) {
481
points[i - 1].y = HEIGHT / w->strip_chart.scale;