comparison lwlib/xlwgauge.c @ 398:74fd4e045ea6 r21-2-29

Import from CVS: tag r21-2-29
author cvs
date Mon, 13 Aug 2007 11:13:30 +0200
parents
children a86b2b5e0111
comparison
equal deleted inserted replaced
397:f4aeb21a5bad 398:74fd4e045ea6
1 /* Gauge Widget for XEmacs.
2 Copyright (C) 1999 Edward A. Falk
3
4 This file is part of XEmacs.
5
6 XEmacs is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 XEmacs is distributed in the hope that it will be useful, but WITHOUT
12 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with XEmacs; see the file COPYING. If not, write to
18 the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 Boston, MA 02111-1307, USA. */
20
21 /* Synched up with: Gauge.c 1.2 */
22
23 /*
24 * Gauge.c - Gauge widget
25 *
26 * Author: Edward A. Falk
27 * falk@falconer.vip.best.com
28 *
29 * Date: July 9, 1997
30 *
31 * Note: for fun and demonstration purposes, I have added selection
32 * capabilities to this widget. If you select the widget, you create
33 * a primary selection containing the current value of the widget in
34 * both integer and string form. If you copy into the widget, the
35 * primary selection is converted to an integer value and the gauge is
36 * set to that value.
37 */
38
39 /* TODO: display time instead of value
40 */
41
42 #define DEF_LEN 50 /* default width (or height for vertical gauge) */
43 #define MIN_LEN 10 /* minimum reasonable width (height) */
44 #define TIC_LEN 6 /* length of tic marks */
45 #define GA_WID 3 /* width of gauge */
46 #define MS_PER_SEC 1000
47
48 #include <config.h>
49 #include <stdlib.h>
50 #include <stdio.h>
51 #include <ctype.h>
52 #include <X11/IntrinsicP.h>
53 #include <X11/Xatom.h>
54 #include <X11/StringDefs.h>
55 #include ATHENA_INCLUDE(XawInit.h)
56 #include "xlwgaugeP.h"
57 #include "../src/xmu.h"
58 #ifdef HAVE_XMU
59 #include <X11/Xmu/Atoms.h>
60 #include <X11/Xmu/Drawing.h>
61 #include <X11/Xmu/StdSel.h>
62 #endif
63
64
65 /****************************************************************
66 *
67 * Gauge resources
68 *
69 ****************************************************************/
70
71
72 static char defaultTranslations[] =
73 "<Btn1Up>: select()\n\
74 <Key>F1: select(CLIPBOARD)\n\
75 <Btn2Up>: paste()\n\
76 <Key>F2: paste(CLIPBOARD)" ;
77
78
79
80 #define offset(field) XtOffsetOf(GaugeRec, field)
81 static XtResource resources[] = {
82 {XtNvalue, XtCValue, XtRInt, sizeof(int),
83 offset(gauge.value), XtRImmediate, (XtPointer)0},
84 {XtNminValue, XtCMinValue, XtRInt, sizeof(int),
85 offset(gauge.v0), XtRImmediate, (XtPointer)0},
86 {XtNmaxValue, XtCMaxValue, XtRInt, sizeof(int),
87 offset(gauge.v1), XtRImmediate, (XtPointer)100},
88 {XtNntics, XtCNTics, XtRInt, sizeof(int),
89 offset(gauge.ntics), XtRImmediate, (XtPointer) 0},
90 {XtNnlabels, XtCNLabels, XtRInt, sizeof(int),
91 offset(gauge.nlabels), XtRImmediate, (XtPointer) 0},
92 {XtNlabels, XtCLabels, XtRStringArray, sizeof(String *),
93 offset(gauge.labels), XtRStringArray, NULL},
94 {XtNautoScaleUp, XtCAutoScaleUp, XtRBoolean, sizeof(Boolean),
95 offset(gauge.autoScaleUp), XtRImmediate, FALSE},
96 {XtNautoScaleDown, XtCAutoScaleDown, XtRBoolean, sizeof(Boolean),
97 offset(gauge.autoScaleDown), XtRImmediate, FALSE},
98 {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
99 offset(gauge.orientation), XtRImmediate, (XtPointer)XtorientHorizontal},
100 {XtNupdate, XtCInterval, XtRInt, sizeof(int),
101 offset(gauge.update), XtRImmediate, (XtPointer)0},
102 {XtNgetValue, XtCCallback, XtRCallback, sizeof(XtPointer),
103 offset(gauge.getValue), XtRImmediate, (XtPointer)NULL},
104 };
105 #undef offset
106
107
108
109 /* member functions */
110
111 static void GaugeClassInit (void);
112 static void GaugeInit (Widget, Widget, ArgList, Cardinal *);
113 static void GaugeDestroy (Widget);
114 static void GaugeResize (Widget);
115 static void GaugeExpose (Widget, XEvent *, Region);
116 static Boolean GaugeSetValues (Widget, Widget, Widget, ArgList, Cardinal *);
117 static XtGeometryResult GaugeQueryGeometry (Widget, XtWidgetGeometry *,
118 XtWidgetGeometry *);
119
120 /* action procs */
121
122 static void GaugeSelect (Widget, XEvent *, String *, Cardinal *);
123 static void GaugePaste (Widget, XEvent *, String *, Cardinal *);
124
125 /* internal privates */
126
127 static void GaugeSize (GaugeWidget, Dimension *, Dimension *, Dimension);
128 static void MaxLabel (GaugeWidget, Dimension *, Dimension *,
129 Dimension *, Dimension *);
130 static void AutoScale (GaugeWidget);
131 static void EnableUpdate (GaugeWidget);
132 static void DisableUpdate (GaugeWidget);
133
134 static void GaugeGetValue (XtPointer, XtIntervalId *);
135 static void GaugeMercury (Display *, Window, GC, GaugeWidget, Cardinal, Cardinal);
136
137 static Boolean GaugeConvert (Widget, Atom *, Atom *, Atom *,
138 XtPointer *, u_long *, int *);
139 static void GaugeLoseSel (Widget, Atom *);
140 static void GaugeDoneSel (Widget, Atom *, Atom *);
141 static void GaugeGetSelCB (Widget, XtPointer, Atom *, Atom *,
142 XtPointer, u_long *, int *);
143
144 static GC Get_GC (GaugeWidget, Pixel);
145
146
147 static XtActionsRec actionsList[] =
148 {
149 {"select", GaugeSelect},
150 {"paste", GaugePaste},
151 } ;
152
153
154
155 /****************************************************************
156 *
157 * Full class record constant
158 *
159 ****************************************************************/
160
161 GaugeClassRec gaugeClassRec = {
162 {
163 /* core_class fields */
164 /* superclass */ (WidgetClass) &labelClassRec,
165 /* class_name */ "Gauge",
166 /* widget_size */ sizeof(GaugeRec),
167 /* class_initialize */ GaugeClassInit,
168 /* class_part_initialize */ NULL,
169 /* class_inited */ FALSE,
170 /* initialize */ GaugeInit,
171 /* initialize_hook */ NULL,
172 /* realize */ XtInheritRealize, /* TODO? */
173 /* actions */ actionsList,
174 /* num_actions */ XtNumber(actionsList),
175 /* resources */ resources,
176 /* num_resources */ XtNumber(resources),
177 /* xrm_class */ NULLQUARK,
178 /* compress_motion */ TRUE,
179 /* compress_exposure */ TRUE,
180 /* compress_enterleave */ TRUE,
181 /* visible_interest */ FALSE,
182 /* destroy */ GaugeDestroy,
183 /* resize */ GaugeResize,
184 /* expose */ GaugeExpose,
185 /* set_values */ GaugeSetValues,
186 /* set_values_hook */ NULL,
187 /* set_values_almost */ XtInheritSetValuesAlmost,
188 /* get_values_hook */ NULL,
189 /* accept_focus */ NULL,
190 /* version */ XtVersion,
191 /* callback_private */ NULL,
192 /* tm_table */ defaultTranslations,
193 /* query_geometry */ GaugeQueryGeometry,
194 /* display_accelerator */ XtInheritDisplayAccelerator,
195 /* extension */ NULL
196 },
197 /* Simple class fields initialization */
198 {
199 /* change_sensitive */ XtInheritChangeSensitive
200 },
201 #ifdef _ThreeDP_h
202 /* ThreeD class fields initialization */
203 {
204 XtInheritXaw3dShadowDraw /* shadowdraw */
205 },
206 #endif
207 /* Label class fields initialization */
208 {
209 /* ignore */ 0
210 },
211 /* Gauge class fields initialization */
212 {
213 /* extension */ NULL
214 },
215 };
216
217 WidgetClass gaugeWidgetClass = (WidgetClass)&gaugeClassRec;
218
219
220
221
222 /****************************************************************
223 *
224 * Member Procedures
225 *
226 ****************************************************************/
227
228 static void
229 GaugeClassInit (void)
230 {
231 XawInitializeWidgetSet();
232 #ifdef HAVE_XMU
233 XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation,
234 NULL, 0) ;
235 #endif
236 }
237
238
239
240 /* ARGSUSED */
241 static void
242 GaugeInit (Widget request,
243 Widget new,
244 ArgList args,
245 Cardinal *num_args)
246 {
247 GaugeWidget gw = (GaugeWidget) new;
248
249 if( gw->gauge.v0 == 0 && gw->gauge.v1 == 0 ) {
250 gw->gauge.autoScaleUp = gw->gauge.autoScaleDown = TRUE ;
251 AutoScale(gw) ;
252 }
253
254 /* If size not explicitly set, set it to our preferred size now. */
255
256 if( request->core.width == 0 || request->core.height == 0 )
257 {
258 Dimension w,h ;
259 GaugeSize(gw, &w,&h, DEF_LEN) ;
260 if( request->core.width == 0 )
261 new->core.width = w ;
262 if( request->core.height == 0 )
263 new->core.height = h ;
264 gw->core.widget_class->core_class.resize(new) ;
265 }
266
267 gw->gauge.selected = None ;
268 gw->gauge.selstr = NULL ;
269
270 if( gw->gauge.update > 0 )
271 EnableUpdate(gw) ;
272
273 gw->gauge.inverse_GC = Get_GC(gw, gw->core.background_pixel) ;
274 }
275
276 static void
277 GaugeDestroy (Widget w)
278 {
279 GaugeWidget gw = (GaugeWidget)w;
280
281 if( gw->gauge.selstr != NULL )
282 XtFree(gw->gauge.selstr) ;
283
284 if( gw->gauge.selected != None )
285 XtDisownSelection(w, gw->gauge.selected, CurrentTime) ;
286
287 XtReleaseGC(w, gw->gauge.inverse_GC) ;
288
289 if( gw->gauge.update > 0 )
290 DisableUpdate(gw) ;
291 }
292
293
294 /* React to size change from manager. Label widget will compute some
295 * internal stuff, but we need to override.
296 */
297
298 static void
299 GaugeResize (Widget w)
300 {
301 GaugeWidget gw = (GaugeWidget)w;
302 int size ; /* height (width) of gauge */
303 int vmargin ; /* vertical (horizontal) margin */
304 int hmargin ; /* horizontal (vertical) margin */
305
306 vmargin = gw->gauge.orientation == XtorientHorizontal ?
307 gw->label.internal_height : gw->label.internal_width ;
308 hmargin = gw->gauge.orientation == XtorientHorizontal ?
309 gw->label.internal_width : gw->label.internal_height ;
310
311 /* TODO: need to call parent resize proc? I don't think so since
312 * we're recomputing everything from scratch anyway.
313 */
314
315 /* find total height (width) of contents */
316
317 size = GA_WID+2 ; /* gauge itself + edges */
318
319 if( gw->gauge.ntics > 1 ) /* tic marks */
320 size += vmargin + TIC_LEN ;
321
322 if( gw->gauge.nlabels > 1 )
323 {
324 Dimension lwm, lw0, lw1 ; /* width of max, left, right labels */
325 Dimension lh ;
326
327 MaxLabel(gw,&lwm,&lh, &lw0,&lw1) ;
328
329 if( gw->gauge.orientation == XtorientHorizontal )
330 {
331 gw->gauge.margin0 = lw0 / 2 ;
332 gw->gauge.margin1 = lw1 / 2 ;
333 size += lh + vmargin ;
334 }
335 else
336 {
337 gw->gauge.margin0 =
338 gw->gauge.margin1 = lh / 2 ;
339 size += lwm + vmargin ;
340 }
341 }
342 else
343 gw->gauge.margin0 = gw->gauge.margin1 = 0 ;
344
345 gw->gauge.margin0 += hmargin ;
346 gw->gauge.margin1 += hmargin ;
347
348 /* Now distribute height (width) over components */
349
350 if( gw->gauge.orientation == XtorientHorizontal )
351 gw->gauge.gmargin = (gw->core.height-size)/2 ;
352 else
353 gw->gauge.gmargin = (gw->core.width-size)/2 ;
354
355 gw->gauge.tmargin = gw->gauge.gmargin + GA_WID+2 + vmargin ;
356 if( gw->gauge.ntics > 1 )
357 gw->gauge.lmargin = gw->gauge.tmargin + TIC_LEN + vmargin ;
358 else
359 gw->gauge.lmargin = gw->gauge.tmargin ;
360 }
361
362 /*
363 * Repaint the widget window
364 */
365
366 /* ARGSUSED */
367 static void
368 GaugeExpose (Widget w,
369 XEvent *event,
370 Region region)
371 {
372 GaugeWidget gw = (GaugeWidget) w;
373 register Display *dpy = XtDisplay(w) ;
374 register Window win = XtWindow(w) ;
375 GC gc; /* foreground, background */
376 GC gctop, gcbot ; /* dark, light shadows */
377
378 int len ; /* length (width or height) of widget */
379 int hgt ; /* height (width) of widget */
380 int e0,e1 ; /* ends of the gauge */
381 int x ;
382 int y ; /* vertical (horizontal) position */
383 int i ;
384 int v0 = gw->gauge.v0 ;
385 int v1 = gw->gauge.v1 ;
386 int value = gw->gauge.value ;
387
388 gc = XtIsSensitive(w) ? gw->label.normal_GC : gw->label.gray_GC ;
389
390
391 #ifdef _ThreeDP_h
392 gctop = gw->threeD.bot_shadow_GC ;
393 gcbot = gw->threeD.top_shadow_GC ;
394 #else
395 gctop = gcbot = gc ;
396 #endif
397
398 if( gw->gauge.orientation == XtorientHorizontal ) {
399 len = gw->core.width ;
400 hgt = gw->core.height ;
401 } else {
402 len = gw->core.height ;
403 hgt = gw->core.width ;
404 }
405
406 /* if the gauge is selected, signify by drawing the background
407 * in a constrasting color.
408 */
409
410 if( gw->gauge.selected )
411 {
412 XFillRectangle(dpy,win, gc, 0,0, w->core.width,w->core.height) ;
413 gc = gw->gauge.inverse_GC ;
414 }
415
416 e0 = gw->gauge.margin0 ; /* left (top) end */
417 e1 = len - gw->gauge.margin1 -1 ; /* right (bottom) end */
418
419 /* Draw the Gauge itself */
420
421 y = gw->gauge.gmargin ;
422
423 if( gw->gauge.orientation == XtorientHorizontal ) /* horizontal */
424 {
425 XDrawLine(dpy,win,gctop, e0+1,y, e1-1,y) ;
426 XDrawLine(dpy,win,gctop, e0,y+1, e0,y+GA_WID) ;
427 XDrawLine(dpy,win,gcbot, e0+1, y+GA_WID+1, e1-1, y+GA_WID+1) ;
428 XDrawLine(dpy,win,gcbot, e1,y+1, e1,y+GA_WID) ;
429 }
430 else /* vertical */
431 {
432 XDrawLine(dpy,win,gctop, y,e0+1, y,e1-1) ;
433 XDrawLine(dpy,win,gctop, y+1,e0, y+GA_WID,e0) ;
434 XDrawLine(dpy,win,gcbot, y+GA_WID+1,e0+1, y+GA_WID+1, e1-1) ;
435 XDrawLine(dpy,win,gcbot, y+1,e1, y+GA_WID,e1) ;
436 }
437
438
439 /* draw the mercury */
440
441 GaugeMercury(dpy, win, gc, gw, 0,value) ;
442
443
444 if( gw->gauge.ntics > 1 )
445 {
446 y = gw->gauge.tmargin ;
447 for(i=0; i<gw->gauge.ntics; ++i)
448 {
449 x = e0 + i*(e1-e0-1)/(gw->gauge.ntics-1) ;
450 if( gw->gauge.orientation == XtorientHorizontal ) {
451 XDrawLine(dpy,win,gcbot, x,y+1, x,y+TIC_LEN-2) ;
452 XDrawLine(dpy,win,gcbot, x,y, x+1,y) ;
453 XDrawLine(dpy,win,gctop, x+1,y+1, x+1,y+TIC_LEN-2) ;
454 XDrawLine(dpy,win,gctop, x,y+TIC_LEN-1, x+1,y+TIC_LEN-1) ;
455 }
456 else {
457 XDrawLine(dpy,win,gcbot, y+1,x, y+TIC_LEN-2,x) ;
458 XDrawLine(dpy,win,gcbot, y,x, y,x+1) ;
459 XDrawLine(dpy,win,gctop, y+1,x+1, y+TIC_LEN-2,x+1) ;
460 XDrawLine(dpy,win,gctop, y+TIC_LEN-1,x, y+TIC_LEN-1,x+1) ;
461 }
462 }
463 }
464
465 /* draw labels */
466 if( gw->gauge.nlabels > 1 )
467 {
468 char label[20], *s = label ;
469 int len, w,h =0 ;
470
471 if( gw->gauge.orientation == XtorientHorizontal )
472 y = gw->gauge.lmargin + gw->label.font->max_bounds.ascent - 1 ;
473 else {
474 y = gw->gauge.lmargin ;
475 h = gw->label.font->max_bounds.ascent / 2 ;
476 }
477
478 for(i=0; i<gw->gauge.nlabels; ++i)
479 {
480 if( gw->gauge.labels == NULL )
481 sprintf(label, "%d", v0+i*(v1 - v0)/(gw->gauge.nlabels - 1)) ;
482 else
483 s = gw->gauge.labels[i] ;
484 if( s != NULL ) {
485 x = e0 + i*(e1-e0-1)/(gw->gauge.nlabels-1) ;
486 len = strlen(s) ;
487 if( gw->gauge.orientation == XtorientHorizontal ) {
488 w = XTextWidth(gw->label.font, s, len) ;
489 XDrawString(dpy,win,gc, x-w/2,y, s,len) ;
490 }
491 else {
492 XDrawString(dpy,win,gc, y,x+h, s,len) ;
493 }
494 }
495 }
496 }
497 }
498
499
500 /*
501 * Set specified arguments into widget
502 */
503
504 static Boolean
505 GaugeSetValues (Widget old,
506 Widget request,
507 Widget new,
508 ArgList args,
509 Cardinal *num_args)
510 {
511 GaugeWidget oldgw = (GaugeWidget) old;
512 GaugeWidget gw = (GaugeWidget) new;
513 Boolean was_resized = False;
514
515 if( gw->gauge.selected != None ) {
516 XtDisownSelection(new, gw->gauge.selected, CurrentTime) ;
517 gw->gauge.selected = None ;
518 }
519
520 /* Changes to v0,v1,labels, ntics, nlabels require resize & redraw. */
521 /* Change to value requires redraw and possible resize if autoscale */
522
523 was_resized =
524 gw->gauge.v0 != oldgw->gauge.v0 ||
525 gw->gauge.v1 != oldgw->gauge.v1 ||
526 gw->gauge.ntics != oldgw->gauge.ntics ||
527 gw->gauge.nlabels != oldgw->gauge.nlabels ||
528 gw->gauge.labels != oldgw->gauge.labels ;
529
530 if( (gw->gauge.autoScaleUp && gw->gauge.value > gw->gauge.v1) ||
531 (gw->gauge.autoScaleDown && gw->gauge.value < gw->gauge.v1/3 ))
532 {
533 AutoScale(gw) ;
534 was_resized = TRUE ;
535 }
536
537 if( was_resized ) {
538 if( gw->label.resize )
539 GaugeSize(gw, &gw->core.width, &gw->core.height, DEF_LEN) ;
540 else
541 GaugeResize(new) ;
542 }
543
544 if( gw->gauge.update != oldgw->gauge.update )
545 {
546 if( gw->gauge.update > 0 )
547 EnableUpdate(gw) ;
548 else
549 DisableUpdate(gw) ;
550 }
551
552 if( gw->core.background_pixel != oldgw->core.background_pixel )
553 {
554 XtReleaseGC(new, gw->gauge.inverse_GC) ;
555 gw->gauge.inverse_GC = Get_GC(gw, gw->core.background_pixel) ;
556 }
557
558 return was_resized || gw->gauge.value != oldgw->gauge.value ||
559 XtIsSensitive(old) != XtIsSensitive(new);
560 }
561
562
563 static XtGeometryResult
564 GaugeQueryGeometry (Widget w,
565 XtWidgetGeometry *intended,
566 XtWidgetGeometry *preferred)
567 {
568 register GaugeWidget gw = (GaugeWidget)w;
569
570 if( intended->width == w->core.width &&
571 intended->height == w->core.height )
572 return XtGeometryNo ;
573
574 preferred->request_mode = CWWidth | CWHeight;
575 GaugeSize(gw, &preferred->width, &preferred->height, DEF_LEN) ;
576
577 if( (!(intended->request_mode & CWWidth) ||
578 intended->width >= preferred->width) &&
579 (!(intended->request_mode & CWHeight) ||
580 intended->height >= preferred->height) )
581 return XtGeometryYes;
582 else
583 return XtGeometryAlmost;
584 }
585
586
587
588
589 /****************************************************************
590 *
591 * Action Procedures
592 *
593 ****************************************************************/
594
595 static void
596 GaugeSelect (Widget w,
597 XEvent *event,
598 String *params,
599 Cardinal *num_params)
600 {
601 GaugeWidget gw = (GaugeWidget)w ;
602 Atom seln = XA_PRIMARY ;
603
604 if( gw->gauge.selected != None ) {
605 XtDisownSelection(w, gw->gauge.selected, CurrentTime) ;
606 gw->gauge.selected = None ;
607 }
608
609 if( *num_params > 0 ) {
610 seln = XInternAtom(XtDisplay(w), params[0], False) ;
611 printf("atom %s is %ld\n", params[0], seln) ;
612 }
613
614 if( ! XtOwnSelection(w, seln, event->xbutton.time, GaugeConvert,
615 GaugeLoseSel, GaugeDoneSel) )
616 {
617 /* in real code, this error message would be replaced by
618 * something more elegant, or at least deleted
619 */
620
621 fprintf(stderr, "Gauge failed to get selection, try again\n") ;
622 }
623 else
624 {
625 gw->gauge.selected = TRUE ;
626 gw->gauge.selstr = (String)XtMalloc(4*sizeof(int)) ;
627 sprintf(gw->gauge.selstr, "%d", gw->gauge.value) ;
628 GaugeExpose(w,0,0) ;
629 }
630 }
631
632
633 static Boolean
634 GaugeConvert (Widget w,
635 Atom *selection, /* usually XA_PRIMARY */
636 Atom *target, /* requested target */
637 Atom *type, /* returned type */
638 XtPointer *value, /* returned value */
639 u_long *length, /* returned length */
640 int *format) /* returned format */
641 {
642 GaugeWidget gw = (GaugeWidget)w ;
643 XSelectionRequestEvent *req ;
644
645 printf( "requesting selection %s:%s\n",
646 XGetAtomName(XtDisplay(w),*selection),
647 XGetAtomName(XtDisplay(w),*target));
648
649 #ifdef HAVE_XMU
650 if( *target == XA_TARGETS(XtDisplay(w)) )
651 {
652 Atom *rval, *stdTargets ;
653 u_long stdLength ;
654
655 /* XmuConvertStandardSelection can handle this. This function
656 * will return a list of standard targets. We prepend TEXT,
657 * STRING and INTEGER to the list and return it.
658 */
659
660 req = XtGetSelectionRequest(w, *selection, NULL) ;
661 XmuConvertStandardSelection(w, req->time, selection, target,
662 type, (XPointer*)&stdTargets, &stdLength, format) ;
663
664 *type = XA_ATOM ; /* TODO: needed? */
665 *length = stdLength + 3 ;
666 rval = (Atom *) XtMalloc(sizeof(Atom)*(stdLength+3)) ;
667 *value = (XtPointer) rval ;
668 *rval++ = XA_INTEGER ;
669 *rval++ = XA_STRING ;
670 *rval++ = XA_TEXT(XtDisplay(w)) ;
671 memcpy((char *)rval, (char *)stdTargets, stdLength*sizeof(Atom)) ;
672 XtFree((char*) stdTargets) ;
673 *format = 8*sizeof(Atom) ; /* TODO: needed? */
674 return True ;
675 }
676
677 else
678 #endif
679 if( *target == XA_INTEGER )
680 {
681 *type = XA_INTEGER ;
682 *length = 1 ;
683 *value = (XtPointer) &gw->gauge.value ;
684 *format = 8*sizeof(int) ;
685 return True ;
686 }
687
688 else if( *target == XA_STRING
689 #ifdef HAVE_XMU
690 ||
691 *target == XA_TEXT(XtDisplay(w))
692 #endif
693 )
694 {
695 *type = *target ;
696 *length = strlen(gw->gauge.selstr)*sizeof(char) ;
697 *value = (XtPointer) gw->gauge.selstr ;
698 *format = 8 ;
699 return True ;
700 }
701
702 else
703 {
704 /* anything else, we just give it to XmuConvertStandardSelection() */
705 #ifdef HAVE_XMU
706 req = XtGetSelectionRequest(w, *selection, NULL) ;
707 if( XmuConvertStandardSelection(w, req->time, selection, target,
708 type, (XPointer *) value, length, format) )
709 return True ;
710 else
711 #endif
712 {
713 printf(
714 "Gauge: requestor is requesting unsupported selection %s:%s\n",
715 XGetAtomName(XtDisplay(w),*selection),
716 XGetAtomName(XtDisplay(w),*target));
717 return False ;
718 }
719 }
720 }
721
722
723
724 static void
725 GaugeLoseSel (Widget w,
726 Atom *selection) /* usually XA_PRIMARY */
727 {
728 GaugeWidget gw = (GaugeWidget)w ;
729 Display *dpy = XtDisplay(w) ;
730 Window win = XtWindow(w) ;
731
732 if( gw->gauge.selstr != NULL ) {
733 XtFree(gw->gauge.selstr) ;
734 gw->gauge.selstr = NULL ;
735 }
736
737 gw->gauge.selected = False ;
738 XClearWindow(dpy,win) ;
739 GaugeExpose(w,0,0) ;
740 }
741
742
743 static void
744 GaugeDoneSel (Widget w,
745 Atom *selection, /* usually XA_PRIMARY */
746 Atom *target) /* requested target */
747 {
748 /* selection done, anything to do? */
749 }
750
751
752 static void
753 GaugePaste (Widget w,
754 XEvent *event,
755 String *params,
756 Cardinal *num_params)
757 {
758 Atom seln = XA_PRIMARY ;
759
760 if( *num_params > 0 ) {
761 seln = XInternAtom(XtDisplay(w), params[0], False) ;
762 printf("atom %s is %ld\n", params[0], seln) ;
763 }
764
765 /* try for integer value first */
766 XtGetSelectionValue(w, seln, XA_INTEGER,
767 GaugeGetSelCB, (XtPointer)XA_INTEGER,
768 event->xbutton.time) ;
769 }
770
771 static void
772 GaugeGetSelCB (Widget w,
773 XtPointer client,
774 Atom *selection,
775 Atom *type,
776 XtPointer value,
777 u_long *length,
778 int *format)
779 {
780 Display *dpy = XtDisplay(w) ;
781 Atom target = (Atom)client ;
782 int *iptr ;
783 char *cptr ;
784
785 if( *type == XA_INTEGER ) {
786 iptr = (int *)value ;
787 XawGaugeSetValue(w, *iptr) ;
788 }
789
790 else if( *type == XA_STRING
791 #ifdef HAVE_XMU
792 ||
793 *type == XA_TEXT(dpy)
794 #endif
795 )
796 {
797 cptr = (char *)value ;
798 XawGaugeSetValue(w, atoi(cptr)) ;
799 }
800
801 /* failed, try string */
802 else if( *type == None && target == XA_INTEGER )
803 XtGetSelectionValue(w, *selection, XA_STRING,
804 GaugeGetSelCB, (XtPointer)XA_STRING,
805 CurrentTime) ;
806 }
807
808
809
810 /****************************************************************
811 *
812 * Public Procedures
813 *
814 ****************************************************************/
815
816
817 /* Change gauge value. Only undraw or draw what needs to be
818 * changed.
819 */
820
821 void
822 XawGaugeSetValue (Widget w,
823 Cardinal value)
824 {
825 GaugeWidget gw = (GaugeWidget)w ;
826 int oldvalue ;
827 GC gc ;
828
829 if( gw->gauge.selected != None ) {
830 XtDisownSelection(w, gw->gauge.selected, CurrentTime) ;
831 gw->gauge.selected = None ;
832 }
833
834 if( !XtIsRealized(w) ) {
835 gw->gauge.value = value ;
836 return ;
837 }
838
839 /* need to rescale? */
840 if(( gw->gauge.autoScaleUp && value > gw->gauge.v1) ||
841 (gw->gauge.autoScaleDown && value < gw->gauge.v1/3 ))
842 {
843 XtVaSetValues(w, XtNvalue, value, 0) ;
844 return ;
845 }
846
847 oldvalue = gw->gauge.value ;
848 gw->gauge.value = value ;
849
850 gc = XtIsSensitive(w) ? gw->label.normal_GC : gw->label.gray_GC ;
851 GaugeMercury(XtDisplay(w), XtWindow(w), gc, gw, oldvalue,value) ;
852 }
853
854
855 Cardinal
856 XawGaugeGetValue (Widget w)
857 {
858 GaugeWidget gw = (GaugeWidget)w ;
859 return gw->gauge.value ;
860 }
861
862
863
864
865 /****************************************************************
866 *
867 * Private Procedures
868 *
869 ****************************************************************/
870
871 /* draw the mercury over a specific region */
872
873 static void
874 GaugeMercury (Display *dpy,
875 Window win,
876 GC gc,
877 GaugeWidget gw,
878 Cardinal val0,
879 Cardinal val1)
880 {
881 int v0 = gw->gauge.v0 ;
882 int v1 = gw->gauge.v1 ;
883 int vd = v1 - v0 ;
884 Dimension len ; /* length (width or height) of gauge */
885 Position e0, e1 ; /* gauge ends */
886 Position p0, p1 ; /* mercury ends */
887 int y ; /* vertical (horizontal) position */
888 Boolean undraw = FALSE ;
889
890 len = gw->gauge.orientation == XtorientHorizontal ?
891 gw->core.width : gw->core.height ;
892
893 e0 = gw->gauge.margin0 ; /* left (top) end */
894 e1 = len - gw->gauge.margin1 -1 ; /* right (bottom) end */
895
896 if( vd <= 0 ) vd = 1 ;
897
898 if( val0 < v0 ) val0 = v0 ;
899 else if( val0 > v1 ) val0 = v1 ;
900 if( val1 < v0 ) val1 = v0 ;
901 else if( val1 > v1 ) val1 = v1 ;
902
903 p0 = (val0-v0)*(e1-e0-1)/vd ;
904 p1 = (val1-v0)*(e1-e0-1)/vd ;
905
906 if( p1 == p0 )
907 return ;
908
909 y = gw->gauge.gmargin ;
910
911 if( p1 < p0 )
912 {
913 Position tmp = p0 ;
914 p0 = p1 ;
915 p1 = tmp ;
916 gc = gw->label.normal_GC ;
917 XSetForeground(dpy,gc, gw->core.background_pixel) ;
918 undraw = TRUE ;
919 }
920
921 if( gw->gauge.orientation == XtorientHorizontal )
922 XFillRectangle(dpy,win,gc, e0+p0+1,y+1, p1-p0,GA_WID) ;
923 else
924 XFillRectangle(dpy,win,gc, y+1,e1-p1, GA_WID,p1-p0) ;
925
926 if( undraw )
927 XSetForeground(dpy,gc, gw->label.foreground) ;
928 }
929
930
931
932 /* Search the labels, find the largest one. */
933 /* TODO: handle vertical fonts? */
934
935 static void
936 MaxLabel (GaugeWidget gw,
937 Dimension *wid, /* max label width */
938 Dimension *hgt, /* max label height */
939 Dimension *w0, /* width of first label */
940 Dimension *w1) /* width of last label */
941 {
942 char lstr[80], *lbl ;
943 int w ;
944 XFontStruct *font = gw->label.font ;
945 int i ;
946 int lw = 0;
947 int v0 = gw->gauge.v0 ;
948 int dv = gw->gauge.v1 - v0 ;
949 int n = gw->gauge.nlabels ;
950
951 if( n > 0 )
952 {
953 if( --n <= 0 ) {n = 1 ; v0 += dv/2 ;}
954
955 /* loop through all labels, figure out how much room they
956 * need.
957 */
958 w = 0 ;
959 for(i=0; i<gw->gauge.nlabels; ++i)
960 {
961 if( gw->gauge.labels == NULL ) /* numeric labels */
962 sprintf(lbl = lstr,"%d", v0 + i*dv/n) ;
963 else
964 lbl = gw->gauge.labels[i] ;
965
966 if( lbl != NULL ) {
967 lw = XTextWidth(font, lbl, strlen(lbl)) ;
968 w = Max( w, lw ) ;
969 }
970 else
971 lw = 0 ;
972
973 if( i == 0 && w0 != NULL ) *w0 = lw ;
974 }
975 if( w1 != NULL ) *w1 = lw ;
976
977 *wid = w ;
978 *hgt = font->max_bounds.ascent + font->max_bounds.descent ;
979 }
980 else
981 *wid = *hgt = 0 ;
982 }
983
984
985 /* Determine the preferred size for this widget. choose 100x100 for
986 * debugging.
987 */
988
989 static void
990 GaugeSize (GaugeWidget gw,
991 Dimension *wid,
992 Dimension *hgt,
993 Dimension min_len)
994 {
995 int w,h ; /* width, height of gauge */
996 int vmargin ; /* vertical margin */
997 int hmargin ; /* horizontal margin */
998
999 hmargin = gw->label.internal_width ;
1000 vmargin = gw->label.internal_height ;
1001
1002 /* find total height (width) of contents */
1003
1004
1005 /* find minimum size for undecorated gauge */
1006
1007 if( gw->gauge.orientation == XtorientHorizontal )
1008 {
1009 w = min_len ;
1010 h = GA_WID+2 ; /* gauge itself + edges */
1011 }
1012 else
1013 {
1014 w = GA_WID+2 ;
1015 h = min_len ;
1016 }
1017
1018 if( gw->gauge.ntics > 0 )
1019 {
1020 if( gw->gauge.orientation == XtorientHorizontal )
1021 {
1022 w = Max(w, gw->gauge.ntics*3) ;
1023 h += vmargin + TIC_LEN ;
1024 }
1025 else
1026 {
1027 w += hmargin + TIC_LEN ;
1028 h = Max(h, gw->gauge.ntics*3) ;
1029 }
1030 }
1031
1032
1033 /* If labels are requested, this gets a little interesting.
1034 * We want the end labels centered on the ends of the gauge and
1035 * the centers of the labels evenly spaced. The labels at the ends
1036 * will not be the same width, meaning that the gauge itself need
1037 * not be centered in the widget.
1038 *
1039 * First, determine the spacing. This is the width of the widest
1040 * label, plus the internal margin. Total length of the gauge is
1041 * spacing * (nlabels-1). To this, we add half the width of the
1042 * left-most label and half the width of the right-most label
1043 * to get the entire desired width of the widget.
1044 */
1045 if( gw->gauge.nlabels > 0 )
1046 {
1047 Dimension lwm, lw0, lw1 ; /* width of max, left, right labels */
1048 Dimension lh ;
1049
1050 MaxLabel(gw,&lwm,&lh, &lw0,&lw1) ;
1051
1052 if( gw->gauge.orientation == XtorientHorizontal )
1053 {
1054 lwm = (lwm+hmargin) * (gw->gauge.nlabels-1) + (lw0+lw1)/2 ;
1055 w = Max(w, lwm) ;
1056 h += lh + vmargin ;
1057 }
1058 else
1059 {
1060 lh = lh*gw->gauge.nlabels + (gw->gauge.nlabels - 1)*vmargin ;
1061 h = Max(h, lh) ;
1062 w += lwm + hmargin ;
1063 }
1064 }
1065
1066 w += hmargin*2 ;
1067 h += vmargin*2 ;
1068
1069 *wid = w ;
1070 *hgt = h ;
1071 }
1072
1073
1074
1075 static void
1076 AutoScale (GaugeWidget gw)
1077 {
1078 static int scales[3] = {1,2,5} ;
1079 int sptr = 0, smult=1 ;
1080
1081 if( gw->gauge.autoScaleDown )
1082 gw->gauge.v1 = 0 ;
1083 while( gw->gauge.value > gw->gauge.v1 )
1084 {
1085 if( ++sptr > 2 ) {
1086 sptr = 0 ;
1087 smult *= 10 ;
1088 }
1089 gw->gauge.v1 = scales[sptr] * smult ;
1090 }
1091 }
1092
1093 static void
1094 EnableUpdate (GaugeWidget gw)
1095 {
1096 gw->gauge.intervalId =
1097 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)gw),
1098 gw->gauge.update * MS_PER_SEC, GaugeGetValue,
1099 (XtPointer)gw) ;
1100 }
1101
1102 static void
1103 DisableUpdate (GaugeWidget gw)
1104 {
1105 XtRemoveTimeOut(gw->gauge.intervalId) ;
1106 }
1107
1108 static void
1109 GaugeGetValue (XtPointer clientData,
1110 XtIntervalId *intervalId)
1111 {
1112 GaugeWidget gw = (GaugeWidget)clientData ;
1113 Cardinal value ;
1114
1115 if( gw->gauge.update > 0 )
1116 EnableUpdate(gw) ;
1117
1118 if( gw->gauge.getValue != NULL )
1119 {
1120 XtCallCallbackList((Widget)gw, gw->gauge.getValue, (XtPointer)&value);
1121 XawGaugeSetValue((Widget)gw, value) ;
1122 }
1123 }
1124
1125
1126 static GC
1127 Get_GC (GaugeWidget gw,
1128 Pixel fg)
1129 {
1130 XGCValues values ;
1131 #define vmask GCForeground
1132 #define umask (GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset\
1133 |GCFont|GCDashList|GCArcMode)
1134
1135 values.foreground = fg ;
1136
1137 return XtAllocateGC((Widget)gw, 0, vmask, &values, 0L, umask) ;
1138 }