/************************************************************* * * Rheostat.c * Rheostat widget implementation * * Author: Joe English, joe@trystero.art.com * ************************************************************* * * Future enhancements: * * BUG: If you drag the arrow to a position outside the valid * range too quickly, it sticks inside the dial; it should * peg out at the minimum or maximum value. I'm not sure * how to determine which, though... * write query_geometry method. * Add set(value) action * SetValues() doesn't check for as much as it should; * SetValues() and Initialize() need to do MUCH more range checking * When number_intervals is is not a divisor of ValueRange, ticks * aren't drawn where the arrow actually goes. * Do we need a tickThickness resource? */ #include #include #include #include #include "RheostatP.h" #include "Rheostat.h" /*********************************************************************** * * Convenience macros, defaults, and declarations: * ***********************************************************************/ #define RADIANS(d) (M_PI * (d)/ 180.0) #define DEGREES(r) ((r) * 180.0 / M_PI) #define DEG_TO_RAD (180.0 / M_PI) #define RAD_TO_DEG (M_PI / 180.0) #define MIN(x,y) ((x) < (y) ? (x) : (y)) #define MAX(x,y) ((x) > (y) ? (x) : (y)) /* Rheostat-specific: */ #define MinAngle(w) (w->rheostat.minimum_angle) #define MaxAngle(w) (w->rheostat.maximum_angle) #define MinValue(w) (w->rheostat.minimum_value) #define MaxValue(w) (w->rheostat.maximum_value) #define AngleRange(w) (w->rheostat.maximum_angle-w->rheostat.minimum_angle) #define ValueRange(w) (w->rheostat.maximum_value-w->rheostat.minimum_value) #define ValueInc(w) ((w->rheostat.maximum_value-w->rheostat.minimum_value) \ / w->rheostat.number_intervals) #define CenterX(w) ((int)w->core.width/2) #define CenterY(w) ((int)w->core.height/2) /* MARGIN(w) = space from border to radius. */ #define _MARGIN(w) \ ( w->rheostat.outer_margin \ + w->rheostat.tick_length \ + w->rheostat.dial_thickness \ + w->rheostat.inner_margin) #ifdef MOTIF #define MARGIN(w) (_MARGIN(w) \ + w->primitive.highlight_thickness \ + w->primitive.shadow_thickness) #else #define MARGIN(w) _MARGIN(w) #endif /* Cast operator to keep lint/gcc happy: */ #define W (Widget) /* * Default values for various resources: */ #define MIN_RADIUS 2 #define DFLT_RADIUS 30 #define DFLT_OUTER 25 #define DFLT_INNER 20 #define DFLT_WIDTH 20 #define DFLT_ARROWTHICKNESS 0 /* Another good set of defaults: RADIUS=INNER=30, OUTER=15, WIDTH=10 */ #define DFLT_TICKLEN 5 #define DFLT_TICKTHICKNESS 0 #define DFLT_DIALTHICKNESS 3 #define DFLT_MINVALUE 0 #define DFLT_MAXVALUE 100 #define DFLT_MINANGLE 45 #define DFLT_MAXANGLE 315 #define DFLT_NUMTICKS 10 #define DFLT_MARGIN 2 /* * Method functions: */ static void Initialize(); static void Redisplay(); static void Resize(); static void Destroy(); static Boolean SetValues(); /* * Action functions: */ static void Set(); static void Notify(); static void Increment(); /* * Private functions: */ static void draw_arrow (/* RheostatWidget, GC */); static void draw_ticks (/* RheostatWidget, GC */); static void draw_dial (/* RheostatWidget, GC */); static void calculate_position (/* RheostatWidget */); static void get_GCs (/* RheostatWidget */); static void free_GCs (/* RheostatWidget */); static void call_callbacks (/* RheostatWidget *, String, XEvent * */); /*********************************************************************** * * Translation, action, and resource tables: * ***********************************************************************/ #ifdef MOTIF /* use osfXXX instead of XXX */ static char default_translations[] = ": set() \n\ : set() \n\ : notify() \n\ minus: increment(-1) notify() \n\ plus: increment(+1) notify() \n\ osfPageUp: increment(+1i) notify() \n\ osfPageDown: increment(-1i) notify() \n\ Return: notify() \n\ "; #else /* no "virtual keysym" braindamage */ static char default_translations[] = ": set() \n\ : set() \n\ : notify() \n\ minus: increment(-1) notify() \n\ plus: increment(+1) notify() \n\ Prior: increment(-1i) notify() \n\ Next: increment(+1i) notify() \n\ Home: increment(min) notify() \n\ End: increment(max) notify() \n\ Return: notify() \n\ "; #endif static XtActionsRec actions[] = { { "set", (XtActionProc) Set }, { "notify", (XtActionProc) Notify }, { "increment", (XtActionProc) Increment } }; static XtResource resources[] = { # define OFFSET(x) (XtOffset(RheostatWidget, rheostat.x)) {XtNvalue, XtCValue, XtRInt, sizeof(int), OFFSET(value), XtRImmediate, (caddr_t)0}, {XtNminimumValue, XtCMinimum, XtRInt, sizeof(int), OFFSET(minimum_value), XtRImmediate, (caddr_t) DFLT_MINVALUE}, {XtNmaximumValue, XtCMaximum, XtRInt, sizeof(int), OFFSET(maximum_value), XtRImmediate, (caddr_t) DFLT_MAXVALUE}, {XtNminimumAngle, XtCMinimum, XtRInt, sizeof(int), OFFSET(minimum_angle), XtRImmediate, (caddr_t) DFLT_MINANGLE}, {XtNmaximumAngle, XtCMaximum, XtRInt, sizeof(int), OFFSET(maximum_angle), XtRImmediate, (caddr_t) DFLT_MAXANGLE}, {XtNtickGravity, XtCGravity, XtRBoolean, sizeof(Boolean), OFFSET(tick_gravity), XtRImmediate, (caddr_t)True}, {XtNnumberIntervals, XtCNumberIntervals, XtRInt, sizeof(int), OFFSET(number_intervals), XtRImmediate, (caddr_t) DFLT_NUMTICKS}, {XtNresizeArrow, XtCBoolean, XtRBoolean, sizeof(Boolean), OFFSET(resize_arrow), XtRString, "True"}, {XtNsetCallback, XtCCallback, XtRCallback, sizeof(XtPointer), OFFSET(set), XtRCallback, NULL}, {XtNnotify, XtCCallback, XtRCallback, sizeof(XtPointer), OFFSET(notify), XtRCallback, NULL}, {XtNouterMargin, XtCMargin, XtRDimension, sizeof(Dimension), OFFSET(outer_margin), XtRImmediate, (caddr_t) DFLT_MARGIN}, {XtNtickLength, XtCMargin, XtRDimension, sizeof(Dimension), OFFSET(tick_length), XtRImmediate, (caddr_t) DFLT_TICKLEN}, {XtNdialThickness, XtCThickness, XtRDimension, sizeof(Dimension), OFFSET(dial_thickness), XtRImmediate, (caddr_t) DFLT_DIALTHICKNESS}, {XtNinnerMargin, XtCMargin, XtRDimension, sizeof(Dimension), OFFSET(inner_margin), XtRImmediate, (caddr_t) DFLT_MARGIN}, {XtNradius, XtCLength, XtRDimension, sizeof(Dimension), OFFSET(radius), XtRImmediate, (caddr_t) DFLT_RADIUS}, {XtNouterArrowLength, XtCLength, XtRDimension, sizeof(Dimension), OFFSET(outer_arrow_length), XtRImmediate, (caddr_t) DFLT_OUTER}, {XtNinnerArrowLength, XtCLength, XtRDimension, sizeof(Dimension), OFFSET(inner_arrow_length), XtRImmediate, (caddr_t) DFLT_INNER}, {XtNarrowWidth, XtCWidth, XtRDimension, sizeof(Dimension), OFFSET(arrow_width), XtRImmediate, (caddr_t) DFLT_WIDTH}, {XtNfillArrow, XtCBoolean, XtRBoolean, sizeof(Boolean), OFFSET(fill_arrow), XtRString, "False" }, {XtNarrowThickness, XtCThickness, XtRDimension, sizeof(Dimension), OFFSET(arrow_thickness), XtRImmediate, (caddr_t) DFLT_ARROWTHICKNESS}, {XtNtickThickness, XtCThickness, XtRDimension, sizeof(Dimension), OFFSET(tick_thickness), XtRImmediate, (caddr_t) DFLT_TICKTHICKNESS}, #ifdef MOTIF {XtNuseShadowColors, XtCBoolean, XtRBoolean, sizeof(Boolean), OFFSET(use_shadow_colors), XtRString, "False"}, #endif {XtNarrowColor, XtCForeground, XtRPixel, sizeof(Pixel), OFFSET(arrow_pixel), XtRString, XtDefaultForeground}, {XtNdialColor, XtCForeground, XtRPixel, sizeof(Pixel), OFFSET(dial_pixel), XtRString, XtDefaultForeground}, {XtNtickColor, XtCForeground, XtRPixel, sizeof(Pixel), OFFSET(tick_pixel), XtRString, XtDefaultForeground}, # undef OFFSET }; RheostatClassRec rheostatClassRec = { /* CoreClassPart */ { #ifdef MOTIF /* superclass */ (WidgetClass) &xmPrimitiveClassRec, #else /* superclass */ (WidgetClass) &widgetClassRec, #endif /* class_name */ "Rheostat", /* widget_size */ sizeof(RheostatRec), /* class_initialize */ NULL, /* class_part_initialize */ NULL, /* class_inited */ FALSE, /* initialize */ Initialize, /* initialize_hook */ NULL, /* realize */ XtInheritRealize, /* actions */ actions, /* num_actions */ XtNumber(actions), /* resources */ resources, /* num_resources */ XtNumber(resources), /* xrm_class */ NULLQUARK, /* compress_motion */ TRUE, /* compress_exposure */ TRUE, /* compress_enterleave */ TRUE, /* visible_interest */ TRUE, /* destroy */ Destroy, /* resize */ Resize, /* expose */ Redisplay, /* set_values */ SetValues, /* set_values_hook */ NULL, /* set_values_almost */ XtInheritSetValuesAlmost, /* get_values_hook */ NULL, /* accept_focus */ NULL, /* version */ XtVersion, /* callback private */ NULL, /* tm_table */ default_translations, /* query_geometry */ XtInheritQueryGeometry, /* display_accelerator */ XtInheritDisplayAccelerator, /* extension */ NULL }, #ifdef MOTIF /* Primitive class fields */ { /* border_highlight */ (XtWidgetProc) _XtInherit, /* border_unhighlight */ (XtWidgetProc) _XtInherit, /* translations */ XtInheritTranslations, /* arm_and_activate */ (XmArmAndActivate)Notify, /* syn_resources */ NULL, /* num_syn_resources */ 0, /* extension */ NULL }, #endif /* Rheostat class fields */ { /* ignore */ 0 } }; WidgetClass rheostatWidgetClass = (WidgetClass) &rheostatClassRec; /*********************************************************************** * * Method functions: * **********************************************************************/ /* * Initialize method: */ static void Initialize(request, new) RheostatWidget request, new; { int margin = MARGIN(new); int user_radius = new->rheostat.radius; /* request from user */ int size_radius = /* calculated from size */ MIN(new->core.height,new->core.width)/2 - margin; int min_radius = /* from arrow dimens */ MAX(new->rheostat.inner_arrow_length,new->rheostat.outer_arrow_length); int min_dimen; /* * Check geometry: * Set radius from user value, else widget size, else default. * Make sure radius is >= inner length & outer length. * %%% This is a bit restrictive -- e.g., r=10,i=10,o=12 should be allowed * Make sure width and height are >= 2*(radius + margins) */ if (user_radius != 0) new->rheostat.radius = user_radius; else if (new->core.width != 0 && new->core.height != 0) new->rheostat.radius = size_radius; else new->rheostat.radius = DFLT_RADIUS; /* Make sure radius is large enough: */ if (new->rheostat.radius < min_radius) new->rheostat.radius = min_radius; /* Make sure widget is large enough: */ min_dimen = 2*(new->rheostat.radius+margin); if (new->core.width < min_dimen) new->core.width = min_dimen; if (new->core.height < min_dimen) new->core.height = min_dimen; #ifdef MOTIF if (new->rheostat.use_shadow_colors) { new->rheostat.arrow_pixel = new->primitive.bottom_shadow_color; new->rheostat.dial_pixel = new->primitive.top_shadow_color; } #endif get_GCs(new); calculate_position(new); new->rheostat.orig_radius = new->rheostat.radius; new->rheostat.orig_outer_length = new->rheostat.outer_arrow_length; new->rheostat.orig_inner_length = new->rheostat.inner_arrow_length; new->rheostat.orig_width = new->rheostat.arrow_width; } /* * Destroy method: */ static void Destroy(w) RheostatWidget w; { free_GCs(w); } /* * Resize method: */ static void Resize(w) RheostatWidget w; { int newr; newr = (w->core.height < w->core.width ? w->core.height : w->core.width) / 2 - MARGIN(w); if (newr < 2) newr = 2; if (w->rheostat.resize_arrow) { int oldr = w->rheostat.orig_radius; w->rheostat.outer_arrow_length = (w->rheostat.orig_outer_length * newr) / oldr; w->rheostat.inner_arrow_length = (w->rheostat.orig_inner_length * newr) / oldr; w->rheostat.arrow_width = (w->rheostat.orig_width * newr) / oldr; } w->rheostat.radius = newr; calculate_position(w); } /* * Expose method: */ static void Redisplay(w, event, region) RheostatWidget w; XEvent *event; Region region; { # ifdef MOTIF int hlt = w->primitive.highlight_thickness; _XmDrawShadow(XtDisplay(w), XtWindow(w), w->primitive.top_shadow_GC, w->primitive.bottom_shadow_GC, w->primitive.shadow_thickness, hlt, hlt, w->core.width - 2*hlt, w->core.height - 2*hlt); # endif draw_ticks(w, w->rheostat.tick_GC); draw_dial(w, w->rheostat.dial_GC); draw_arrow(w, w->rheostat.arrow_GC); } /* * SetValues: */ static Boolean SetValues(current, request, new) RheostatWidget current, request, new; { Boolean redraw = FALSE; /* TRUE=>widget needs to be redrawn */ Boolean recalc = FALSE; /* TRUE=>arrow position changed */ # define CHECK(fld) (new->fld != current->fld) /* * Check rheostat parameters: */ if ( CHECK(rheostat.value) || CHECK(rheostat.minimum_value) || CHECK(rheostat.maximum_value) || CHECK(rheostat.maximum_angle) || CHECK(rheostat.minimum_angle) ) { recalc=TRUE; redraw=TRUE; } /* * Bounds check: */ if (new->rheostat.value > new->rheostat.maximum_value) new->rheostat.value = new->rheostat.maximum_value; if (new->rheostat.value < new->rheostat.minimum_value) new->rheostat.value = new->rheostat.minimum_value; /* * Margin, geometry parameters -- may affect radius; */ if ( CHECK(rheostat.outer_margin) || CHECK(rheostat.dial_thickness) || CHECK(rheostat.inner_margin) #ifdef MOTIF || CHECK(primitive.shadow_thickness) || CHECK(primitive.highlight_thickness) #endif ) { int newr = (new->core.height < new->core.width ? new->core.height : new->core.width) / 2 - MARGIN(new); if (newr < MIN_RADIUS) newr = MIN_RADIUS; new->rheostat.radius = newr; recalc=TRUE; } /* * Radius and arrow sizes: */ if ( CHECK(rheostat.radius) || CHECK(rheostat.outer_arrow_length) || CHECK(rheostat.inner_arrow_length) || CHECK(rheostat.arrow_width) ) { new->rheostat.orig_radius = new->rheostat.radius; new->rheostat.orig_outer_length = new->rheostat.outer_arrow_length; new->rheostat.orig_inner_length = new->rheostat.inner_arrow_length; new->rheostat.orig_width = new->rheostat.arrow_width; recalc = TRUE; redraw = TRUE; } /* * Check for color change: */ if ( CHECK(core.background_pixel) || CHECK(rheostat.tick_pixel) || CHECK(rheostat.dial_pixel) || CHECK(rheostat.arrow_pixel) || CHECK(rheostat.arrow_thickness) || CHECK(rheostat.dial_thickness) ) { get_GCs(new); free_GCs(current); redraw = TRUE; } /* * Other display resources: */ if ( CHECK(rheostat.number_intervals) || CHECK(rheostat.fill_arrow) ) { redraw = TRUE; } /* * Wrap up: */ # undef CHECK if (recalc) calculate_position(new); return redraw; } /*********************************************************************** * * Action functions: * ***********************************************************************/ /*ARGSUSED*/ static void Set(w, event, params, nparams) RheostatWidget w; XEvent *event; String *params; Cardinal *nparams; { if (event->type == ButtonPress || event->type == MotionNotify) { int x,y,v; double theta,length,radius; x = event->xbutton.x - CenterX(w); y = event->xbutton.y - CenterY(w); if (!x && !y) /* click at center of widget -- no angle */ return; /* else */ radius = sqrt((double)(x*x + y*y)); /* * Calculate value in range 0 .. 360 */ theta = DEGREES(atan2((double)(-x), (double)(y))); theta -= w->rheostat.minimum_angle; if (theta < 0.0) theta += 360.0; v = (int)( theta * (double)ValueRange(w) / (double)AngleRange(w) ) + w->rheostat.minimum_value; /* * If tick_gravity is on, and click is in tick region, * snap to nearest increment: */ length = (double)(w->rheostat.radius + w->rheostat.inner_margin); if ( w->rheostat.tick_gravity && radius >= length && radius <= length + w->rheostat.dial_thickness + w->rheostat.tick_length) { double inc = ValueInc(w); v = (v / inc + 0.5); v *= inc; } /* * Bounds-check: * Note: v should never be < minimum_value. */ if (v > w->rheostat.maximum_value || v < w->rheostat.minimum_value) return; draw_arrow(w,w->rheostat.eraser_GC); w->rheostat.value = v; calculate_position(w); draw_arrow(w,w->rheostat.arrow_GC); } call_callbacks(w, XtNsetCallback, event); } static void Increment(w, event, params, nparams) RheostatWidget w; XEvent *event; String *params; Cardinal *nparams; { double inc = ValueInc(w); Boolean snap = False; double v; /* * Figure out increment from parameter: */ v = w->rheostat.value; if (*nparams != 1) { /* default: step to nearest interval: */ v += inc; snap = True; } else { if (!strcmp(params[0],"max")) v = w->rheostat.maximum_value; else if (!strcmp(params[0],"min")) v = w->rheostat.minimum_value; else if (!strcmp(params[0],"+1i")) { v += inc; snap = True; } else if (!strcmp(params[0],"-1i")) { v -= inc; snap = True; } else v += atof(params[0]); } if (snap) v = (int)(v / inc + 0.5) * inc; /* * Bounds-check: */ if (v > w->rheostat.maximum_value) v = w->rheostat.maximum_value; if (v < w->rheostat.minimum_value) v = w->rheostat.minimum_value; draw_arrow(w,w->rheostat.eraser_GC); w->rheostat.value = v; calculate_position(w); draw_arrow(w,w->rheostat.arrow_GC); call_callbacks(w,XtNsetCallback,event); } /*ARGSUSED*/ static void Notify(w, event, params, nparams) RheostatWidget w; XEvent *event; String *params; Cardinal *nparams; { call_callbacks(w, XtNnotify, event); } /*********************************************************************** * * Utility routines: * ***********************************************************************/ static void call_callbacks(w, callback_name, event) RheostatWidget w; char *callback_name; XEvent *event; { RheostatCallbackStruct cb; cb.reason = 0; /* this is never used, even under Motif */ cb.event = event; cb.value = w->rheostat.value; XtCallCallbacks(W w, callback_name, (XtPointer)&cb); } static void draw_arrow(w, gc) RheostatWidget w; GC gc; { XfwfDrawArrow(XtDisplay(w), XtWindow(w), gc, w->rheostat.tip_x, w->rheostat.tip_y, w->rheostat.tip_x - CenterX(w), w->rheostat.tip_y - CenterY(w), w->rheostat.outer_arrow_length, w->rheostat.inner_arrow_length, w->rheostat.arrow_width, w->rheostat.fill_arrow); } static void draw_dial(w, gc) RheostatWidget w; GC gc; { int radius = w->rheostat.radius + w->rheostat.inner_margin +(w->rheostat.dial_thickness+1) / 2; XDrawArc(XtDisplay(w), XtWindow(w), w->rheostat.dial_GC, CenterX(w) - radius, CenterY(w) - radius, 2*radius, 2*radius, 64 * ((270 - w->rheostat.minimum_angle + 360) % 360), 64 * -AngleRange(w) ); } static void draw_ticks(w, gc) RheostatWidget w; GC gc; { int i,cx,cy; double theta,inc; double ro,ri; /* inner & outer radii of ticks */ if (!w->rheostat.number_intervals) return; /* * %%% should check if minimum_angle == maximum_angle (mod 360), * so the last tick doesn't coincide with the first. */ inc = RADIANS((double)AngleRange(w))/(double)(w->rheostat.number_intervals); ri = (double)(w->rheostat.radius + w->rheostat.inner_margin + (w->rheostat.dial_thickness+1)/2); ro = ri + w->rheostat.tick_length + (w->rheostat.dial_thickness+1)/2; cx = CenterX(w); cy = CenterY(w); /* * Draw segments: */ theta = RADIANS((double)MinAngle(w)); i = w->rheostat.number_intervals + 1; while (i--) { double c = cos(theta); double s = sin(theta); XDrawLine(XtDisplay(w),XtWindow(w),gc, cx - (int)(ro * s), cy + (int)(ro * c), cx - (int)(ri * s), cy + (int)(ri * c)); theta += inc; } } static void calculate_position(w) RheostatWidget w; { double theta,length; length = (double)w->rheostat.radius; /* * Calculate angle: theta = V*(maxTheta-minTheta) / (maxV - minV) + minTheta */ theta = (double)(w->rheostat.value) * (double)(AngleRange(w)) / (double)(ValueRange(w)) + (double)(MinAngle(w)); theta = RADIANS(theta); w->rheostat.tip_x = CenterX(w) - (int)(length * sin(theta)); w->rheostat.tip_y = CenterY(w) + (int)(length * cos(theta)); } /* * get_GCs * allocate foreground & background. GCs. */ static void get_GCs(w) RheostatWidget w; { XGCValues values; XtGCMask mask; /* * dial: */ mask = GCForeground | GCBackground | GCLineWidth | GCCapStyle; values.foreground = w->rheostat.dial_pixel; values.background = w->core.background_pixel; values.line_width = w->rheostat.dial_thickness; values.cap_style = CapRound; w->rheostat.dial_GC = XtGetGC(W w, mask, &values); /* * tick marks: */ mask = GCForeground | GCBackground | GCFunction | GCLineWidth | GCCapStyle; values.foreground = w->rheostat.tick_pixel; values.background = w->core.background_pixel; values.function = GXcopy; values.line_width = w->rheostat.tick_thickness; values.cap_style = CapRound; w->rheostat.tick_GC = XtGetGC(W w, mask, &values); /* * Arrow: */ mask = GCForeground | GCBackground | GCFunction | GCLineWidth | GCCapStyle | GCFillStyle; values.foreground = w->rheostat.arrow_pixel; values.background = w->core.background_pixel; values.line_width = w->rheostat.arrow_thickness; values.cap_style = CapRound; values.fill_style = FillSolid; w->rheostat.arrow_GC = XtGetGC(W w, mask, &values); /* * Eraser (identical to Arrow except fg & bg pixels are swapped): */ values.foreground = w->core.background_pixel; values.background = w->rheostat.arrow_pixel; w->rheostat.eraser_GC = XtGetGC(W w, mask, &values); return; } static void free_GCs(w) RheostatWidget w; { XtReleaseGC(W w,w->rheostat.arrow_GC); XtReleaseGC(W w,w->rheostat.eraser_GC); XtReleaseGC(W w,w->rheostat.dial_GC); XtReleaseGC(W w,w->rheostat.tick_GC); return; } void XfwfDrawArrow(dpy, d, gc, endx, endy, dx, dy, outer_length, inner_length, width, fill) Display *dpy; Drawable d; GC gc; Position endx, endy; /* position of arrow tip */ int dx, dy; /* slope of arrow */ Dimension outer_length; /* distance tip->base */ Dimension inner_length; /* distance tip->inner */ Dimension width; /* distance base->outer points */ Boolean fill; /* True=>fill arrow,False=>outline */ { XPoint points[5]; float scalef = sqrt((double)(dx*dx+dy*dy)); /* normalization factor */ int al = (int)outer_length, bl = (int)inner_length, aw = (int)width / 2, lx = al * dx / scalef, /* distance from tip to base */ ly = al * dy / scalef, mx = bl * dx / scalef, /* distance from tip to middle point */ my = bl * dy / scalef, wx = aw * -dy / scalef, /* distance from base to outer points */ wy = aw * dx / scalef; points[0].x = endx; points[0].y = endy; points[1].x = endx-lx + wx; points[1].y = endy-ly + wy; points[2].x = endx-mx; points[2].y = endy-my; points[3].x = endx-lx - wx; points[3].y = endy-ly - wy; points[4].x = endx; points[4].y = endy; if (fill) XFillPolygon(dpy,d,gc, points,5, inner_length <= outer_length ? Nonconvex : Convex, CoordModeOrigin); else XDrawLines(dpy,d,gc,points,5,CoordModeOrigin); } /*********************************************************************** * * Public functions: * ***********************************************************************/ /* RheostatSetIntCallback() * General-purpose callback function for Rheostat widgets; * gets the position of the Rheostat, sets *(int *)closure */ void XfwfRheostatSetIntCallback(w,closure,call_data) Widget w; XtPointer closure; XtPointer call_data; { *((int *)closure) = ((RheostatCallbackStruct *)call_data)->value; }