rebuild geeqie
[oi-userland.git] / components / x11 / libXaw4 / src / Xaw3_1StripChart.c
blobd49cfc027dad76377e308e3b73a94b382600c63d
1 #ifndef lint
2 static char Xrcsid[] = "$XConsortium: StripChart.c,v 1.14 90/02/08 13:49:39 jim Exp $";
3 #endif
5 /***********************************************************
6 Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts,
7 and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
9 All Rights Reserved
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
25 SOFTWARE.
27 ******************************************************************/
29 #include <stdio.h>
30 #include <X11/IntrinsicP.h>
31 #include <X11/StringDefs.h>
32 #include <./Xaw3_1XawInit.h>
33 #include <./Xaw3_1StripCharP.h>
35 #ifdef SYSV
36 #ifndef bcopy
37 #define bcopy(a,b,c) memmove(b,a,c)
38 #endif /*bcopy*/
39 #else
40 extern void bcopy();
41 #endif /*SYSV*/
43 #define MS_PER_SEC 1000
45 /* Private Data */
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},
68 #undef offset
70 static void Initialize(), Destroy(), Redisplay(), MoveChart(), SetPoints();
71 static Boolean SetValues();
72 static int repaint_window();
74 StripChartClassRec stripChartClassRec = {
75 { /* core fields */
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,
85 /* actions */ NULL,
86 /* num_actions */ 0,
87 /* resources */ resources,
88 /* num_resources */ XtNumber(resources),
89 /* xrm_class */ NULL,
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,
105 /* tm_table */ NULL,
106 /* query_geometry */ XtInheritQueryGeometry,
107 /* display_accelerator */ XtInheritDisplayAccelerator,
108 /* extension */ NULL
110 { /* Simple class fields */
111 /* change_sensitive */ XtInheritChangeSensitive
115 WidgetClass stripChartWidgetClass = (WidgetClass) &stripChartClassRec;
117 /****************************************************************
119 * Private Procedures
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.
129 * Returns: none
132 static void
133 CreateGC(w, which)
134 StripChartWidget w;
135 unsigned int which;
137 XGCValues myXGCV;
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.
154 * Returns: none
157 static void
158 DestroyGC(w, which)
159 StripChartWidget w;
160 unsigned int which;
162 if (which & FOREGROUND)
163 XtReleaseGC((Widget) w, w->strip_chart.fgGC);
165 if (which & HIGHLIGHT)
166 XtReleaseGC((Widget) w, w->strip_chart.hiGC);
169 /* ARGSUSED */
170 static void Initialize (greq, gnew)
171 Widget 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,
180 (caddr_t) gnew);
181 else
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;
190 SetPoints(w);
193 static void Destroy (gw)
194 Widget 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.
210 /* ARGSUSED */
211 static void Redisplay(w, event, region)
212 Widget w;
213 XEvent *event;
214 Region region;
216 if (event->type == GraphicsExpose)
217 (void) repaint_window ((StripChartWidget)w, event->xgraphicsexpose.x,
218 event->xgraphicsexpose.width);
219 else
220 (void) repaint_window ((StripChartWidget)w, event->xexpose.x,
221 event->xexpose.width);
224 /* ARGSUSED */
225 static void
226 draw_it(client_data, id)
227 caddr_t client_data;
228 XtIntervalId id; /* unused */
230 StripChartWidget w = (StripChartWidget)client_data;
231 double value;
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)
245 return;
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,
278 CoordModePrevious);
281 XFlush(XtDisplay(w)); /* Flush output buffers */
283 w->strip_chart.interval++; /* Next point */
284 } /* draw_it */
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.
296 static int
297 repaint_window(w, left, width)
298 StripChartWidget w;
299 int left, width;
301 register int i, j;
302 register int next = w->strip_chart.interval;
303 int scale = w->strip_chart.scale;
304 int scalewidth = 0;
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;
315 left = 0;
316 width = next;
317 scalewidth = w->core.width;
319 SetPoints(w);
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);
330 width += left - 1;
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);
351 return(next);
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).
358 * Returns: none.
361 static void
362 MoveChart(w, blit)
363 StripChartWidget w;
364 Boolean blit;
366 double old_max;
367 int left, i, j;
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. */
374 else {
375 j = w->core.width - w->strip_chart.jump_val;
376 if (j < 0) j = 0;
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);
400 return;
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,
406 0, 0);
408 XClearArea(XtDisplay((Widget)w), XtWindow((Widget)w),
409 (int) j, 0,
410 (unsigned int) w->core.width - j, (unsigned int)w->core.height,
411 FALSE);
413 /* Draw graph reference lines */
414 left = j;
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);
420 return;
423 /* ARGSUSED */
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) )
441 ret_val = TRUE;
443 if ( w->strip_chart.fgpixel != old->strip_chart.fgpixel )
444 new_gc |= FOREGROUND;
446 if ( w->strip_chart.hipixel != old->strip_chart.hipixel )
447 new_gc |= HIGHLIGHT;
449 DestroyGC(old, new_gc);
450 CreateGC(w, new_gc);
452 return( ret_val );
455 /* Function Name: SetPoints
456 * Description: Sets up the polypoint that will be used to draw in
457 * the graph lines.
458 * Arguments: w - the StripChart widget.
459 * Returns: none.
462 #define HEIGHT ( (unsigned int) w->core.height)
464 static void
465 SetPoints(w)
466 StripChartWidget w;
468 XPoint * points;
469 Cardinal size;
470 int i;
472 if (w->strip_chart.scale <= 1) { /* no scale lines. */
473 XtFree ((char *) w->strip_chart.points);
474 w->strip_chart.points = NULL;
475 return;
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++) {
486 points[i - 1].x = 0;
487 points[i - 1].y = HEIGHT / w->strip_chart.scale;