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;
383 /* if the gauge is selected, signify by drawing the background
384 * in a contrasting color.
387 if (gw->gauge.selected) {
388 XFillRectangle(dpy, win, gc, 0, 0, w->core.width,
390 gc = gw->gauge.inverse_GC;
393 e0 = gw->gauge.margin0; /* left (top) end */
394 e1 = len - gw->gauge.margin1 - 1; /* right (bottom) end */
396 /* Draw the Gauge itself */
398 y = gw->gauge.gmargin;
400 if (gw->gauge.orientation == XtorientHorizontal) { /* horizontal */
401 XDrawLine(dpy, win, gctop, e0 + 1, y, e1 - 1, y);
402 XDrawLine(dpy, win, gctop, e0, y + 1, e0, y + GA_WID);
403 XDrawLine(dpy, win, gcbot, e0 + 1, y + GA_WID + 1, e1 - 1,
405 XDrawLine(dpy, win, gcbot, e1, y + 1, e1, y + GA_WID);
406 } else { /* vertical */
408 XDrawLine(dpy, win, gctop, y, e0 + 1, y, e1 - 1);
409 XDrawLine(dpy, win, gctop, y + 1, e0, y + GA_WID, e0);
410 XDrawLine(dpy, win, gcbot, y + GA_WID + 1, e0 + 1,
411 y + GA_WID + 1, e1 - 1);
412 XDrawLine(dpy, win, gcbot, y + 1, e1, y + GA_WID, e1);
415 /* draw the mercury */
417 GaugeMercury(dpy, win, gc, gw, 0, value);
419 if (gw->gauge.ntics > 1) {
420 y = gw->gauge.tmargin;
421 for (i = 0; i < gw->gauge.ntics; ++i) {
422 x = e0 + i * (e1 - e0 - 1) / (gw->gauge.ntics - 1);
423 if (gw->gauge.orientation == XtorientHorizontal) {
424 XDrawLine(dpy, win, gcbot, x, y + 1, x,
426 XDrawLine(dpy, win, gcbot, x, y, x + 1, y);
427 XDrawLine(dpy, win, gctop, x + 1, y + 1, x + 1,
429 XDrawLine(dpy, win, gctop, x, y + TIC_LEN - 1,
430 x + 1, y + TIC_LEN - 1);
432 XDrawLine(dpy, win, gcbot, y + 1, x,
434 XDrawLine(dpy, win, gcbot, y, x, y, x + 1);
435 XDrawLine(dpy, win, gctop, y + 1, x + 1,
436 y + TIC_LEN - 2, x + 1);
437 XDrawLine(dpy, win, gctop, y + TIC_LEN - 1, x,
438 y + TIC_LEN - 1, x + 1);
444 if (gw->gauge.nlabels > 1) {
445 char label[sizeof(long)*3+1], *s = label;
446 int xlen, wd, h = 0, n;
448 if (gw->gauge.orientation == XtorientHorizontal)
449 y = gw->gauge.lmargin +
450 gw->label.font->max_bounds.ascent - 1;
452 y = gw->gauge.lmargin;
453 h = gw->label.font->max_bounds.ascent / 2;
456 for (i = 0; i < gw->gauge.nlabels; ++i) {
457 if (gw->gauge.labels == NULL) {
458 n = snprintf(label, sizeof(label),
461 (gw->gauge.nlabels - 1));
462 assert(n >= 0 && (size_t)n < sizeof(label));
465 s = gw->gauge.labels[i];
467 x = e0 + i * (e1 - e0 - 1) /
468 (gw->gauge.nlabels - 1);
470 if (gw->gauge.orientation == XtorientHorizontal) {
471 wd = XTextWidth(gw->label.font, s,
473 XDrawString(dpy, win, gc, x - wd / 2, y,
476 XDrawString(dpy, win, gc, y, x + h, s,
485 * Set specified arguments into widget
489 GaugeSetValues(Widget old,
490 Widget request, Widget new, ArgList args, Cardinal * num_args)
492 GaugeWidget oldgw = (GaugeWidget) old;
493 GaugeWidget gw = (GaugeWidget) new;
494 Boolean was_resized = False;
496 if (gw->gauge.selected != None) {
497 XtDisownSelection(new, gw->gauge.selected, CurrentTime);
498 gw->gauge.selected = None;
501 /* Changes to v0,v1,labels, ntics, nlabels require resize & redraw. */
502 /* Change to value requires redraw and possible resize if autoscale */
505 gw->gauge.v0 != oldgw->gauge.v0 ||
506 gw->gauge.v1 != oldgw->gauge.v1 ||
507 gw->gauge.ntics != oldgw->gauge.ntics ||
508 gw->gauge.nlabels != oldgw->gauge.nlabels ||
509 gw->gauge.labels != oldgw->gauge.labels;
511 if ((gw->gauge.autoScaleUp && gw->gauge.value > gw->gauge.v1) ||
512 (gw->gauge.autoScaleDown && gw->gauge.value < gw->gauge.v1 / 3)) {
518 if (gw->label.resize)
519 GaugeSize(gw, &gw->core.width, &gw->core.height,
525 if (gw->gauge.update != oldgw->gauge.update) {
526 if (gw->gauge.update > 0)
532 if (gw->core.background_pixel != oldgw->core.background_pixel) {
533 XtReleaseGC(new, gw->gauge.inverse_GC);
534 gw->gauge.inverse_GC = Get_GC(gw, gw->core.background_pixel);
537 return was_resized || gw->gauge.value != oldgw->gauge.value ||
538 XtIsSensitive(old) != XtIsSensitive(new);
541 static XtGeometryResult
542 GaugeQueryGeometry(Widget w,
543 XtWidgetGeometry * intended, XtWidgetGeometry * preferred)
545 register GaugeWidget gw = (GaugeWidget) w;
547 if (intended->width == w->core.width &&
548 intended->height == w->core.height)
551 preferred->request_mode = CWWidth | CWHeight;
552 GaugeSize(gw, &preferred->width, &preferred->height, DEF_LEN);
554 if ((!(intended->request_mode & CWWidth) ||
555 intended->width >= preferred->width) &&
556 (!(intended->request_mode & CWHeight) ||
557 intended->height >= preferred->height))
558 return XtGeometryYes;
560 return XtGeometryAlmost;
563 /****************************************************************
567 ****************************************************************/
570 GaugeSelect(Widget w, XEvent * event, String * params, Cardinal * num_params)
572 GaugeWidget gw = (GaugeWidget) w;
573 Atom seln = XA_PRIMARY;
575 if (gw->gauge.selected != None) {
576 XtDisownSelection(w, gw->gauge.selected, CurrentTime);
577 gw->gauge.selected = None;
580 if (*num_params > 0) {
581 seln = XInternAtom(XtDisplay(w), params[0], False);
582 printf("atom %s is %ld\n", params[0], seln);
585 if (!XtOwnSelection(w, seln, event->xbutton.time, GaugeConvert,
586 GaugeLoseSel, GaugeDoneSel)) {
587 /* in real code, this error message would be replaced by
588 * something more elegant, or at least deleted
591 fprintf(stderr, "Gauge failed to get selection, try again\n");
594 const int max_selstr = 4 * sizeof(int);
595 gw->gauge.selected = TRUE;
596 gw->gauge.selstr = (String) XtMalloc(max_selstr);
597 n = snprintf(gw->gauge.selstr, max_selstr, "%d", gw->gauge.value);
598 assert(n >= 0 && n < max_selstr);
599 GaugeExpose(w, 0, 0);
603 static Boolean GaugeConvert(Widget w, Atom * selection, /* usually XA_PRIMARY */
604 Atom * target, /* requested target */
605 Atom * type, /* returned type */
606 XtPointer * value, /* returned value */
607 unsigned long *length, /* returned length */
609 { /* returned format */
610 GaugeWidget gw = (GaugeWidget) w;
611 XSelectionRequestEvent *req;
613 printf("requesting selection %s:%s\n",
614 XGetAtomName(XtDisplay(w), *selection),
615 XGetAtomName(XtDisplay(w), *target));
618 if (*target == XA_TARGETS(XtDisplay(w))) {
621 unsigned long stdLength;
623 /* XmuConvertStandardSelection can handle this. This function
624 * will return a list of standard targets. We prepend TEXT,
625 * STRING and INTEGER to the list and return it.
628 req = XtGetSelectionRequest(w, *selection, NULL);
629 XmuConvertStandardSelection(w, req->time, selection, target,
633 *type = XA_ATOM; /* TODO: needed? */
634 *length = stdLength + 3;
635 rval = (Atom *) XtMalloc(sizeof(Atom) * (stdLength + 3));
636 *value = (XtPointer) rval;
637 *rval++ = XA_INTEGER;
639 *rval++ = XA_TEXT(XtDisplay(w));
640 memcpy((char *)rval, (char *)stdTargets,
641 stdLength * sizeof(Atom));
642 XtFree((char *)stdTargets);
643 *format = 8 * sizeof(Atom); /* TODO: needed? */
649 if (*target == XA_INTEGER) {
652 *value = (XtPointer) & gw->gauge.value;
653 *format = 8 * sizeof(int);
657 else if (*target == XA_STRING
659 || *target == XA_TEXT(XtDisplay(w))
663 *length = strlen(gw->gauge.selstr) * sizeof(char);
664 *value = (XtPointer) gw->gauge.selstr;
670 /* anything else, we just give it to XmuConvertStandardSelection() */
672 req = XtGetSelectionRequest(w, *selection, NULL);
673 if (XmuConvertStandardSelection(w, req->time, selection, target,
674 type, (XPointer *) value,
681 ("Gauge: requestor is requesting unsupported selection %s:%s\n",
682 XGetAtomName(XtDisplay(w), *selection),
683 XGetAtomName(XtDisplay(w), *target));
689 static void GaugeLoseSel(Widget w, Atom * selection)
690 { /* usually XA_PRIMARY */
691 GaugeWidget gw = (GaugeWidget) w;
692 Display *dpy = XtDisplay(w);
693 Window win = XtWindow(w);
695 if (gw->gauge.selstr != NULL) {
696 XtFree(gw->gauge.selstr);
697 gw->gauge.selstr = NULL;
700 gw->gauge.selected = False;
701 XClearWindow(dpy, win);
702 GaugeExpose(w, 0, 0);
705 static void GaugeDoneSel(Widget w, Atom * selection, /* usually XA_PRIMARY */
707 { /* requested target */
708 /* selection done, anything to do? */
712 GaugePaste(Widget w, XEvent * event, String * params, Cardinal * num_params)
714 Atom seln = XA_PRIMARY;
716 if (*num_params > 0) {
717 seln = XInternAtom(XtDisplay(w), params[0], False);
718 printf("atom %s is %ld\n", params[0], seln);
721 /* try for integer value first */
722 XtGetSelectionValue(w, seln, XA_INTEGER,
723 GaugeGetSelCB, (XtPointer) XA_INTEGER,
724 event->xbutton.time);
728 GaugeGetSelCB(Widget w,
731 Atom * type, XtPointer value, unsigned long *length, int *format)
733 Display *dpy = XtDisplay(w);
734 Atom target = (Atom) client;
738 if (*type == XA_INTEGER) {
740 XawGaugeSetValue(w, *iptr);
743 else if (*type == XA_STRING
745 || *type == XA_TEXT(dpy)
748 cptr = (char *)value;
749 XawGaugeSetValue(w, atoi(cptr));
752 /* failed, try string */
753 else if (*type == None && target == XA_INTEGER)
754 XtGetSelectionValue(w, *selection, XA_STRING,
755 GaugeGetSelCB, (XtPointer) XA_STRING,
759 /****************************************************************
763 ****************************************************************/
765 /* Change gauge value. Only undraw or draw what needs to be
769 void XawGaugeSetValue(Widget w, Cardinal value)
771 GaugeWidget gw = (GaugeWidget) w;
775 if (gw->gauge.selected != None) {
776 XtDisownSelection(w, gw->gauge.selected, CurrentTime);
777 gw->gauge.selected = None;
780 if (!XtIsRealized(w)) {
781 gw->gauge.value = value;
785 /* need to rescale? */
786 if ((gw->gauge.autoScaleUp && value > (Cardinal)gw->gauge.v1) ||
787 (gw->gauge.autoScaleDown && value < (Cardinal)gw->gauge.v1 / 3)) {
788 XtVaSetValues(w, XtNvalue, value, NULL);
792 oldvalue = gw->gauge.value;
793 gw->gauge.value = value;
795 gc = XtIsSensitive(w) ? gw->label.normal_GC : gw->label.gray_GC;
796 GaugeMercury(XtDisplay(w), XtWindow(w), gc, gw, oldvalue, value);
799 Cardinal XawGaugeGetValue(Widget w)
801 GaugeWidget gw = (GaugeWidget) w;
802 return gw->gauge.value;
805 /****************************************************************
809 ****************************************************************/
811 /* draw the mercury over a specific region */
814 GaugeMercury(Display * dpy,
815 Window win, GC gc, GaugeWidget gw, Cardinal val0, Cardinal val1)
817 int v0 = gw->gauge.v0;
818 int v1 = gw->gauge.v1;
820 Dimension len; /* length (width or height) of gauge */
821 Position e0, e1; /* gauge ends */
822 Position p0, p1; /* mercury ends */
823 int y; /* vertical (horizontal) position */
824 Boolean undraw = FALSE;
826 len = gw->gauge.orientation == XtorientHorizontal ?
827 gw->core.width : gw->core.height;
829 e0 = gw->gauge.margin0; /* left (top) end */
830 e1 = len - gw->gauge.margin1 - 1; /* right (bottom) end */
835 if (val0 < (Cardinal)v0)
837 else if (val0 > (Cardinal)v1)
839 if (val1 < (Cardinal)v0)
841 else if (val1 > (Cardinal)v1)
844 p0 = (val0 - v0) * (e1 - e0 - 1) / vd;
845 p1 = (val1 - v0) * (e1 - e0 - 1) / vd;
850 y = gw->gauge.gmargin;
856 gc = gw->label.normal_GC;
857 XSetForeground(dpy, gc, gw->core.background_pixel);
861 if (gw->gauge.orientation == XtorientHorizontal)
862 XFillRectangle(dpy, win, gc, e0 + p0 + 1, y + 1, p1 - p0,
865 XFillRectangle(dpy, win, gc, y + 1, e1 - p1, GA_WID, p1 - p0);
868 XSetForeground(dpy, gc, gw->label.foreground);
871 /* Search the labels, find the largest one. */
872 /* TODO: handle vertical fonts? */
874 static void MaxLabel(GaugeWidget gw, Dimension * wid, /* max label width */
875 Dimension * hgt, /* max label height */
876 Dimension * w0, /* width of first label */
878 { /* width of last label */
881 XFontStruct *font = gw->label.font;
884 int v0 = gw->gauge.v0;
885 int dv = gw->gauge.v1 - v0;
886 int n = gw->gauge.nlabels;
894 /* loop through all labels, figure out how much room they
898 for (i = 0; i < gw->gauge.nlabels; ++i) {
899 if (gw->gauge.labels == NULL) { /* numeric labels */
900 int sz = snprintf(lbl = lstr, sizeof(lstr),
901 "%d", v0 + i * dv / n);
902 assert(sz >= 0 && (size_t)sz < sizeof(lstr));
904 lbl = gw->gauge.labels[i];
907 lw = XTextWidth(font, lbl, strlen(lbl));
912 if (i == 0 && w0 != NULL)
919 *hgt = font->max_bounds.ascent + font->max_bounds.descent;
924 /* Determine the preferred size for this widget. choose 100x100 for
929 GaugeSize(GaugeWidget gw, Dimension * wid, Dimension * hgt, Dimension min_len)
931 int w, h; /* width, height of gauge */
932 int vmargin; /* vertical margin */
933 int hmargin; /* horizontal margin */
935 hmargin = gw->label.internal_width;
936 vmargin = gw->label.internal_height;
938 /* find total height (width) of contents */
940 /* find minimum size for undecorated gauge */
942 if (gw->gauge.orientation == XtorientHorizontal) {
944 h = GA_WID + 2; /* gauge itself + edges */
950 if (gw->gauge.ntics > 0) {
951 if (gw->gauge.orientation == XtorientHorizontal) {
952 w = Max(w, gw->gauge.ntics * 3);
953 h += vmargin + TIC_LEN;
955 w += hmargin + TIC_LEN;
956 h = Max(h, gw->gauge.ntics * 3);
960 /* If labels are requested, this gets a little interesting.
961 * We want the end labels centered on the ends of the gauge and
962 * the centers of the labels evenly spaced. The labels at the ends
963 * will not be the same width, meaning that the gauge itself need
964 * not be centered in the widget.
966 * First, determine the spacing. This is the width of the widest
967 * label, plus the internal margin. Total length of the gauge is
968 * spacing * (nlabels-1). To this, we add half the width of the
969 * left-most label and half the width of the right-most label
970 * to get the entire desired width of the widget.
972 if (gw->gauge.nlabels > 0) {
973 Dimension lwm, lw0, lw1; /* width of max, left, right labels */
976 MaxLabel(gw, &lwm, &lh, &lw0, &lw1);
978 if (gw->gauge.orientation == XtorientHorizontal) {
980 (lwm + hmargin) * (gw->gauge.nlabels - 1) + (lw0 +
986 lh = lh * gw->gauge.nlabels + (gw->gauge.nlabels -
1000 static void AutoScale(GaugeWidget gw)
1002 static int scales[3] = { 1, 2, 5 };
1003 int sptr = 0, smult = 1;
1005 if (gw->gauge.autoScaleDown)
1007 while (gw->gauge.value > gw->gauge.v1) {
1012 gw->gauge.v1 = scales[sptr] * smult;
1016 static void EnableUpdate(GaugeWidget gw)
1018 gw->gauge.intervalId =
1019 XtAppAddTimeOut(XtWidgetToApplicationContext((Widget) gw),
1020 gw->gauge.update * MS_PER_SEC, GaugeGetValue,
1024 static void DisableUpdate(GaugeWidget gw)
1026 XtRemoveTimeOut(gw->gauge.intervalId);
1029 static void GaugeGetValue(XtPointer clientData, XtIntervalId * intervalId)
1031 GaugeWidget gw = (GaugeWidget) clientData;
1034 if (gw->gauge.update > 0)
1037 if (gw->gauge.getValue != NULL) {
1038 XtCallCallbackList((Widget) gw, gw->gauge.getValue,
1039 (XtPointer) & value);
1040 XawGaugeSetValue((Widget) gw, value);
1044 static GC Get_GC(GaugeWidget gw, Pixel fg)
1047 #define vmask GCForeground
1048 #define umask (GCBackground|GCSubwindowMode|GCGraphicsExposures|GCDashOffset\
1049 |GCFont|GCDashList|GCArcMode)
1051 values.foreground = fg;
1053 return XtAllocateGC((Widget) gw, 0, vmask, &values, 0L, umask);