/*
 * @(#)DialSq.c
 *
 * Copyright 1994 - 2008  David A. Bagley, bagleyd AT verizon.net
 *
 * All rights reserved.
 *
 * Permission to use, copy, modify, and distribute this software and
 * its documentation for any purpose and without fee is hereby granted,
 * provided that the above copyright notice appear in all copies and
 * that both that copyright notice and this permission notice appear in
 * supporting documentation, and that the name of the author not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * This program is distributed in the hope that it will be "useful",
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */

/* Methods file for Square Dial */

#include "DialSqP.h"

static void initializeSquareDial(Widget request, Widget renew);
static void resizeSquareDial(SquareDialWidget w);

/* Not sure why DialSq.ad is not working. */
/*#define SETVAL 1*/
#ifdef SETVAL
static Boolean setValuesSquareDial(Widget current, Widget request,
		Widget renew);
#endif
/*#define RESOURCES 1*/
#ifdef RESOURCES
static XtResource resourcesSquareDial[] =
{
	{XtNwidth, XtCWidth, XtRDimension, sizeof(Dimension),
	 XtOffset(DialWidget, core.width),
	 XtRString, (caddr_t) "100"},
	{XtNheight, XtCHeight, XtRDimension, sizeof(Dimension),
	 XtOffset(DialWidget, core.height),
	 XtRString, (caddr_t) "100"},
	{XtNforeground, XtCForeground, XtRPixel, sizeof(Pixel),
	 XtOffset(DialWidget, dial.foreground),
	 XtRString, (caddr_t) XtDefaultForeground},
	{XtNbackground, XtCBackground, XtRPixel, sizeof (Pixel),
	 XtOffset(DialWidget, dial.background),
	 XtRString, (caddr_t) XtDefaultBackground},
	{XtNindicatorColor, XtCColor, XtRPixel, sizeof(Pixel),
	 XtOffset(DialWidget, dial.indicatorColor),
	 XtRString, (caddr_t) "Blue"},
	{XtNmarkerColor, XtCColor, XtRPixel, sizeof(Pixel),
	 XtOffset(DialWidget, dial.markerColor),
	 XtRString, (caddr_t) "Green"},
	{XtNmarkers, XtCMarkers, XtRInt, sizeof(int),
	 XtOffset(DialWidget, dial.markers),
	 XtRString, (caddr_t) "17"},
	{XtNmaxDegree, XtCMaxDegree, XtRInt, sizeof(int),
	 XtOffset(DialWidget, dial.maxDegree),
	 XtRString, (caddr_t) "270"},
	{XtNfactor, XtCFactor, XtRInt, sizeof(int),
	 XtOffset(DialWidget, dial.factor),
	 XtRString, (caddr_t) "100"},
	{XtNminimum, XtCMinimum, XtRInt, sizeof(int),
	 XtOffset(DialWidget, dial.minimum),
	 XtRString, (caddr_t) "0"},
	{XtNmaximum, XtCMaximum, XtRInt, sizeof(int),
	 XtOffset(DialWidget, dial.maximum),
	 XtRString, (caddr_t) "100"},
	{XtNmarkerLength, XtCPosition, XtRPosition, sizeof(Position),
	 XtOffset(DialWidget, dial.markerLength),
	 XtRString, (caddr_t) "10"},
	{XtNval, XtCVal, XtRInt, sizeof(int),
	 XtOffset(DialWidget, dial.val),
	 XtRString, (caddr_t) "0"},
	{XtNversionOnly, XtCBoolean, XtRBoolean, sizeof (Boolean),
	 XtOffset(DialWidget, dial.versionOnly),
	 XtRString, (caddr_t) "FALSE"},
	{XtNmenu, XtCMenu, XtRInt, sizeof (int),
	 XtOffset(DialWidget, dial.menu),
	 XtRString, (caddr_t) "999"}, /* ACTION_IGNORE */
	{XtNpixmapSize, XtCPixmapSize, XtRInt, sizeof (int),
	 XtOffset(DialWidget, dial.pixmapSize),
	 XtRString, (caddr_t) "64"},
	{XtNselectCallback, XtCCallback, XtRCallback, sizeof(caddr_t),
	 XtOffset(DialWidget, dial.select),
	 XtRCallback, (caddr_t) NULL}
};
#endif

SquareDialClassRec squareDialClassRec =
{
	{
		(WidgetClass) & dialClassRec,		/* superclass */
		(char *) "DialSq",	/* class name */
		sizeof(SquareDialRec),	/* widget size */
		NULL,		/* class initialize */
		NULL,		/* class part initialize */
		FALSE,		/* class inited */
		(XtInitProc) initializeSquareDial,	/* initialize */
		NULL,		/* initialize hook */
		XtInheritRealize,	/* realize */
		NULL,		/* actions */
		0,		/* num actions */
#ifdef RESOURCES
		resourcesSquareDial,	/* resources */
		XtNumber(resourcesSquareDial),	/* num resources */
#else
		NULL,		/* resources */
		0,		/* num resources */
#endif
		NULLQUARK,	/* xrm class */
		TRUE,		/* compress motion */
		TRUE,		/* compress exposure */
		TRUE,		/* compress enterleave */
		TRUE,		/* visible interest */
		NULL,		/* destroy */
		(XtWidgetProc) resizeSquareDial,	/* resize */
		XtInheritExpose,	/* expose */
#ifdef SETVAL
		(XtSetValuesFunc) setValuesSquareDial,	/* set values */
#else
		NULL,		/* set values */
#endif
		NULL,		/* set values hook */
		XtInheritSetValuesAlmost,	/* set values almost */
		NULL,		/* get values hook */
		XtInheritAcceptFocus,	/* accept focus */
		XtVersion,	/* version */
		NULL,		/* callback private */
		XtInheritTranslations,	/* tm table */
		NULL,		/* query geometry */
		NULL,		/* display accelerator */
		NULL		/* extension */
	},
	{
		0		/* ignore */
	},
	{
		0		/* ignore */
	}
};

WidgetClass squareDialWidgetClass = (WidgetClass) &squareDialClassRec;

static void
initializeSquareDial(Widget request, Widget renew)
{
	SquareDialWidget w = (SquareDialWidget) renew;

	resizeSquareDial(w);
}

static void
resizeSquareDial(SquareDialWidget w)
{
	int marks_per_side = 0, h_increment, v_increment, i;
	int h_offset, v_offset;
	XSegment *ptr;

	ptr = w->dial.segments;
	w->dial.center.x = w->core.width / 2;
	w->dial.center.y = w->core.height / 2;
	w->dial.dialRadius = 9 * MIN(w->core.width, w->core.height) / 20;
	/* Approximating */
	if (w->dial.maxDegree <= 90) {
		marks_per_side = w->dial.markers + 1;
		w->dial.markers = marks_per_side + 1;
	} else if (w->dial.maxDegree <= 180) {
		marks_per_side = w->dial.markers / 2;
		w->dial.markers = marks_per_side * 2;
	} else if (w->dial.maxDegree <= 270) {
		marks_per_side = w->dial.markers / 3;
		w->dial.markers = marks_per_side * 3;
	} else {
		marks_per_side = w->dial.markers / 4;
		w->dial.markers = marks_per_side * 4;
	}
	h_increment = (int) w->core.width / (marks_per_side + 1);
	h_offset = ((int) w->core.width -
		h_increment * (marks_per_side + 1)) / 2;
	v_increment = (int) w->core.height / (marks_per_side + 1);
	v_offset = ((int) w->core.height -
		v_increment * (marks_per_side + 1)) / 2;
	for (i = 1; i <= marks_per_side; i++) {
		ptr->x1 = i * h_increment + h_offset;
		ptr->y1 = 2;
		ptr->x2 = i * h_increment + h_offset;
		ptr++->y2 = w->dial.markerLength + 2;
	}
	if (w->dial.maxDegree > 90) {
		for (i = 1; i <= marks_per_side; i++) {
			if (w->dial.maxDegree <= 180 &&
					i - 1 >= marks_per_side / 2)
				break;
			ptr->x1 = 2;
			ptr->y1 = i * v_increment + v_offset;
			ptr->x2 = w->dial.markerLength + 2;
			ptr++->y2 = i * v_increment + v_offset;
		}
		for (i = 1; i <= marks_per_side; i++) {
			if (w->dial.maxDegree <= 180 &&
					i - 1 >= marks_per_side / 2)
				break;
			ptr->x1 = w->core.width - w->dial.markerLength - 3;
			ptr->y1 = i * v_increment + v_offset;
			ptr->x2 = w->core.width - 3;
			ptr++->y2 = i * v_increment + v_offset;
		}
		if (w->dial.maxDegree > 270) {
			for (i = 1; i <= marks_per_side; i++) {
				ptr->x1 = w->core.width - i * h_increment +
					h_offset;
				ptr->y1 = w->core.height -
					w->dial.markerLength - 3;
				ptr->x2 = w->core.width - i * h_increment +
					h_offset;
				ptr++->y2 = w->core.height - 3;
			}
		}
	}
	calculateDial((DialWidget) w);
}

#ifdef SETVAL
static Boolean
setValuesSquareDial(Widget current, Widget request, Widget renew)
{
	SquareDialWidget c = (SquareDialWidget) current;
	SquareDialWidget w = (SquareDialWidget) renew;
	XGCValues values;
	XtGCMask valueMask;
	Boolean redraw = FALSE;
	Boolean redraw_indicator = FALSE;

	if (w->dial.indicatorColor != c->dial.indicatorColor ||
			w->core.background_pixel != c->core.background_pixel) {
		valueMask = GCForeground | GCBackground;
		values.foreground = w->dial.indicatorColor;
		values.background = w->core.background_pixel;
		XtReleaseGC(renew, w->dial.indicatorGC);
		w->dial.indicatorGC = XtGetGC(renew, valueMask, &values);
		values.foreground = w->core.background_pixel;
		values.background = w->dial.indicatorColor;
		XtReleaseGC(renew, w->dial.inverseGC);
		w->dial.inverseGC = XtGetGC(renew, valueMask, &values);
		redraw_indicator = TRUE;
	}
	if (w->dial.foreground != c->dial.foreground) {
		valueMask = GCForeground | GCBackground;
		values.foreground = w->dial.foreground;
		values.background = w->core.background_pixel;
		XtReleaseGC(renew, w->dial.dialGC);
		w->dial.dialGC = XtGetGC(renew, valueMask, &values);
		redraw = TRUE;
	}
	return (redraw);
}
#endif
