1 /***********************************************************
3 Copyright 1987, 1988, 1994, 1998 The Open Group
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
26 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
30 Permission to use, copy, modify, and distribute this software and its
31 documentation for any purpose and without fee is hereby granted,
32 provided that the above copyright notice appear in all copies and that
33 both that copyright notice and this permission notice appear in
34 supporting documentation, and that the name of Digital not be
35 used in advertising or publicity pertaining to distribution of the
36 software without specific, written prior permission.
38 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
46 ******************************************************************/
52 #include <X11/IntrinsicP.h>
53 #include <X11/StringDefs.h>
54 #include <X11/Xfuncs.h>
55 #include <X11/Xaw/StripCharP.h>
56 #include <X11/Xaw/XawInit.h>
59 #define MS_PER_SEC 1000
64 static void XawStripChartInitialize(Widget, Widget, ArgList, Cardinal*);
65 static void XawStripChartDestroy(Widget);
66 static void XawStripChartRedisplay(Widget, XEvent*, Region);
67 static void XawStripChartResize(Widget);
68 static Boolean XawStripChartSetValues(Widget, Widget, Widget,
74 static void CreateGC(StripChartWidget, unsigned int);
75 static void DestroyGC(StripChartWidget, unsigned int);
76 static void draw_it(XtPointer, XtIntervalId*);
77 static void MoveChart(StripChartWidget, Bool);
78 static int repaint_window(StripChartWidget, int, int);
83 #define offset(field) XtOffsetOf(StripChartRec, field)
84 static XtResource resources[] = {
109 offset(strip_chart.update),
118 offset(strip_chart.min_scale),
127 offset(strip_chart.fgpixel),
136 offset(strip_chart.hipixel),
145 offset(strip_chart.get_value),
154 offset(strip_chart.jump_val),
156 (XtPointer)DEFAULT_JUMP
161 StripChartClassRec stripChartClassRec = {
164 (WidgetClass)&simpleClassRec, /* superclass */
165 "StripChart", /* class_name */
166 sizeof(StripChartRec), /* widget_size */
167 XawInitializeWidgetSet, /* class_initialize */
168 NULL, /* class_part_initialize */
169 False, /* class_inited */
170 XawStripChartInitialize, /* initialize */
171 NULL, /* initialize_hook */
172 XtInheritRealize, /* realize */
175 resources, /* resources */
176 XtNumber(resources), /* num_resources */
177 NULLQUARK, /* xrm_class */
178 True, /* compress_motion */
179 XtExposeCompressMultiple /* compress_exposure */
180 | XtExposeGraphicsExposeMerged,
181 True, /* compress_enterleave */
182 False, /* visible_interest */
183 XawStripChartDestroy, /* destroy */
184 XawStripChartResize, /* resize */
185 XawStripChartRedisplay, /* expose */
186 XawStripChartSetValues, /* set_values */
187 NULL, /* set_values_hook */
188 NULL, /* set_values_almost */
189 NULL, /* get_values_hook */
190 NULL, /* accept_focus */
191 XtVersion, /* version */
192 NULL, /* callback_private */
194 XtInheritQueryGeometry, /* query_geometry */
195 XtInheritDisplayAccelerator, /* display_accelerator */
196 NULL, /* extension */
200 XtInheritChangeSensitive, /* change_sensitive */
204 WidgetClass stripChartWidgetClass = (WidgetClass)&stripChartClassRec;
214 * w - strip chart widget
215 * which - GC's to create
221 CreateGC(StripChartWidget w, unsigned int which)
225 if (which & FOREGROUND) {
226 myXGCV.foreground = w->strip_chart.fgpixel;
227 w->strip_chart.fgGC = XtGetGC((Widget)w, GCForeground, &myXGCV);
230 if (which & HIGHLIGHT) {
231 myXGCV.foreground = w->strip_chart.hipixel;
232 w->strip_chart.hiGC = XtGetGC((Widget)w, GCForeground, &myXGCV);
241 * w - strip chart widget
242 * which - which GC's to destroy
248 DestroyGC(StripChartWidget w, unsigned int which)
250 if (which & FOREGROUND)
251 XtReleaseGC((Widget)w, w->strip_chart.fgGC);
253 if (which & HIGHLIGHT)
254 XtReleaseGC((Widget)w, w->strip_chart.hiGC);
259 XawStripChartInitialize(Widget greq, Widget gnew,
260 ArgList args, Cardinal *num_args)
262 StripChartWidget w = (StripChartWidget)gnew;
264 if (w->strip_chart.update > 0)
265 w->strip_chart.interval_id =
266 XtAppAddTimeOut(XtWidgetToApplicationContext(gnew),
267 w->strip_chart.update * MS_PER_SEC,
268 draw_it, (XtPointer)gnew);
269 CreateGC(w, ALL_GCS);
271 w->strip_chart.scale = w->strip_chart.min_scale;
272 w->strip_chart.interval = 0;
273 w->strip_chart.max_value = 0.0;
274 w->strip_chart.points = NULL;
275 XawStripChartResize(gnew);
279 XawStripChartDestroy(Widget gw)
281 StripChartWidget w = (StripChartWidget)gw;
283 if (w->strip_chart.update > 0)
284 XtRemoveTimeOut(w->strip_chart.interval_id);
285 if (w->strip_chart.points)
286 XtFree((char *)w->strip_chart.points);
287 DestroyGC(w, ALL_GCS);
291 * NOTE: This function really needs to recieve graphics exposure
292 * events, but since this is not easily supported until R4 I am
293 * going to hold off until then.
297 XawStripChartRedisplay(Widget w, XEvent *event, Region region)
299 if (event->type == GraphicsExpose)
300 (void)repaint_window((StripChartWidget)w, event->xgraphicsexpose.x,
301 event->xgraphicsexpose.width);
303 (void)repaint_window((StripChartWidget)w, event->xexpose.x,
304 event->xexpose.width);
309 draw_it(XtPointer client_data, XtIntervalId *id)
311 StripChartWidget w = (StripChartWidget)client_data;
314 if (w->strip_chart.update > 0)
315 w->strip_chart.interval_id =
316 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)w),
317 w->strip_chart.update * MS_PER_SEC,draw_it,
320 if (w->strip_chart.interval >= XtWidth(w))
321 MoveChart((StripChartWidget)w, True);
323 /* Get the value, stash the point and draw corresponding line */
324 if (w->strip_chart.get_value == NULL)
327 XtCallCallbacks((Widget)w, XtNgetValue, (XtPointer)&value);
330 * Keep w->strip_chart.max_value up to date, and if this data
331 * point is off the graph, change the scale to make it fit
333 if (value > w->strip_chart.max_value) {
334 w->strip_chart.max_value = value;
335 if (XtIsRealized((Widget)w) &&
336 w->strip_chart.max_value > w->strip_chart.scale) {
337 XClearWindow(XtDisplay(w), XtWindow(w));
338 w->strip_chart.interval = repaint_window(w, 0, XtWidth(w));
342 w->strip_chart.valuedata[w->strip_chart.interval] = value;
343 if (XtIsRealized((Widget)w)) {
344 int y = (int)(XtHeight(w) - XtHeight(w) * value
345 / w->strip_chart.scale);
347 XFillRectangle(XtDisplay(w), XtWindow(w), w->strip_chart.fgGC,
348 w->strip_chart.interval, y,
352 * Fill in the graph lines we just painted over
354 if (w->strip_chart.points != NULL) {
355 w->strip_chart.points[0].x = w->strip_chart.interval;
356 XDrawPoints(XtDisplay(w), XtWindow(w), w->strip_chart.hiGC,
357 w->strip_chart.points, w->strip_chart.scale - 1,
361 XFlush(XtDisplay(w)); /* Flush output buffers */
363 w->strip_chart.interval++; /* Next point */
366 /* Blts data according to current size, then redraws the stripChart window
367 * Next represents the number of valid points in data. Returns the (possibly)
368 * adjusted value of next. If next is 0, this routine draws an empty window
369 * (scale - 1 lines for graph). If next is less than the current window width,
370 * the returned value is identical to the initial value of next and data is
371 * unchanged. Otherwise keeps half a window's worth of data. If data is
372 * changed, then w->strip_chart.max_value is updated to reflect the
376 repaint_window(StripChartWidget w, int left, int width)
379 int next = w->strip_chart.interval;
380 int scale = w->strip_chart.scale;
383 /* Compute the minimum scale required to graph the data, but don't go
384 lower than min_scale */
385 if (w->strip_chart.interval != 0 || scale <= w->strip_chart.max_value)
386 scale = w->strip_chart.max_value + 1;
387 if (scale < w->strip_chart.min_scale)
388 scale = w->strip_chart.min_scale;
390 if (scale != w->strip_chart.scale) {
391 w->strip_chart.scale = scale;
394 scalewidth = XtWidth(w);
396 XawStripChartResize((Widget)w);
398 if (XtIsRealized((Widget)w))
399 XClearWindow(XtDisplay(w), XtWindow(w));
402 if (XtIsRealized((Widget)w)) {
403 Display *dpy = XtDisplay(w);
404 Window win = XtWindow(w);
413 /* Draw data point lines */
414 for (i = left; i < width; i++) {
415 int y = XtHeight(w) - (XtHeight(w) * w->strip_chart.valuedata[i])
416 / w->strip_chart.scale;
418 XFillRectangle(dpy, win, w->strip_chart.fgGC,
419 i, y, 1, XtHeight(w) - y);
422 /* Draw graph reference lines */
423 for (i = 1; i < w->strip_chart.scale; i++) {
424 j = i * ((int)XtHeight(w) / w->strip_chart.scale);
425 XDrawLine(dpy, win, w->strip_chart.hiGC, left, j, scalewidth, j);
437 * blit - blit the bits?
440 * Moves the chart over when it would run off the end.
443 MoveChart(StripChartWidget w, Bool blit)
447 int next = w->strip_chart.interval;
449 if (!XtIsRealized((Widget)w))
452 if (w->strip_chart.jump_val < 0)
453 w->strip_chart.jump_val = DEFAULT_JUMP;
454 if (w->strip_chart.jump_val == DEFAULT_JUMP)
457 j = (int)XtWidth(w) - w->strip_chart.jump_val;
462 (void)memmove((char *)w->strip_chart.valuedata,
463 (char *)(w->strip_chart.valuedata + next - j),
465 next = w->strip_chart.interval = j;
468 * Since we just lost some data, recompute the
469 * w->strip_chart.max_value
471 old_max = w->strip_chart.max_value;
472 w->strip_chart.max_value = 0.0;
473 for (i = 0; i < next; i++) {
474 if (w->strip_chart.valuedata[i] > w->strip_chart.max_value)
475 w->strip_chart.max_value = w->strip_chart.valuedata[i];
481 if (old_max != w->strip_chart.max_value) {
482 XClearWindow(XtDisplay(w), XtWindow(w));
483 repaint_window(w, 0, XtWidth(w));
487 XCopyArea(XtDisplay((Widget)w), XtWindow((Widget)w), XtWindow((Widget)w),
488 w->strip_chart.hiGC, (int)XtWidth(w) - j, 0, j, XtHeight(w), 0, 0);
490 XClearArea(XtDisplay((Widget)w), XtWindow((Widget)w),
491 j, 0, XtWidth(w) - j, XtHeight(w), False);
493 /* Draw graph reference lines */
495 for (i = 1; i < w->strip_chart.scale; i++) {
496 j = i * (XtHeight(w) / w->strip_chart.scale);
497 XDrawLine(XtDisplay((Widget)w), XtWindow((Widget)w),
498 w->strip_chart.hiGC, left, j, XtWidth(w), j);
504 XawStripChartSetValues(Widget current, Widget request, Widget cnew,
505 ArgList args, Cardinal *num_args)
507 StripChartWidget old = (StripChartWidget)current;
508 StripChartWidget w = (StripChartWidget)cnew;
509 Bool ret_val = False;
510 unsigned int new_gc = NO_GCS;
512 if (w->strip_chart.update != old->strip_chart.update) {
513 if (old->strip_chart.update > 0)
514 XtRemoveTimeOut(old->strip_chart.interval_id);
515 if (w->strip_chart.update > 0)
516 w->strip_chart.interval_id =
517 XtAppAddTimeOut(XtWidgetToApplicationContext(cnew),
518 w->strip_chart.update * MS_PER_SEC,
519 draw_it, (XtPointer)w);
522 if (w->strip_chart.min_scale > w->strip_chart.max_value + 1)
525 if (w->strip_chart.fgpixel != old->strip_chart.fgpixel) {
526 new_gc |= FOREGROUND;
530 if (w->strip_chart.hipixel != old->strip_chart.hipixel) {
535 DestroyGC(old, new_gc);
543 * XawStripChartResize
546 * w - StripChart widget
549 * Sets up the polypoint that will be used to draw in the graph lines.
552 XawStripChartResize(Widget widget)
554 StripChartWidget w = (StripChartWidget)widget;
559 if (w->strip_chart.scale <= 1) {
560 XtFree((char *)w->strip_chart.points);
561 w->strip_chart.points = NULL;
565 size = sizeof(XPoint) * (w->strip_chart.scale - 1);
567 points = (XPoint *)XtRealloc((XtPointer)w->strip_chart.points, size);
568 w->strip_chart.points = points;
570 /* Draw graph reference lines into clip mask */
572 for (i = 1; i < w->strip_chart.scale; i++) {
574 points[i - 1].y = XtHeight(w) / w->strip_chart.scale;