/*
 * @(#)xdial.c
 *
 * Copyright 1994 - 2013  David A. Bagley, bagleyd@tux.org
 *
 * 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.
 */

/* Driver file for Dial */

#include "version.h"
static const char aboutHelp[] = {
"Dial Version " VERSION "\n"
"Send bugs (reports or fixes) to the author: "
"David Bagley <bagleyd@tux.org>\n"
"The latest version is at: "
"http://www.tux.org/~bagleyd/puzzles.html"
};

#include "xwin.h"
#include <X11/Shell.h>
#include <X11/cursorfont.h>
#ifdef HAVE_MOTIF
#include <Xm/PanedW.h>
#include <Xm/RowColumn.h>
#include <Xm/Label.h>
#include <Xm/LabelG.h>
#include <Xm/MessageB.h>
#include <Xm/PushBG.h>
#include <Xm/CascadeB.h>
#endif
#include "Dial.h"
#include "DialSq.h"
#ifdef HAVE_XPM
#include <X11/xpm.h>
#ifdef CONSTPIXMAPS
#include "dial.t.xpm"
#include "dial.p.xpm"
#include "dial.s.xpm"
#include "dial.m.xpm"
#include "dial.l.xpm"
#include "dial.xpm"
#else
#include "pixmaps/dial.t.xpm"
#include "pixmaps/dial.p.xpm"
#include "pixmaps/dial.s.xpm"
#include "pixmaps/dial.m.xpm"
#include "pixmaps/dial.l.xpm"
#include "pixmaps/dial.xpm"
#endif
#define RESIZE_XPM(s) ((char **) (((s)<=32)?\
(((s)<=22)?(((s)<=16)?dial_t_xpm:dial_p_xpm):\
(((s)<=24)?dial_s_xpm:dial_m_xpm)):\
(((s)<=48)?dial_l_xpm:dial_xpm)))
#endif
#include "pixmaps/dial.xbm"
#define DEFINE_XBM (char *) dial_bits, dial_width, dial_height

#ifdef HAVE_MOTIF
static Widget tracker;
static Widget aboutDialog;
static Arg args[3];
static char *progDsp;
#endif
#define FILE_NAME_LENGTH 1024
#define TITLE_LENGTH 2048

static Widget dial, dialsq;
#ifndef HAVE_MOTIF
static Widget shell;
static char prog[] = "  TAC";
#endif
static Pixmap pixmap = None;
static Widget topLevel;
static char titleDsp[TITLE_LENGTH] = "";

static void printState(Widget w, int n)
{
	int factor;
	float m = n;

	XtVaGetValues(dial,
		XtNfactor, &factor, NULL);
#ifdef HAVE_MOTIF
	{
		XmString xmstr;

		if (!XtIsSubclass(tracker, xmLabelWidgetClass))
			XtError("PrintState() requires a Label Widget");
		(void) sprintf(titleDsp, "%g      ", m / factor);
		xmstr = XmStringCreateLtoR(titleDsp, XmSTRING_DEFAULT_CHARSET);
		XtVaSetValues(tracker, XmNlabelString, xmstr, NULL);
	}
#else
	(void) sprintf(titleDsp, "%g%s", m / factor, prog);
	XtVaSetValues(w, XtNtitle, titleDsp, NULL);
#endif
}

static void initialize(void)
{
	int n;

	XtVaGetValues(dial,
		XtNval, &n,
		NULL);
	printState(XtParent(dial), n);
	XtVaGetValues(dialsq,
		XtNval, &n,
		NULL);
	printState(XtParent(dialsq), n);
}

static void callbackDial(Widget w, caddr_t clientData,
		dialCallbackStruct *callData)
{
	int reason = callData->reason;
	Widget otherw;

	if (reason == ACTION_HIDE) {
		(void) XIconifyWindow(XtDisplay(topLevel),
			XtWindow(topLevel),
			XScreenNumberOfScreen(XtScreen(topLevel)));
#ifndef HAVE_MOTIF
		(void) XIconifyWindow(XtDisplay(shell),
			XtWindow(shell),
			XScreenNumberOfScreen(XtScreen(shell)));
#endif
		return;
	}
	if (w == dial)
		otherw = dialsq;
	else /* (w == dialsq) */
		otherw = dial;
	XtVaSetValues(w, XtNval, callData->val, NULL);
	XtVaSetValues(otherw, XtNval, callData->val, NULL);
#ifdef HAVE_MOTIF
	printState(tracker, callData->val);
#else
	printState(XtParent(w), callData->val);
	printState(XtParent(otherw), callData->val);
#endif
}

#ifdef HAVE_MOTIF
static void
fileMenuListener(Widget w, void *value, void *clientData)
{
	int val = (int) value;

	if (val == 0)
		exit(0);
}

static void
moveMenuListener(Widget w, void *value, void *clientData)
{
	int val = (int) value + ACTION_INCREMENT;

	XtVaSetValues(dial, XtNmenu, val, NULL);
}

static Widget
createHelp(Widget w, char *text, char *title)
{
	Widget button, messageBox;
	char titleDsp[FILE_NAME_LENGTH + 8];
	XmString titleString = NULL, messageString = NULL, buttonString = NULL;
	static XmStringCharSet charSet =
		(XmStringCharSet) XmSTRING_DEFAULT_CHARSET;

	messageString = XmStringCreateLtoR(text, charSet);
	(void) sprintf(titleDsp, "%s: %s", progDsp, title);
	titleString = XmStringCreateSimple((char *) titleDsp);
	buttonString = XmStringCreateSimple((char *) "OK");
	XtSetArg(args[0], XmNdialogTitle, titleString);
	XtSetArg(args[1], XmNokLabelString, buttonString);
	XtSetArg(args[2], XmNmessageString, messageString);
	messageBox = XmCreateInformationDialog(w, (char *) "helpBox",
		args, 3);
	button = XmMessageBoxGetChild(messageBox, XmDIALOG_CANCEL_BUTTON);
	XtUnmanageChild(button);
	button = XmMessageBoxGetChild(messageBox, XmDIALOG_HELP_BUTTON);
	XtUnmanageChild(button);
	XmStringFree(titleString);
	XmStringFree(buttonString);
	XmStringFree(messageString);
	return messageBox;
}

static void
helpMenuListener(Widget w, XtPointer value, XtPointer clientData)
{
	int val = (int) value;

	switch (val) {
	case 0:
		XtManageChild(aboutDialog);
		break;
	default:
		{
			char *buf;

			intCat(&buf, "helpMenuListener: %d", val);
			XtWarning(buf);
			free(buf);
		}
	}
}
#endif

int
main(int argc, char **argv)
{
	int pixmapSize;
#ifdef HAVE_MOTIF
	Widget menuBar, pullDownMenu, widget;
	Widget menuBarPanel, controlPanel, mainPanel;
	Widget controlRowCol;
	XmString fileString, moveString;
	XmString quitString;
	XmString incrementString, decrementString;

	progDsp = argv[0];
#endif
	topLevel = XtInitialize(argv[0], "Dial",
		NULL, 0, &argc, argv);
#ifdef HAVE_MOTIF
	 menuBarPanel = XtVaCreateManagedWidget("menuBarPanel",
		xmPanedWindowWidgetClass, topLevel,
		XmNseparatorOn, False,
		XmNsashWidth, 1,
		XmNsashHeight, 1, NULL);
	fileString = XmStringCreateSimple((char *) "File");
	moveString = XmStringCreateSimple((char *) "Move");
	menuBar = XmVaCreateSimpleMenuBar(menuBarPanel, (char *) "menuBar",
		XmVaCASCADEBUTTON, fileString, 'F',
		XmVaCASCADEBUTTON, moveString, 'M',
		NULL);
	XmStringFree(fileString);
	XmStringFree(moveString);
	XtManageChild(menuBar);
	quitString = XmStringCreateSimple((char *) "Exit");
	(void) XmVaCreateSimplePulldownMenu(menuBar, (char *) "fileMenu",
		0, fileMenuListener,
		XmVaPUSHBUTTON, quitString, 'x', NULL, NULL,
		NULL);
	XmStringFree(quitString);
	incrementString = XmStringCreateSimple((char *) "Increment");
	decrementString = XmStringCreateSimple((char *) "Decrement");
	(void) XmVaCreateSimplePulldownMenu(menuBar, (char *) "moveMenu",
		1, moveMenuListener,
		XmVaPUSHBUTTON, incrementString, 'I', NULL, NULL,
		XmVaPUSHBUTTON, decrementString, 'D', NULL, NULL,
		NULL);
	XmStringFree(incrementString);
	XmStringFree(decrementString);
	pullDownMenu = XmCreatePulldownMenu(menuBar,
		(char *) "helpPullDown", NULL, 0);
	widget = XtVaCreateManagedWidget("Help",
		xmCascadeButtonWidgetClass, menuBar,
		XmNsubMenuId, pullDownMenu,
		XmNmnemonic, 'H', NULL);
	XtVaSetValues(menuBar, XmNmenuHelpWidget, widget, NULL);
	widget = XtVaCreateManagedWidget("About",
		xmPushButtonGadgetClass, pullDownMenu,
		XmNmnemonic, 'A', NULL);
	XtAddCallback(widget, XmNactivateCallback, helpMenuListener, (char *) 0);
	XtManageChild(menuBar);
	aboutDialog = createHelp(menuBar, (char *) aboutHelp,
		(char *) "About");
	mainPanel = XtCreateManagedWidget("mainPanel",
		xmPanedWindowWidgetClass, menuBarPanel,
		NULL, 0);
	controlPanel = XtVaCreateManagedWidget("controlPanel",
		xmPanedWindowWidgetClass, mainPanel,
		XmNseparatorOn, False,
		XmNsashWidth, 1,
		XmNsashHeight, 1,
		NULL);
	controlRowCol = XtVaCreateManagedWidget("controlRowCol",
		xmRowColumnWidgetClass, controlPanel,
		XmNnumColumns, 1,
		XmNorientation, XmHORIZONTAL,
		XmNpacking, XmPACK_COLUMN, NULL);
	dial = XtCreateManagedWidget("dial",
		dialWidgetClass, mainPanel, NULL, 0);
	XtVaSetValues(dial,
		XtNheight, 100, NULL);
	dialsq = XtCreateManagedWidget("dialsq",
		squareDialWidgetClass, mainPanel, NULL, 0);
	XtVaSetValues(dialsq,
		XtNheight, 100, NULL);
	(void) XtVaCreateManagedWidget("tacText",
		xmLabelGadgetClass, controlRowCol,
		XtVaTypedArg, XmNlabelString, XmRString, "TAC", 4, NULL);
	tracker = XtVaCreateManagedWidget("0     ",
		xmLabelWidgetClass, controlRowCol, NULL);
#else
	shell = XtCreateApplicationShell(argv[0],
		topLevelShellWidgetClass, NULL, 0);
	dial = XtCreateManagedWidget("dial",
		dialWidgetClass, topLevel, NULL, 0);
	dialsq = XtCreateManagedWidget("dialsq",
		squareDialWidgetClass, shell, NULL, 0);
#endif
	XtVaGetValues(dial,
		XtNpixmapSize, &pixmapSize, NULL);
#ifdef HAVE_XPM
	{
		XpmAttributes xpmAttributes;
		XpmColorSymbol transparentColor[1] = {{NULL,
			(char *) "none", 0 }};
		Pixel bg;

		xpmAttributes.valuemask = XpmColorSymbols | XpmCloseness;
		xpmAttributes.colorsymbols = transparentColor;
		xpmAttributes.numsymbols = 1;
		xpmAttributes.closeness = 40000;
		XtVaGetValues(topLevel, XtNbackground, &bg, NULL);
		transparentColor[0].pixel = bg;
		(void) XpmCreatePixmapFromData(XtDisplay(topLevel),
			RootWindowOfScreen(XtScreen(topLevel)),
			RESIZE_XPM(pixmapSize), &pixmap, NULL,
			&xpmAttributes);
	}
	if (pixmap == (Pixmap) NULL)
#endif
		pixmap = XCreateBitmapFromData(XtDisplay(topLevel),
			RootWindowOfScreen(XtScreen(topLevel)),
			DEFINE_XBM);
	XtVaSetValues(topLevel,
#ifdef HAVE_MOTIF
		XmNkeyboardFocusPolicy, XmPOINTER, /* not XmEXPLICIT */
#else
		XtNinput, True,
#endif
		XtNiconPixmap, pixmap, NULL);
	XtAddCallback(dial, XtNselectCallback,
		(XtCallbackProc) callbackDial, (XtPointer) NULL);
	XtAddCallback(dialsq, XtNselectCallback,
		(XtCallbackProc) callbackDial, (XtPointer) NULL);
#ifndef HAVE_MOTIF
	XtVaSetValues(shell,
		XtNinput, True,
		XtNiconPixmap, pixmap, NULL);
#endif
	initialize();
	XtRealizeWidget(topLevel);
#ifndef HAVE_MOTIF
	XtRealizeWidget(shell);
#endif
	XGrabButton(XtDisplay(dial), (unsigned int) AnyButton, AnyModifier,
		XtWindow(dial), TRUE,
		(unsigned int) (ButtonPressMask | ButtonMotionMask |
		ButtonReleaseMask),
		GrabModeAsync, GrabModeAsync, XtWindow(dial),
		XCreateFontCursor(XtDisplay(dial), XC_hand2));
	XGrabButton(XtDisplay(dialsq), (unsigned int) AnyButton, AnyModifier,
		XtWindow(dialsq), TRUE,
		(unsigned int) (ButtonPressMask | ButtonMotionMask |
		ButtonReleaseMask),
		GrabModeAsync, GrabModeAsync, XtWindow(dialsq),
		XCreateFontCursor(XtDisplay(dialsq), XC_hand2));
	XtMainLoop();

#ifdef VMS
	return 1;
#else
	return 0;
#endif
}
