1 /* Gauge Widget for SXEmacs.
2 Copyright (C) 1999 Edward A. Falk
4 This file is part of SXEmacs.
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
19 /* Synched up with: Gauge.c 1.2 */
22 * Gauge.c - Gauge widget
24 * Author: Edward A. Falk
25 * falk@falconer.vip.best.com
29 * Note: for fun and demonstration purposes, I have added selection
30 * capabilities to this widget. If you select the widget, you create
31 * a primary selection containing the current value of the widget in
32 * both integer and string form. If you copy into the widget, the
33 * primary selection is converted to an integer value and the gauge is
37 /* TODO: display time instead of value
40 #define DEF_LEN 50 /* default width (or height for vertical gauge) */
41 #define MIN_LEN 10 /* minimum reasonable width (height) */
42 #define TIC_LEN 6 /* length of tic marks */
43 #define GA_WID 3 /* width of gauge */
44 #define MS_PER_SEC 1000
50 #include "lwlib-internal.h"
51 #include <X11/IntrinsicP.h>
52 #include <X11/Xatom.h>
53 #include <X11/StringDefs.h>
54 #include ATHENA_XawInit_h_
55 #include "xlwgaugeP.h"
56 #include "ui/X11/xmu.h"
58 #include <X11/Xmu/Atoms.h>
59 #include <X11/Xmu/Drawing.h>
60 #include <X11/Xmu/StdSel.h>
63 /****************************************************************
67 ****************************************************************/
69 static char defaultTranslations[] = "<Btn1Up>: select()\n\
70 <Key>F1: select(CLIPBOARD)\n\
72 <Key>F2: paste(CLIPBOARD)";
74 #define offset(field) XtOffsetOf(GaugeRec, field)
75 static XtResource resources[] = {
76 {XtNvalue, XtCValue, XtRInt, sizeof(int),
77 offset(gauge.value), XtRImmediate, (XtPointer) 0},
78 {XtNminValue, XtCMinValue, XtRInt, sizeof(int),
79 offset(gauge.v0), XtRImmediate, (XtPointer) 0},
80 {XtNmaxValue, XtCMaxValue, XtRInt, sizeof(int),
81 offset(gauge.v1), XtRImmediate, (XtPointer) 100},
82 {XtNntics, XtCNTics, XtRInt, sizeof(int),
83 offset(gauge.ntics), XtRImmediate, (XtPointer) 0},
84 {XtNnlabels, XtCNLabels, XtRInt, sizeof(int),
85 offset(gauge.nlabels), XtRImmediate, (XtPointer) 0},
86 {XtNlabels, XtCLabels, XtRStringArray, sizeof(String *),
87 offset(gauge.labels), XtRStringArray, NULL}
89 {XtNautoScaleUp, XtCAutoScaleUp, XtRBoolean, sizeof(Boolean),
90 offset(gauge.autoScaleUp), XtRImmediate, FALSE}
92 {XtNautoScaleDown, XtCAutoScaleDown, XtRBoolean, sizeof(Boolean),
93 offset(gauge.autoScaleDown), XtRImmediate, FALSE}
95 {XtNorientation, XtCOrientation, XtROrientation, sizeof(XtOrientation),
96 offset(gauge.orientation), XtRImmediate, (XtPointer) XtorientHorizontal}
98 {XtNupdate, XtCInterval, XtRInt, sizeof(int),
99 offset(gauge.update), XtRImmediate, (XtPointer) 0},
100 {XtNgetValue, XtCCallback, XtRCallback, sizeof(XtPointer),
101 offset(gauge.getValue), XtRImmediate, (XtPointer) NULL}
106 /* member functions */
108 static void GaugeClassInit(void);
109 static void GaugeInit(Widget, Widget, ArgList, Cardinal *);
110 static void GaugeDestroy(Widget);
111 static void GaugeResize(Widget);
112 static void GaugeExpose(Widget, XEvent *, Region);
113 static Boolean GaugeSetValues(Widget, Widget, Widget, ArgList, Cardinal *);
114 static XtGeometryResult GaugeQueryGeometry(Widget, XtWidgetGeometry *,
119 static void GaugeSelect(Widget, XEvent *, String *, Cardinal *);
120 static void GaugePaste(Widget, XEvent *, String *, Cardinal *);
122 /* internal privates */
124 static void GaugeSize(GaugeWidget, Dimension *, Dimension *, Dimension);
125 static void MaxLabel(GaugeWidget, Dimension *, Dimension *,
126 Dimension *, Dimension *);
127 static void AutoScale(GaugeWidget);
128 static void EnableUpdate(GaugeWidget);
129 static void DisableUpdate(GaugeWidget);
131 static void GaugeGetValue(XtPointer, XtIntervalId *);
132 static void GaugeMercury(Display *, Window, GC, GaugeWidget, Cardinal,
135 static Boolean GaugeConvert(Widget, Atom *, Atom *, Atom *,
136 XtPointer *, unsigned long *, int *);
137 static void GaugeLoseSel(Widget, Atom *);
138 static void GaugeDoneSel(Widget, Atom *, Atom *);
139 static void GaugeGetSelCB(Widget, XtPointer, Atom *, Atom *,
140 XtPointer, unsigned long *, int *);
142 static GC Get_GC(GaugeWidget, Pixel);
144 static XtActionsRec actionsList[] = {
145 {"select", GaugeSelect},
146 {"paste", GaugePaste},
149 /****************************************************************
151 * Full class record constant
153 ****************************************************************/
155 GaugeClassRec gaugeClassRec = {
157 /* core_class fields */
158 /* superclass */ (WidgetClass) & labelClassRec,
159 /* class_name */ "Gauge",
160 /* widget_size */ sizeof(GaugeRec),
161 /* class_initialize */ GaugeClassInit,
162 /* class_part_initialize */ NULL,
163 /* class_inited */ FALSE,
164 /* initialize */ GaugeInit,
165 /* initialize_hook */ NULL,
166 /* realize */ XtInheritRealize,
168 /* actions */ actionsList,
169 /* num_actions */ XtNumber(actionsList),
170 /* resources */ resources,
171 /* num_resources */ XtNumber(resources),
172 /* xrm_class */ NULLQUARK,
173 /* compress_motion */ TRUE,
174 /* compress_exposure */ TRUE,
175 /* compress_enterleave */ TRUE,
176 /* visible_interest */ FALSE,
177 /* destroy */ GaugeDestroy,
178 /* resize */ GaugeResize,
179 /* expose */ GaugeExpose,
180 /* set_values */ GaugeSetValues,
181 /* set_values_hook */ NULL,
182 /* set_values_almost */ XtInheritSetValuesAlmost,
183 /* get_values_hook */ NULL,
184 /* accept_focus */ NULL,
185 /* version */ XtVersion,
186 /* callback_private */ NULL,
187 /* tm_table */ defaultTranslations,
188 /* query_geometry */ GaugeQueryGeometry,
189 /* display_accelerator */ XtInheritDisplayAccelerator,
193 /* Simple class fields initialization */
195 /* change_sensitive */ XtInheritChangeSensitive
199 /* ThreeD class fields initialization */
201 XtInheritXaw3dShadowDraw /* shadowdraw */
205 /* Label class fields initialization */
210 /* Gauge class fields initialization */
217 WidgetClass gaugeWidgetClass = (WidgetClass) & gaugeClassRec;
219 /****************************************************************
223 ****************************************************************/
225 static void GaugeClassInit(void)
227 XawInitializeWidgetSet();
229 XtAddConverter(XtRString, XtROrientation, XmuCvtStringToOrientation,
236 GaugeInit(Widget request, Widget new, ArgList args, Cardinal * num_args)
238 GaugeWidget gw = (GaugeWidget) new;
240 if (gw->gauge.v0 == 0 && gw->gauge.v1 == 0) {
241 gw->gauge.autoScaleUp = gw->gauge.autoScaleDown = TRUE;
245 /* If size not explicitly set, set it to our preferred size now. */
247 if (request->core.width == 0 || request->core.height == 0) {
249 GaugeSize(gw, &w, &h, DEF_LEN);
250 if (request->core.width == 0)
252 if (request->core.height == 0)
253 new->core.height = h;
254 gw->core.widget_class->core_class.resize(new);
257 gw->gauge.selected = None;
258 gw->gauge.selstr = NULL;
260 if (gw->gauge.update > 0)
263 gw->gauge.inverse_GC = Get_GC(gw, gw->core.background_pixel);
266 static void GaugeDestroy(Widget w)
268 GaugeWidget gw = (GaugeWidget) w;
270 if (gw->gauge.selstr != NULL)
271 XtFree(gw->gauge.selstr);
273 if (gw->gauge.selected != None)
274 XtDisownSelection(w, gw->gauge.selected, CurrentTime);
276 XtReleaseGC(w, gw->gauge.inverse_GC);
278 if (gw->gauge.update > 0)
282 /* React to size change from manager. Label widget will compute some
283 * internal stuff, but we need to override.
286 static void GaugeResize(Widget w)
288 GaugeWidget gw = (GaugeWidget) w;
289 int size; /* height (width) of gauge */
290 int vmargin; /* vertical (horizontal) margin */
291 int hmargin; /* horizontal (vertical) margin */
293 vmargin = gw->gauge.orientation == XtorientHorizontal ?
294 gw->label.internal_height : gw->label.internal_width;
295 hmargin = gw->gauge.orientation == XtorientHorizontal ?
296 gw->label.internal_width : gw->label.internal_height;
298 /* TODO: need to call parent resize proc? I don't think so since
299 * we're recomputing everything from scratch anyway.
302 /* find total height (width) of contents */
304 size = GA_WID + 2; /* gauge itself + edges */
306 if (gw->gauge.ntics > 1) /* tic marks */
307 size += vmargin + TIC_LEN;
309 if (gw->gauge.nlabels > 1) {
310 Dimension lwm, lw0, lw1; /* width of max, left, right labels */
313 MaxLabel(gw, &lwm, &lh, &lw0, &lw1);
315 if (gw->gauge.orientation == XtorientHorizontal) {
316 gw->gauge.margin0 = lw0 / 2;
317 gw->gauge.margin1 = lw1 / 2;
318 size += lh + vmargin;
320 gw->gauge.margin0 = gw->gauge.margin1 = lh / 2;
321 size += lwm + vmargin;
324 gw->gauge.margin0 = gw->gauge.margin1 = 0;
326 gw->gauge.margin0 += hmargin;
327 gw->gauge.margin1 += hmargin;
329 /* Now distribute height (width) over components */
331 if (gw->gauge.orientation == XtorientHorizontal)
332 gw->gauge.gmargin = (gw->core.height - size) / 2;
334 gw->gauge.gmargin = (gw->core.width - size) / 2;
336 gw->gauge.tmargin = gw->gauge.gmargin + GA_WID + 2 + vmargin;
337 if (gw->gauge.ntics > 1)
338 gw->gauge.lmargin = gw->gauge.tmargin + TIC_LEN + vmargin;
340 gw->gauge.lmargin = gw->gauge.tmargin;
344 * Repaint the widget window
348 static void GaugeExpose(Widget w, XEvent * event, Region region)
350 GaugeWidget gw = (GaugeWidget) w;
351 register Display *dpy = XtDisplay(w);
352 register Window win = XtWindow(w);
353 GC gc; /* foreground, background */
354 GC gctop, gcbot; /* dark, light shadows */
356 int len; /* length (width or height) of widget */
357 int hgt; /* height (width) of widget */
358 int e0, e1; /* ends of the gauge */
360 int y; /* vertical (horizontal) position */
362 int v0 = gw->gauge.v0;
363 int v1 = gw->gauge.v1;
364 int value = gw->gauge.value;
366 gc = XtIsSensitive(w) ? gw->label.normal_GC : gw->label.gray_GC;
369 gctop = gw->threeD.bot_shadow_GC;
370 gcbot = gw->threeD.top_shadow_GC;
375 if (gw->gauge.orientation == XtorientHorizontal) {
376 len = gw->core.width;
377 hgt = gw->core.height;
379 len = gw->core.height;
380 hgt = gw->core.width;
385 /* if the gauge is selected, signify by drawing the background
386 * in a contrasting color.
389 if (gw->gauge.selected) {
390 XFillRectangle(dpy, win, gc, 0, 0, w->core.width,
392 gc = gw->gauge.inverse_GC;
395 e0 = gw->gauge.margin0; /* left (top) end */
396 e1 = len - gw->gauge.margin1 - 1; /* right (bottom) end */
398 /* Draw the Gauge itself */
400 y = gw->gauge.gmargin;
402 if (gw->gauge.orientation == XtorientHorizontal) { /* horizontal */
403 XDrawLine(dpy, win, gctop, e0 + 1, y, e1 - 1, y);
404 XDrawLine(dpy, win, gctop, e0, y + 1, e0, y + GA_WID);
405 XDrawLine(dpy, win, gcbot, e0 + 1, y + GA_WID + 1, e1 - 1,
407 XDrawLine(dpy, win, gcbot, e1, y + 1, e1, y + GA_WID);
408 } else { /* vertical */
410 XDrawLine(dpy, win, gctop, y, e0 + 1, y, e1 - 1);
411 XDrawLine(dpy, win, gctop, y + 1, e0, y + GA_WID, e0);
412 XDrawLine(dpy, win, gcbot, y + GA_WID + 1, e0 + 1,
413 y + GA_WID + 1, e1 - 1);
414 XDrawLine(dpy, win, gcbot, y + 1, e1, y + GA_WID, e1);
417 /* draw the mercury */
419 GaugeMercury(dpy, win, gc, gw, 0, value);
421 if (gw->gauge.ntics > 1) {
422 y = gw->gauge.tmargin;
423 for (i = 0; i < gw->gauge.ntics; ++i) {
424 x = e0 + i * (e1 - e0 - 1) / (gw->gauge.ntics - 1);
425 if (gw->gauge.orientation == XtorientHorizontal) {
426 XDrawLine(dpy, win, gcbot, x, y + 1, x,
428 XDrawLine(dpy, win, gcbot, x, y, x + 1, y);
429 XDrawLine(dpy, win, gctop, x + 1, y + 1, x + 1,
431 XDrawLine(dpy, win, gctop, x, y + TIC_LEN - 1,
432 x + 1, y + TIC_LEN - 1);
434 XDrawLine(dpy, win, gcbot, y + 1, x,
436 XDrawLine(dpy, win, gcbot, y, x, y, x + 1);
437 XDrawLine(dpy, win, gctop, y + 1, x + 1,
438 y + TIC_LEN - 2, x + 1);
439 XDrawLine(dpy, win, gctop, y + TIC_LEN - 1, x,
440 y + TIC_LEN - 1, x + 1);
446 if (gw->gauge.nlabels > 1) {
447 char label[sizeof(long)*3+1], *s = label;
448 int xlen, wd, h = 0, n;
450 if (gw->gauge.orientation == XtorientHorizontal)
451 y = gw->gauge.lmargin +
452 gw->label.font->max_bounds.ascent - 1;
454 y = gw->gauge.lmargin;
455 h = gw->label.font->max_bounds.ascent / 2;
458 for (i = 0; i < gw->gauge.nlabels; ++i) {
459 if (gw->gauge.labels == NULL) {
460 n = snprintf(label, sizeof(label),
463 (gw->gauge.nlabels - 1));
464 assert(n >= 0 && (size_t)n < sizeof(label));
467 s = gw->gauge.labels[i];
469 x = e0 + i * (e1 - e0 - 1) /
470 (gw->gauge.nlabels - 1);
472 if (gw->gauge.orientation == XtorientHorizontal) {
473 wd = XTextWidth(gw->label.font, s,
475 XDrawString(dpy, win, gc, x - wd / 2, y,
478 XDrawString(dpy, win, gc, y, x + h, s,
487 * Set specified arguments into widget
491 GaugeSetValues(Widget old,
492 Widget request, Widget new, ArgList args, Cardinal * num_args)
494 GaugeWidget oldgw = (GaugeWidget) old;
495 GaugeWidget gw = (GaugeWidget) new;
496 Boolean was_resized = False;
498 if (gw->gauge.selected != None) {
499 XtDisownSelection(new, gw->gauge.selected, CurrentTime);
500 gw->gauge.selected = None;
503 /* Changes to v0,v1,labels, ntics, nlabels require resize & redraw. */
504 /* Change to value requires redraw and possible resize if autoscale */
507 gw->gauge.v0 != oldgw->gauge.v0 ||
508 gw->gauge.v1 != oldgw->gauge.v1 ||
509 gw->gauge.ntics != oldgw->gauge.ntics ||
510 gw->gauge.nlabels != oldgw->gauge.nlabels ||
511 gw->gauge.labels != oldgw->gauge.labels;
513 if ((gw->gauge.autoScaleUp && gw->gauge.value > gw->gauge.v1) ||
514 (gw->gauge.autoScaleDown && gw->gauge.value < gw->gauge.v1 / 3)) {
520 if (gw->label.resize)
521 GaugeSize(gw, &gw->core.width, &gw->core.height,
527 if (gw->gauge.update != oldgw->gauge.update) {
528 if (gw->gauge.update > 0)
534 if (gw->core.background_pixel != oldgw->core.background_pixel) {
535 XtReleaseGC(new, gw->gauge.inverse_GC);
536 gw->gauge.inverse_GC = Get_GC(gw, gw->core.background_pixel);
539 return was_resized || gw->gauge.value != oldgw->gauge.value ||
540 XtIsSensitive(old) != XtIsSensitive(new);
543 static XtGeometryResult
544 GaugeQueryGeometry(Widget w,
545 XtWidgetGeometry * intended, XtWidgetGeometry * preferred)
547 register GaugeWidget gw = (GaugeWidget) w;
549 if (intended->width == w->core.width &&
550 intended->height == w->core.height)
553 preferred->request_mode = CWWidth | CWHeight;
554 GaugeSize(gw, &preferred->width, &preferred->height, DEF_LEN);
556 if ((!(intended->request_mode & CWWidth) ||
557 intended->width >= preferred->width) &&
558 (!(intended->request_mode & CWHeight) ||
559 intended->height >= preferred->height))
560 return XtGeometryYes;
562 return XtGeometryAlmost;
565 /****************************************************************
569 ****************************************************************/
572 GaugeSelect(Widget w, XEvent * event, String * params, Cardinal * num_params)
574 GaugeWidget gw = (GaugeWidget) w;
575 Atom seln = XA_PRIMARY;
577 if (gw->gauge.selected != None) {
578 XtDisownSelection(w, gw->gauge.selected, CurrentTime);
579 gw->gauge.selected = None;
582 if (*num_params > 0) {
583 seln = XInternAtom(XtDisplay(w), params[0], False);
584 printf("atom %s is %ld\n", params[0], seln);
587 if (!XtOwnSelection(w, seln, event->xbutton.time, GaugeConvert,
588 GaugeLoseSel, GaugeDoneSel)) {
589 /* in real code, this error message would be replaced by
590 * something more elegant, or at least deleted
593 fprintf(stderr, "Gauge failed to get selection, try again\n");
596 const int max_selstr = 4 * sizeof(int);
597 gw->gauge.selected = TRUE;
598 gw->gauge.selstr = (String) XtMalloc(max_selstr);
599 n = snprintf(gw->gauge.selstr, max_selstr, "%d", gw->gauge.value);
600 assert(n >= 0 && n < max_selstr);
601 GaugeExpose(w, 0, 0);
605 static Boolean GaugeConvert(Widget w, Atom * selection, /* usually XA_PRIMARY */
606 Atom * target, /* requested target */
607 Atom * type, /* returned type */
608 XtPointer * value, /* returned value */
609 unsigned long *length, /* returned length */
611 { /* returned format */
612 GaugeWidget gw = (GaugeWidget) w;
613 XSelectionRequestEvent *req;
615 printf("requesting selection %s:%s\n",
616 XGetAtomName(XtDisplay(w), *selection),
617 XGetAtomName(XtDisplay(w), *target));
620 if (*target == XA_TARGETS(XtDisplay(w))) {
623 unsigned long stdLength;
625 /* XmuConvertStandardSelection can handle this. This function
626 * will return a list of standard targets. We prepend TEXT,
627 * STRING and INTEGER to the list and return it.
630 req = XtGetSelectionRequest(w, *selection, NULL);
631 XmuConvertStandardSelection(w, req->time, selection, target,
635 *type = XA_ATOM; /* TODO: needed? */
636 *length = stdLength + 3;
637 rval = (Atom *) XtMalloc(sizeof(Atom) * (stdLength + 3));
638 *value = (XtPointer) rval;
639 *rval++ = XA_INTEGER;
641 *rval++ = XA_TEXT(XtDisplay(w));
642 memcpy((char *)rval, (char *)stdTargets,
643 stdLength * sizeof(Atom));
644 XtFree((char *)stdTargets);
645 *format = 8 * sizeof(Atom); /* TODO: needed? */
651 if (*target == XA_INTEGER) {
654 *value = (XtPointer) & gw->gauge.value;
655 *format = 8 * sizeof(int);
659 else if (*target == XA_STRING
661 || *target == XA_TEXT(XtDisplay(w))
665 *length = strlen(gw->gauge.selstr) * sizeof(char);
666 *value = (XtPointer) gw->gauge.selstr;
672 /* anything else, we just give it to XmuConvertStandardSelection() */
674 req = XtGetSelectionRequest(w, *selection, NULL);
675 if (XmuConvertStandardSelection(w, req->time, selection, target,
676 type, (XPointer *) value,
683 ("Gauge: requestor is requesting unsupported selection %s:%s\n",
684 XGetAtomName(XtDisplay(w), *selection),
685 XGetAtomName(XtDisplay(w), *target));
691 static void GaugeLoseSel(Widget w, Atom * selection)
692 { /* usually XA_PRIMARY */
693 GaugeWidget gw = (GaugeWidget) w;
694 Display *dpy = XtDisplay(w);
695 Window win = XtWindow(w);
697 if (gw->gauge.selstr != NULL) {
698 XtFree(gw->gauge.selstr);
699 gw->gauge.selstr = NULL;
702 gw->gauge.selected = False;
703 XClearWindow(dpy, win);
704 GaugeExpose(w, 0, 0);
707 static void GaugeDoneSel(Widget w, Atom * selection, /* usually XA_PRIMARY */
709 { /* requested target */
710 /* selection done, anything to do? */
714 GaugePaste(Widget w, XEvent * event, String * params, Cardinal * num_params)
716 Atom seln = XA_PRIMARY;
718 if (*num_params > 0) {
719 seln = XInternAtom(XtDisplay(w), params[0], False);
720 printf("atom %s is %ld\n", params[0], seln);
723 /* try for integer value first */
724 XtGetSelectionValue(w, seln, XA_INTEGER,
725 GaugeGetSelCB, (XtPointer) XA_INTEGER,
726 event->xbutton.time);
730 GaugeGetSelCB(Widget w,
733 Atom * type, XtPointer value, unsigned long *length, int *format)
735 Display *dpy = XtDisplay(w);
736 Atom target = (Atom) client;
740 if (*type == XA_INTEGER) {
742 XawGaugeSetValue(w, *iptr);
745 else if (*type == XA_STRING
747 || *type == XA_TEXT(dpy)
750 cptr = (char *)value;
751 XawGaugeSetValue(w, atoi(cptr));
754 /* failed, try string */
755 else if (*type == None && target == XA_INTEGER)
756 XtGetSelectionValue(w, *selection, XA_STRING,
757 GaugeGetSelCB, (XtPointer) XA_STRING,
761 /****************************************************************
765 ****************************************************************/
767 /* Change gauge value. Only undraw or draw what needs to be
771 void XawGaugeSetValue(Widget w, Cardinal value)
773 GaugeWidget gw = (GaugeWidget) w;
777 if (gw->gauge.selected != None) {
778 XtDisownSelection(w, gw->gauge.selected, CurrentTime);
779 gw->gauge.selected = None;
782 if (!XtIsRealized(w)) {
783 gw->gauge.value = value;
787 /* need to rescale? */
788 if ((gw->gauge.autoScaleUp && value > (Cardinal)gw->gauge.v1) ||
789 (gw->gauge.autoScaleDown && value < (Cardinal)gw->gauge.v1 / 3)) {
790 XtVaSetValues(w, XtNvalue, value, NULL);
794 oldvalue = gw->gauge.value;
795 gw->gauge.value = value;
797 gc = XtIsSensitive(w) ? gw->label.normal_GC : gw->label.gray_GC;
798 GaugeMercury(XtDisplay(w), XtWindow(w), gc, gw, oldvalue, value);
801 Cardinal XawGaugeGetValue(Widget w)
803 GaugeWidget gw = (GaugeWidget) w;
804 return gw->gauge.value;
807 /****************************************************************
811 ****************************************************************/
813 /* draw the mercury over a specific region */
816 GaugeMercury(Display * dpy,
817 Window win, GC gc, GaugeWidget gw, Cardinal val0, Cardinal val1)
819 int v0 = gw->gauge.v0;
820 int v1 = gw->gauge.v1;
822 Dimension len; /* length (width or height) of gauge */
823 Position e0, e1; /* gauge ends */
824 Position p0, p1; /* mercury ends */
825 int y; /* vertical (horizontal) position */
826 Boolean undraw = FALSE;
828 len = gw->gauge.orientation == XtorientHorizontal ?
829 gw->core.width : gw->core.height;
831 e0 = gw->gauge.margin0; /* left (top) end */
832 e1 = len - gw->gauge.margin1 - 1; /* right (bottom) end */
837 if (val0 < (Cardinal)v0)
839 else if (val0 > (Cardinal)v1)
841 if (val1 < (Cardinal)v0)
843 else if (val1 > (Cardinal)v1)
846 p0 = (val0 - v0) * (e1 - e0 - 1) / vd;
847 p1 = (val1 - v0) * (e1 - e0 - 1) / vd;
852 y = gw->gauge.gmargin;
858 gc = gw->label.normal_GC;
859 XSetForeground(dpy, gc, gw->core.background_pixel);
863 if (gw->gauge.orientation == XtorientHorizontal)
864 XFillRectangle(dpy, win, gc, e0 + p0 + 1, y + 1, p1 - p0,
867 XFillRectangle(dpy, win, gc, y + 1, e1 - p1, GA_WID, p1 - p0);
870 XSetForeground(dpy, gc, gw->label.foreground);
873 /* Search the labels, find the largest one. */
874 /* TODO: handle vertical fonts? */
876 static void MaxLabel(GaugeWidget gw, Dimension * wid, /* max label width */
877 Dimension * hgt, /* max label height */
878 Dimension * w0, /* width of first label */
880 { /* width of last label */
883 XFontStruct *font = gw->label.font;
886 int v0 = gw->gauge.v0;
887 int dv = gw->gauge.v1 - v0;
888 int n = gw->gauge.nlabels;
896 /* loop through all labels, figure out how much room they
900 for (i = 0; i < gw->gauge.nlabels; ++i) {
901 if (gw->gauge.labels == NULL) { /* numeric labels */
902 int sz = snprintf(lbl = lstr, sizeof(lstr),
903 "%d", v0 + i * dv / n);
904 assert(sz >= 0 && (size_t)sz < sizeof(lstr));
906 lbl = gw->gauge.labels[i];
909 lw = XTextWidth(font, lbl, strlen(lbl));
914 if (i == 0 && w0 != NULL)
921 *hgt = font->max_bounds.ascent + font->max_bounds.descent;
926 /* Determine the preferred size for this widget. choose 100x100 for
931 GaugeSize(GaugeWidget gw, Dimension * wid, Dimension * hgt, Dimension min_len)
933 int w, h; /* width, height of gauge */
934 int vmargin; /* vertical margin */
935 int hmargin; /* horizontal margin */
937 hmargin = gw->label.internal_width;
938 vmargin = gw->label.internal_height;
940 /* find total height (width) of contents */
942 /* find minimum size for undecorated gauge */
944 if (gw->gauge.orientation == XtorientHorizontal) {
946 h = GA_WID + 2; /* gauge itself + edges */
952 if (gw->gauge.ntics > 0) {
953 if (gw->gauge.orientation == XtorientHorizontal) {
954 w = Max(w, gw->gauge.ntics * 3);
955 h += vmargin + TIC_LEN;
957 w += hmargin + TIC_LEN;
958 h = Max(h, gw->gauge.ntics * 3);
962 /* If labels are requested, this gets a little interesting.
963 * We want the end labels centered on the ends of the gauge and
964 * the centers of the labels evenly spaced. The labels at the ends
965 * will not be the same width, meaning that the gauge itself need
966 * not be centered in the widget.
968 * First, determine the spacing. This is the width of the widest
969 * label, plus the internal margin. Total length of the gauge is
970 * spacing * (nlabels-1). To this, we add half the width of the
971 * left-most label and half the width of the right-most label
972 * to get the entire desired width of the widget.
974 if (gw->gauge.nlabels > 0) {
975 Dimension lwm, lw0, lw1; /* width of max, left, right labels */
978 MaxLabel(gw, &lwm, &lh, &lw0, &lw1);
980 if (gw->gauge.orientation == XtorientHorizontal) {
982 (lwm + hmargin) * (gw->gauge.nlabels - 1) + (lw0 +
988 lh = lh * gw->gauge.nlabels + (gw->gauge.nlabels -
1002 static void AutoScale(GaugeWidget gw)
1004 static int scales[3] = { 1, 2, 5 };
1005 int sptr = 0, smult = 1;
1007 if (gw->gauge.autoScaleDown)
1009 while (gw->gauge.value > gw->gauge.v1) {
1014 gw->gauge.v1 = scales[sptr] * smult;
1018 static void EnableUpdate(GaugeWidget gw)
1020 gw->gauge.intervalId =
1021 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) gw),
1022 gw->gauge.update * MS_PER_SEC, GaugeGetValue,
1026 static void DisableUpdate(GaugeWidget gw)
1028 XtRemoveTimeOut(gw->gauge.intervalId);
1031 static void GaugeGetValue(XtPointer clientData, XtIntervalId * intervalId)
1033 GaugeWidget gw = (GaugeWidget) clientData;
1036 if (gw->gauge.update > 0)
1039 if (gw->gauge.getValue != NULL) {
1040 XtCallCallbackList((Widget) gw, gw->gauge.getValue,
1041 (XtPointer) & value);
1042 XawGaugeSetValue((Widget) gw, value);
1046 static GC Get_GC(GaugeWidget gw, Pixel fg)
1049 #define vmask GCForeground
1050 #define umask (GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset\
1051 |GCFont|GCDashList|GCArcMode)
1053 values.foreground = fg;
1055 return XtAllocateGC((Widget) gw, 0, vmask, &values, 0L, umask);