/*
 *----------------------------------------------------------------------
 *
 * ConfigureDial --
 *
 *	This procedure is called to process an argv/argc list, plus
 *	the Tk option database, in order to configure (or
 *	reconfigure) a dial widget.
 *
 * Results:
 *	The return value is a standard Tcl result.  If TCL_ERROR is
 *	returned, then interp->result contains an error message.
 *
 * Side effects:
 *	Configuration information, such as colors, border width,
 *	etc. get set for dPtr;  old resources get freed,
 *	if there were any.
 *
 *----------------------------------------------------------------------
 */
static int
ConfigureDial(interp, dPtr, objc, objv, flags)
     Tcl_Interp *interp;	/* Used for error reporting. */
     register TkDial *dPtr;	/* Information about widget; may or may not
				 * already have values for some fields */
     int objc;
     Tcl_Obj *CONST objv[];
     int flags;			/* Flags to pass to Tk_ConfigureWidget. */
{
    Tk_SavedOptions savedOptions;
    Tcl_Obj *errorResult = NULL;
    int error;

    XGCValues gcValues;
    GC newGC;
    unsigned int mask;

    /* Eliminate any existing trace on a variable monitored by the dial.  */
    if (dPtr->varName != NULL) {
	Tcl_UntraceVar(interp, dPtr->varName, 
		       TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
		       DialVarProc, (ClientData) dPtr);
    }

    for (error = 0; error <= 1; error++) {
	if (!error) {
	    /*
	     * First pass: set options to new values.
	     */

	    if (Tk_SetOptions(interp, (char *) dPtr,
		    dPtr->optionTable, objc, objv,
		    dPtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) {
		continue;
	    }
	} else {
	    /*
	     * Second pass: restore options to old values.
	     */

	    errorResult = Tcl_GetObjResult(interp);
	    Tcl_IncrRefCount(errorResult);
	    Tk_RestoreSavedOptions(&savedOptions);
	}

	/*
	 * A few other options also need special processing, such as parsing
	 * the geometry and setting the background from a 3-D border.
	 */

	dPtr->tickInterval	= fabs(dPtr->tickInterval);
	dPtr->minTickInterval = fabs(dPtr->minTickInterval);
	dPtr->tickWidth	= MAX(dPtr->tickWidth, 0);

	break;
    }
    if (!error) {
	Tk_FreeSavedOptions(&savedOptions);
    }

    /*
     * If the dial is tied to the value of a variable, then set up
     * a trace on the variable's value and set the dial's value from
     * the value of the variable, if it exists.
     */
    if (dPtr->varName != NULL) {
	char *stringValue, *end;
	double value;

	stringValue = Tcl_GetVar(interp, dPtr->varName, TCL_GLOBAL_ONLY);
	if (stringValue != NULL) {
	    value = strtod(stringValue, &end);
	    if ((end != stringValue) && (*end == 0)) {
		dPtr->value = value;
	    }
	}
	Tcl_TraceVar(interp, dPtr->varName,
		     TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
		     DialVarProc, (ClientData) dPtr);
    }

    /*
     * Set the dial value to itself;  all this does is to make sure
     * that the dial's value is within the new acceptable range for
     * the dial and reflect the value in the associated variable,
     * if any.
     */
    ComputeFormat(dPtr);
    SetDialValue(dPtr, dPtr->value, 1, 1);

    /* Create GC's */
    gcValues.foreground = dPtr->tickColorPtr->pixel;
    gcValues.line_width = dPtr->tickWidth;
    newGC = Tk_GetGC(dPtr->tkwin, GCForeground|GCLineWidth, &gcValues);
    if (dPtr->tickGC != None) {
	Tk_FreeGC(dPtr->display, dPtr->tickGC);
    }
    dPtr->tickGC = newGC;

    gcValues.foreground = dPtr->needleColorPtr->pixel;
    mask = GCForeground;
    if (dPtr->needleType == NEEDLE_LINE) {
	/* we only want line needles to have a width */
	gcValues.line_width = (int)rint(NEEDLE_WIDTH*dPtr->reqRadius);
	mask |= GCLineWidth;
    }
    newGC = Tk_GetGC(dPtr->tkwin, mask, &gcValues);
    if (dPtr->needleGC != None) {
	Tk_FreeGC(dPtr->display, dPtr->needleGC);
    }
    dPtr->needleGC = newGC;

    if (dPtr->highlightWidth < 0) {
	dPtr->highlightWidth = 0;
    }
    gcValues.font = Tk_FontId(dPtr->tkfont);
    gcValues.foreground = dPtr->textColorPtr->pixel;
    gcValues.graphics_exposures = False;
    newGC = Tk_GetGC(dPtr->tkwin, GCForeground|GCFont|GCGraphicsExposures,
		     &gcValues);
    if (dPtr->textGC != None) {
	Tk_FreeGC(dPtr->display, dPtr->textGC);
    }
    dPtr->textGC = newGC;

    dPtr->inset = dPtr->highlightWidth + dPtr->borderWidth;

    /*
     * Recompute display-related information, and let the geometry
     * manager know how much space is needed now.
     */
    Tk_SetBackgroundFromBorder(dPtr->tkwin, dPtr->bgBorder);
    ComputeDialGeometry(dPtr);
    Tk_SetInternalBorder(dPtr->tkwin, dPtr->inset);
    EventuallyRedrawDial(dPtr, REDRAW_ALL);
    if (error) {
	Tcl_SetObjResult(interp, errorResult);
	Tcl_DecrRefCount(errorResult);
	return TCL_ERROR;
    } else {
	return TCL_OK;
    }
}
