1 /* Gauge Widget for XEmacs.
2 Copyright (C) 1999 Edward A. Falk
4 This file is part of XEmacs.
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
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
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. */
21 /* Synched up with: Gauge.c 1.2 */
24 * Gauge.c - Gauge widget
26 * Author: Edward A. Falk
27 * falk@falconer.vip.best.com
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
39 /* TODO: display time instead of value
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
52 #include <X11/IntrinsicP.h>
53 #include <X11/Xatom.h>
54 #include <X11/StringDefs.h>
55 #include ATHENA_XawInit_h_
56 #include "xlwgaugeP.h"
57 #include "../src/xmu.h"
59 #include <X11/Xmu/Atoms.h>
60 #include <X11/Xmu/Drawing.h>
61 #include <X11/Xmu/StdSel.h>
65 /****************************************************************
69 ****************************************************************/
72 static char defaultTranslations[] =
73 "<Btn1Up>: select()\n\
74 <Key>F1: select(CLIPBOARD)\n\
76 <Key>F2: paste(CLIPBOARD)" ;
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},
109 /* member functions */
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 *,
122 static void GaugeSelect (Widget, XEvent *, String *, Cardinal *);
123 static void GaugePaste (Widget, XEvent *, String *, Cardinal *);
125 /* internal privates */
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);
134 static void GaugeGetValue (XtPointer, XtIntervalId *);
135 static void GaugeMercury (Display *, Window, GC, GaugeWidget, Cardinal, Cardinal);
137 static Boolean GaugeConvert (Widget, Atom *, Atom *, Atom *,
138 XtPointer *, unsigned 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, unsigned long *, int *);
144 static GC Get_GC (GaugeWidget, Pixel);
147 static XtActionsRec actionsList[] =
149 {"select", GaugeSelect},
150 {"paste", GaugePaste},
155 /****************************************************************
157 * Full class record constant
159 ****************************************************************/
161 GaugeClassRec gaugeClassRec = {
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,
197 /* Simple class fields initialization */
199 /* change_sensitive */ XtInheritChangeSensitive
202 /* ThreeD class fields initialization */
204 XtInheritXaw3dShadowDraw /* shadowdraw */
207 /* Label class fields initialization */
211 /* Gauge class fields initialization */
217 WidgetClass gaugeWidgetClass = (WidgetClass)&gaugeClassRec;
222 /****************************************************************
226 ****************************************************************/
229 GaugeClassInit (void)
231 XawInitializeWidgetSet();
233 XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation,
242 GaugeInit (Widget request,
247 GaugeWidget gw = (GaugeWidget) new;
249 if( gw->gauge.v0 == 0 && gw->gauge.v1 == 0 ) {
250 gw->gauge.autoScaleUp = gw->gauge.autoScaleDown = TRUE ;
254 /* If size not explicitly set, set it to our preferred size now. */
256 if( request->core.width == 0 || request->core.height == 0 )
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) ;
267 gw->gauge.selected = None ;
268 gw->gauge.selstr = NULL ;
270 if( gw->gauge.update > 0 )
273 gw->gauge.inverse_GC = Get_GC(gw, gw->core.background_pixel) ;
277 GaugeDestroy (Widget w)
279 GaugeWidget gw = (GaugeWidget)w;
281 if( gw->gauge.selstr != NULL )
282 XtFree(gw->gauge.selstr) ;
284 if( gw->gauge.selected != None )
285 XtDisownSelection(w, gw->gauge.selected, CurrentTime) ;
287 XtReleaseGC(w, gw->gauge.inverse_GC) ;
289 if( gw->gauge.update > 0 )
294 /* React to size change from manager. Label widget will compute some
295 * internal stuff, but we need to override.
299 GaugeResize (Widget w)
301 GaugeWidget gw = (GaugeWidget)w;
302 int size ; /* height (width) of gauge */
303 int vmargin ; /* vertical (horizontal) margin */
304 int hmargin ; /* horizontal (vertical) margin */
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 ;
311 /* TODO: need to call parent resize proc? I don't think so since
312 * we're recomputing everything from scratch anyway.
315 /* find total height (width) of contents */
317 size = GA_WID+2 ; /* gauge itself + edges */
319 if( gw->gauge.ntics > 1 ) /* tic marks */
320 size += vmargin + TIC_LEN ;
322 if( gw->gauge.nlabels > 1 )
324 Dimension lwm, lw0, lw1 ; /* width of max, left, right labels */
327 MaxLabel(gw,&lwm,&lh, &lw0,&lw1) ;
329 if( gw->gauge.orientation == XtorientHorizontal )
331 gw->gauge.margin0 = lw0 / 2 ;
332 gw->gauge.margin1 = lw1 / 2 ;
333 size += lh + vmargin ;
338 gw->gauge.margin1 = lh / 2 ;
339 size += lwm + vmargin ;
343 gw->gauge.margin0 = gw->gauge.margin1 = 0 ;
345 gw->gauge.margin0 += hmargin ;
346 gw->gauge.margin1 += hmargin ;
348 /* Now distribute height (width) over components */
350 if( gw->gauge.orientation == XtorientHorizontal )
351 gw->gauge.gmargin = (gw->core.height-size)/2 ;
353 gw->gauge.gmargin = (gw->core.width-size)/2 ;
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 ;
359 gw->gauge.lmargin = gw->gauge.tmargin ;
363 * Repaint the widget window
368 GaugeExpose (Widget w,
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 */
378 int len ; /* length (width or height) of widget */
379 int hgt ; /* height (width) of widget */
380 int e0,e1 ; /* ends of the gauge */
382 int y ; /* vertical (horizontal) position */
384 int v0 = gw->gauge.v0 ;
385 int v1 = gw->gauge.v1 ;
386 int value = gw->gauge.value ;
388 gc = XtIsSensitive(w) ? gw->label.normal_GC : gw->label.gray_GC ;
392 gctop = gw->threeD.bot_shadow_GC ;
393 gcbot = gw->threeD.top_shadow_GC ;
398 if( gw->gauge.orientation == XtorientHorizontal ) {
399 len = gw->core.width ;
400 hgt = gw->core.height ;
402 len = gw->core.height ;
403 hgt = gw->core.width ;
406 /* if the gauge is selected, signify by drawing the background
407 * in a contrasting color.
410 if( gw->gauge.selected )
412 XFillRectangle(dpy,win, gc, 0,0, w->core.width,w->core.height) ;
413 gc = gw->gauge.inverse_GC ;
416 e0 = gw->gauge.margin0 ; /* left (top) end */
417 e1 = len - gw->gauge.margin1 -1 ; /* right (bottom) end */
419 /* Draw the Gauge itself */
421 y = gw->gauge.gmargin ;
423 if( gw->gauge.orientation == XtorientHorizontal ) /* horizontal */
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) ;
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) ;
439 /* draw the mercury */
441 GaugeMercury(dpy, win, gc, gw, 0,value) ;
444 if( gw->gauge.ntics > 1 )
446 y = gw->gauge.tmargin ;
447 for(i=0; i<gw->gauge.ntics; ++i)
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) ;
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) ;
466 if( gw->gauge.nlabels > 1 )
468 char label[20], *s = label ;
471 if( gw->gauge.orientation == XtorientHorizontal )
472 y = gw->gauge.lmargin + gw->label.font->max_bounds.ascent - 1 ;
474 y = gw->gauge.lmargin ;
475 h = gw->label.font->max_bounds.ascent / 2 ;
478 for(i=0; i<gw->gauge.nlabels; ++i)
480 if( gw->gauge.labels == NULL )
481 sprintf(label, "%d", v0+i*(v1 - v0)/(gw->gauge.nlabels - 1)) ;
483 s = gw->gauge.labels[i] ;
485 x = e0 + i*(e1-e0-1)/(gw->gauge.nlabels-1) ;
487 if( gw->gauge.orientation == XtorientHorizontal ) {
488 wd = XTextWidth(gw->label.font, s, xlen) ;
489 XDrawString(dpy,win,gc, x-wd/2,y, s,xlen) ;
492 XDrawString(dpy,win,gc, y,x+h, s,xlen) ;
501 * Set specified arguments into widget
505 GaugeSetValues (Widget old,
511 GaugeWidget oldgw = (GaugeWidget) old;
512 GaugeWidget gw = (GaugeWidget) new;
513 Boolean was_resized = False;
515 if( gw->gauge.selected != None ) {
516 XtDisownSelection(new, gw->gauge.selected, CurrentTime) ;
517 gw->gauge.selected = None ;
520 /* Changes to v0,v1,labels, ntics, nlabels require resize & redraw. */
521 /* Change to value requires redraw and possible resize if autoscale */
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 ;
530 if( (gw->gauge.autoScaleUp && gw->gauge.value > gw->gauge.v1) ||
531 (gw->gauge.autoScaleDown && gw->gauge.value < gw->gauge.v1/3 ))
538 if( gw->label.resize )
539 GaugeSize(gw, &gw->core.width, &gw->core.height, DEF_LEN) ;
544 if( gw->gauge.update != oldgw->gauge.update )
546 if( gw->gauge.update > 0 )
552 if( gw->core.background_pixel != oldgw->core.background_pixel )
554 XtReleaseGC(new, gw->gauge.inverse_GC) ;
555 gw->gauge.inverse_GC = Get_GC(gw, gw->core.background_pixel) ;
558 return was_resized || gw->gauge.value != oldgw->gauge.value ||
559 XtIsSensitive(old) != XtIsSensitive(new);
563 static XtGeometryResult
564 GaugeQueryGeometry (Widget w,
565 XtWidgetGeometry *intended,
566 XtWidgetGeometry *preferred)
568 register GaugeWidget gw = (GaugeWidget)w;
570 if( intended->width == w->core.width &&
571 intended->height == w->core.height )
572 return XtGeometryNo ;
574 preferred->request_mode = CWWidth | CWHeight;
575 GaugeSize(gw, &preferred->width, &preferred->height, DEF_LEN) ;
577 if( (!(intended->request_mode & CWWidth) ||
578 intended->width >= preferred->width) &&
579 (!(intended->request_mode & CWHeight) ||
580 intended->height >= preferred->height) )
581 return XtGeometryYes;
583 return XtGeometryAlmost;
589 /****************************************************************
593 ****************************************************************/
596 GaugeSelect (Widget w,
599 Cardinal *num_params)
601 GaugeWidget gw = (GaugeWidget)w ;
602 Atom seln = XA_PRIMARY ;
604 if( gw->gauge.selected != None ) {
605 XtDisownSelection(w, gw->gauge.selected, CurrentTime) ;
606 gw->gauge.selected = None ;
609 if( *num_params > 0 ) {
610 seln = XInternAtom(XtDisplay(w), params[0], False) ;
611 printf("atom %s is %ld\n", params[0], seln) ;
614 if( ! XtOwnSelection(w, seln, event->xbutton.time, GaugeConvert,
615 GaugeLoseSel, GaugeDoneSel) )
617 /* in real code, this error message would be replaced by
618 * something more elegant, or at least deleted
621 fprintf(stderr, "Gauge failed to get selection, try again\n") ;
625 gw->gauge.selected = TRUE ;
626 gw->gauge.selstr = (String)XtMalloc(4*sizeof(int)) ;
627 sprintf(gw->gauge.selstr, "%d", gw->gauge.value) ;
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 unsigned long *length, /* returned length */
640 int *format) /* returned format */
642 GaugeWidget gw = (GaugeWidget)w ;
643 XSelectionRequestEvent *req ;
645 printf( "requesting selection %s:%s\n",
646 XGetAtomName(XtDisplay(w),*selection),
647 XGetAtomName(XtDisplay(w),*target));
650 if( *target == XA_TARGETS(XtDisplay(w)) )
652 Atom *rval, *stdTargets ;
653 unsigned long stdLength ;
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.
660 req = XtGetSelectionRequest(w, *selection, NULL) ;
661 XmuConvertStandardSelection(w, req->time, selection, target,
662 type, (XPointer*)&stdTargets, &stdLength, format) ;
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? */
679 if( *target == XA_INTEGER )
683 *value = (XtPointer) &gw->gauge.value ;
684 *format = 8*sizeof(int) ;
688 else if( *target == XA_STRING
691 *target == XA_TEXT(XtDisplay(w))
696 *length = strlen(gw->gauge.selstr)*sizeof(char) ;
697 *value = (XtPointer) gw->gauge.selstr ;
704 /* anything else, we just give it to XmuConvertStandardSelection() */
706 req = XtGetSelectionRequest(w, *selection, NULL) ;
707 if( XmuConvertStandardSelection(w, req->time, selection, target,
708 type, (XPointer *) value, length, format) )
714 "Gauge: requestor is requesting unsupported selection %s:%s\n",
715 XGetAtomName(XtDisplay(w),*selection),
716 XGetAtomName(XtDisplay(w),*target));
725 GaugeLoseSel (Widget w,
726 Atom *selection) /* usually XA_PRIMARY */
728 GaugeWidget gw = (GaugeWidget)w ;
729 Display *dpy = XtDisplay(w) ;
730 Window win = XtWindow(w) ;
732 if( gw->gauge.selstr != NULL ) {
733 XtFree(gw->gauge.selstr) ;
734 gw->gauge.selstr = NULL ;
737 gw->gauge.selected = False ;
738 XClearWindow(dpy,win) ;
744 GaugeDoneSel (Widget w,
745 Atom *selection, /* usually XA_PRIMARY */
746 Atom *target) /* requested target */
748 /* selection done, anything to do? */
753 GaugePaste (Widget w,
756 Cardinal *num_params)
758 Atom seln = XA_PRIMARY ;
760 if( *num_params > 0 ) {
761 seln = XInternAtom(XtDisplay(w), params[0], False) ;
762 printf("atom %s is %ld\n", params[0], seln) ;
765 /* try for integer value first */
766 XtGetSelectionValue(w, seln, XA_INTEGER,
767 GaugeGetSelCB, (XtPointer)XA_INTEGER,
768 event->xbutton.time) ;
772 GaugeGetSelCB (Widget w,
777 unsigned long *length,
780 Display *dpy = XtDisplay(w) ;
781 Atom target = (Atom)client ;
785 if( *type == XA_INTEGER ) {
786 iptr = (int *)value ;
787 XawGaugeSetValue(w, *iptr) ;
790 else if( *type == XA_STRING
793 *type == XA_TEXT(dpy)
797 cptr = (char *)value ;
798 XawGaugeSetValue(w, atoi(cptr)) ;
801 /* failed, try string */
802 else if( *type == None && target == XA_INTEGER )
803 XtGetSelectionValue(w, *selection, XA_STRING,
804 GaugeGetSelCB, (XtPointer)XA_STRING,
810 /****************************************************************
814 ****************************************************************/
817 /* Change gauge value. Only undraw or draw what needs to be
822 XawGaugeSetValue (Widget w,
825 GaugeWidget gw = (GaugeWidget)w ;
829 if( gw->gauge.selected != None ) {
830 XtDisownSelection(w, gw->gauge.selected, CurrentTime) ;
831 gw->gauge.selected = None ;
834 if( !XtIsRealized(w) ) {
835 gw->gauge.value = value ;
839 /* need to rescale? */
840 if(( gw->gauge.autoScaleUp && value > gw->gauge.v1) ||
841 (gw->gauge.autoScaleDown && value < gw->gauge.v1/3 ))
843 XtVaSetValues(w, XtNvalue, value, 0) ;
847 oldvalue = gw->gauge.value ;
848 gw->gauge.value = value ;
850 gc = XtIsSensitive(w) ? gw->label.normal_GC : gw->label.gray_GC ;
851 GaugeMercury(XtDisplay(w), XtWindow(w), gc, gw, oldvalue,value) ;
856 XawGaugeGetValue (Widget w)
858 GaugeWidget gw = (GaugeWidget)w ;
859 return gw->gauge.value ;
865 /****************************************************************
869 ****************************************************************/
871 /* draw the mercury over a specific region */
874 GaugeMercury (Display *dpy,
881 int v0 = gw->gauge.v0 ;
882 int v1 = gw->gauge.v1 ;
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 ;
890 len = gw->gauge.orientation == XtorientHorizontal ?
891 gw->core.width : gw->core.height ;
893 e0 = gw->gauge.margin0 ; /* left (top) end */
894 e1 = len - gw->gauge.margin1 -1 ; /* right (bottom) end */
896 if( vd <= 0 ) vd = 1 ;
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 ;
903 p0 = (val0-v0)*(e1-e0-1)/vd ;
904 p1 = (val1-v0)*(e1-e0-1)/vd ;
909 y = gw->gauge.gmargin ;
916 gc = gw->label.normal_GC ;
917 XSetForeground(dpy,gc, gw->core.background_pixel) ;
921 if( gw->gauge.orientation == XtorientHorizontal )
922 XFillRectangle(dpy,win,gc, e0+p0+1,y+1, p1-p0,GA_WID) ;
924 XFillRectangle(dpy,win,gc, y+1,e1-p1, GA_WID,p1-p0) ;
927 XSetForeground(dpy,gc, gw->label.foreground) ;
932 /* Search the labels, find the largest one. */
933 /* TODO: handle vertical fonts? */
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 */
942 char lstr[80], *lbl ;
944 XFontStruct *font = gw->label.font ;
947 int v0 = gw->gauge.v0 ;
948 int dv = gw->gauge.v1 - v0 ;
949 int n = gw->gauge.nlabels ;
953 if( --n <= 0 ) {n = 1 ; v0 += dv/2 ;}
955 /* loop through all labels, figure out how much room they
959 for(i=0; i<gw->gauge.nlabels; ++i)
961 if( gw->gauge.labels == NULL ) /* numeric labels */
962 sprintf(lbl = lstr,"%d", v0 + i*dv/n) ;
964 lbl = gw->gauge.labels[i] ;
967 lw = XTextWidth(font, lbl, strlen(lbl)) ;
973 if( i == 0 && w0 != NULL ) *w0 = lw ;
975 if( w1 != NULL ) *w1 = lw ;
978 *hgt = font->max_bounds.ascent + font->max_bounds.descent ;
985 /* Determine the preferred size for this widget. choose 100x100 for
990 GaugeSize (GaugeWidget gw,
995 int w,h ; /* width, height of gauge */
996 int vmargin ; /* vertical margin */
997 int hmargin ; /* horizontal margin */
999 hmargin = gw->label.internal_width ;
1000 vmargin = gw->label.internal_height ;
1002 /* find total height (width) of contents */
1005 /* find minimum size for undecorated gauge */
1007 if( gw->gauge.orientation == XtorientHorizontal )
1010 h = GA_WID+2 ; /* gauge itself + edges */
1018 if( gw->gauge.ntics > 0 )
1020 if( gw->gauge.orientation == XtorientHorizontal )
1022 w = Max(w, gw->gauge.ntics*3) ;
1023 h += vmargin + TIC_LEN ;
1027 w += hmargin + TIC_LEN ;
1028 h = Max(h, gw->gauge.ntics*3) ;
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.
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.
1045 if( gw->gauge.nlabels > 0 )
1047 Dimension lwm, lw0, lw1 ; /* width of max, left, right labels */
1050 MaxLabel(gw,&lwm,&lh, &lw0,&lw1) ;
1052 if( gw->gauge.orientation == XtorientHorizontal )
1054 lwm = (lwm+hmargin) * (gw->gauge.nlabels-1) + (lw0+lw1)/2 ;
1060 lh = lh*gw->gauge.nlabels + (gw->gauge.nlabels - 1)*vmargin ;
1062 w += lwm + hmargin ;
1076 AutoScale (GaugeWidget gw)
1078 static int scales[3] = {1,2,5} ;
1079 int sptr = 0, smult=1 ;
1081 if( gw->gauge.autoScaleDown )
1083 while( gw->gauge.value > gw->gauge.v1 )
1089 gw->gauge.v1 = scales[sptr] * smult ;
1094 EnableUpdate (GaugeWidget gw)
1096 gw->gauge.intervalId =
1097 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget)gw),
1098 gw->gauge.update * MS_PER_SEC, GaugeGetValue,
1103 DisableUpdate (GaugeWidget gw)
1105 XtRemoveTimeOut(gw->gauge.intervalId) ;
1109 GaugeGetValue (XtPointer clientData,
1110 XtIntervalId *intervalId)
1112 GaugeWidget gw = (GaugeWidget)clientData ;
1115 if( gw->gauge.update > 0 )
1118 if( gw->gauge.getValue != NULL )
1120 XtCallCallbackList((Widget)gw, gw->gauge.getValue, (XtPointer)&value);
1121 XawGaugeSetValue((Widget)gw, value) ;
1127 Get_GC (GaugeWidget gw,
1131 #define vmask GCForeground
1132 #define umask (GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset\
1133 |GCFont|GCDashList|GCArcMode)
1135 values.foreground = fg ;
1137 return XtAllocateGC((Widget)gw, 0, vmask, &values, 0L, umask) ;