/* panel.c
   make and handle callbacks for the main Xgopher panel */

     /*---------------------------------------------------------------*/
     /* Xgopher        version 1.1     20 April 1991                  */
     /*                version 1.0     04 March 1991                  */
     /* X window system client for the University of Minnesota        */
     /*                                Internet Gopher System.        */
     /* Allan Tuchman, University of Illinois at Urbana-Champaign     */
     /*                Computing Services Office                      */
     /* Copyright 1992 by                                             */
     /*           the Board of Trustees of the University of Illinois */
     /* Permission is granted to freely copy and redistribute this    */
     /* software with the copyright notice intact.                    */
     /*---------------------------------------------------------------*/


#include <stdio.h>
#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/cursorfont.h>
#include <X11/Xaw/Box.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Label.h>
#include <X11/Xaw/List.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Scrollbar.h>
#include <X11/Xaw/Simple.h>
#include <X11/Xaw/Viewport.h>

#include "gopher.h"
#include "list.h"
#include "misc.h"
#include "help.h"
#include "resources.h"
#include "xglobals.h"
#include "globals.h"


static Widget	dirLabel, dirList,
		markLabel, markList,
		unmarkButton, unmarkAllButton,
		upButton, fetchButton,
		statusLabel,
		gopherPanel,
		topLevel;

static char	*emptyList[] = {"<none>", NULL};
static	int	previousDir=XAW_LIST_NONE, previousMark=XAW_LIST_NONE;





/* isUpOK
   decide whether the up button is useful at this point.
   It is not useful when the current directory is the root,
   otherwise it is useful.  Should be used after: push, pop, fetch (goTo)
   (push may happen elsewhere). */

void
isUpOK()
{
	Arg		args[2];
	Cardinal	n = 0;
	static	Boolean available = True;

	if (atRoot()) 
		if (available) {	/* disable */
			XtSetArg(args[n], XtNsensitive, False);  n++;
			XtSetValues(upButton, args, n);
			available = False;
		} else ;
	else 
		if (! available) {	/* enable */
			XtSetArg(args[n], XtNsensitive, True);  n++;
			XtSetValues(upButton, args, n);
			available = True;
		}
}


/* isBookmarkOK
   decide whether the bookmark functions are useful at this point.
   They are not useful when the bookmark list is empty, otherwise 
   they are useful.
   Should be used after: mark, unmark, unmarkAll */

void
isBookmarkOK()
{
	Arg		args[2];
	Cardinal	n = 0;
	static	Boolean available = True;

	/* must potentially change {unmark, unmarkAll, fetch, markList} */

	if (anyMarks()) 
		if (! available) {	/* enable */
			XtSetArg(args[n], XtNsensitive, True);  n++;
			XtSetValues(unmarkButton, args, n);
			XtSetValues(unmarkAllButton, args, n);
			XtSetValues(markList, args, n);
			XtSetValues(markLabel, args, n);
			available = True;
		} else ;
	else 
		if (available) {	/* disable */
			XtSetArg(args[n], XtNsensitive, False);  n++;
			XtSetValues(unmarkButton, args, n);
			XtSetValues(unmarkAllButton, args, n);
			XtSetValues(markList, args, n);
			XtSetValues(markLabel, args, n);
			available = False;
		}
}


/* dirSelectProc
   callback for a directory selection */

void
dirSelectProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XawListReturnStruct	*val = (XawListReturnStruct *) call_data;
	gopherItemP		gi;

	XawListUnhighlight(markList);
	previousMark = XAW_LIST_NONE;

	if (appResources->doubleClick  &&  previousDir == val->list_index) {
		previousDir = XAW_LIST_NONE;
		XawListUnhighlight(dirList);
		gi = getCurrentItemN(val->list_index);
		if (gi != NULL) {
			XtCallActionProc(fetchButton, "set", NULL, NULL, 0);
			processSelection(gi);
			isUpOK();
			XtCallActionProc(fetchButton, "unset", NULL, NULL, 0);
		} else ;
	} else 
		previousDir = val->list_index;

	return;
}


/* markSelectProc
   callback for a bookmark selection */

void
markSelectProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XawListReturnStruct	*val = (XawListReturnStruct *) call_data;
	gopherDirP		gd;

	XawListUnhighlight(dirList);
	previousDir = XAW_LIST_NONE;

	if (appResources->doubleClick  &&  previousMark == val->list_index) {
		previousMark = XAW_LIST_NONE;
		XawListUnhighlight(markList);
		gd = getMarkN(val->list_index);
		if (gd != NULL) {
			XtCallActionProc(fetchButton, "set", NULL, NULL, 0);
			clearDirWhenOld(gd);
			goToDir(gd);
			displayCurrent();
			isUpOK();
			XtCallActionProc(fetchButton, "unset", NULL, NULL, 0);
		} else ;
	} else 
		previousMark = val->list_index;

	return;
}


/* fetchProc
   callback to go to a bookmark or directory item */

void
fetchProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	gopherItemP	gi;
	gopherDirP	gd;

	if (previousDir != XAW_LIST_NONE) {
		gi = getCurrentItemN(previousDir);
		previousDir = XAW_LIST_NONE;
		XawListUnhighlight(dirList);
		if (gi != NULL) processSelection(gi);
		isUpOK();
	} else if (previousMark != XAW_LIST_NONE) {
		gd = getMarkN(previousMark);
		previousMark = XAW_LIST_NONE;
		if (gd != NULL) {
			XawListUnhighlight(markList);
			clearDirWhenOld(gd);
			goToDir(gd);
			displayCurrent();
			isUpOK();
		}
	} else {
		/* nothing selected */
		showError(
			"Something must be selected before it can be fetched");
	}
}


/* quitProc
   exit callback. */

void
quitProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	cleanUpTextProc();
	exit(0);
}


/* helpProc
   help callback. */

void
helpProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	char	*string;

	showHelp("xgopher help");
}


/* markProc
   callback to set a bookmark at the current directory */

void
markProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	markDir();
	displayBookmarks();
	isBookmarkOK();
}


/* unmarkProc
   callback to delete a bookmark */

void
unmarkProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	XawListReturnStruct	*val;

	val = XawListShowCurrent(markList);
	if (val->list_index != XAW_LIST_NONE) {
		previousDir = previousMark = XAW_LIST_NONE;
		unmarkDirN(val->list_index);
		displayBookmarks();
		isBookmarkOK();
	}
}


/* unmarkAllProc
   callback to delete all bookmarks */

void
unmarkAllProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	previousMark = XAW_LIST_NONE;
	unmarkAllDirs();
	displayBookmarks();
	isBookmarkOK();
}


/* upProc
   callback to go up a level */

void
upProc(w, client_data, call_data)
Widget		w;
XtPointer	client_data, call_data;
{
	previousDir = previousMark = XAW_LIST_NONE;
	XawListUnhighlight(markList);
	clearDirWhenOld(getParentDirectory());
	popDir();
	displayCurrent();
	isUpOK();
}


/* changeDirLabel
   change the directory list label */

void
changeDirLabel(newLabel)
char	*newLabel;
{
	Arg		args[2];
	Cardinal	n = 0;
	
	XtSetArg(args[n], XtNlabel, (String) newLabel);  n++;
	XtSetValues(dirLabel, args, n);
}


/* changeStatusLabel
   change the status label */

void
changeStatusLabel(newLabel, statType)
char	*newLabel;
int	statType;
{
	Arg		args[2];
	Cardinal	n = 0;
	Display		*dpy;
	static BOOLEAN  waitDefined  = FALSE;
	static		Window	waitWindow;

	dpy = XtDisplay(gopherPanel);
	

	/* Change cursors to show a long wait maybe */

	if (! waitDefined) {
		/* following is from the FAQ file in comp.windows.x */

		unsigned long valuemask;
		XSetWindowAttributes attributes;

		waitDefined = TRUE;

		/* Ignore device events while the busy cursor is displayed. */

		valuemask = CWDontPropagate | CWCursor;
		attributes.do_not_propagate_mask =
			(KeyPressMask | KeyReleaseMask |
			ButtonPressMask | ButtonReleaseMask |
			PointerMotionMask);
		attributes.cursor =
			XCreateFontCursor(XtDisplay(topLevel), XC_watch);

		/* The window will be as big as the display screen,
		   and clipped by its own parent window, so we never
		   have to worry about resizing */

		waitWindow = 
			XCreateWindow(dpy, XtWindow(topLevel),
				0, 0,
				(unsigned int) SERVER_MAX_WINDOW_WIDTH,
				(unsigned int) SERVER_MAX_WINDOW_HEIGHT,
				(unsigned int) 0,
				CopyFromParent, InputOnly, CopyFromParent,
				valuemask, &attributes);
	}
	if (statType == GSTAT_WAIT) {
		XMapWindow(dpy, waitWindow);
		XRaiseWindow(dpy, waitWindow);
	} else {
		XUnmapWindow(dpy, waitWindow);
	}

	n=0;
	XtSetArg(args[n], XtNlabel, (String) newLabel);  n++;
	XtSetValues(statusLabel, args, n);
	XSync(XtDisplay(statusLabel), False);
}


/* changeDirList
   change the directory list contents */

void
changeDirList(list)
char	*list[];
{
	if (list == NULL  ||  list[0] == NULL) 
		XawListChange(dirList, emptyList, 0, 0, True);	
	else
		XawListChange(dirList, list, 0, 0, True);	
}


/* changeMarkList
   change the bookmark list contents */

void
changeMarkList(list)
char	*list[];
{
	if (list == NULL  ||  list[0] == NULL)
		XawListChange(markList, emptyList, 0, 0, True);	
	else
		XawListChange(markList, list, 0, 0, True);	
}


/* upActionProc
   implement the up action */

void
upActionProc(w, event, params, numParams)
Widget		w[];
XEvent		*event;
String		*params;
Cardinal	*numParams;
{
	if (! atRoot()) upProc(upButton, NULL, NULL);
}


/* makeGopherPanel
   create the elements of the main gopher panel */

void
makeGopherPanel(top)
Widget	top;
{
	Widget		quitButton, helpButton,
			spacer,
			markButton,
			dirForm, dirView,
			markForm, markView ;
	Widget		statusForm, goBox;
	Arg		args[10];
	Cardinal	n;

	static XtActionsRec	actionsTable[] = {
				{"up",  upActionProc}
				};
	/*
	static char		defaultTranslations[] = "<Key>u:  up()";
	XtTranslations	transTable;
	*/



	topLevel = top;

	XtAddActions(actionsTable, XtNumber(actionsTable));
	/*
	transTable = XtParseTranslationTable(defaultTranslations);
	*/

	makeXThings();


	/* create main gopher panel */
	gopherPanel = XtCreateManagedWidget("gopherPanel", panedWidgetClass,
					topLevel, NULL, (Cardinal) 0);
		/*
		XtAugmentTranslations(gopherPanel, transTable);
		*/

	/* create STATUS form */
	statusForm = XtCreateManagedWidget("statusForm", formWidgetClass,
					gopherPanel, NULL, (Cardinal) 0);


	/* create DIRECTORY FORM */
	dirForm = XtCreateManagedWidget("directoryForm", formWidgetClass,
					gopherPanel, NULL, (Cardinal) 0);

	/* create GO box */
	goBox = XtCreateManagedWidget("goBox", boxWidgetClass,
					gopherPanel, NULL, (Cardinal) 0);


	/* create BOOKMARK FORM */
	markForm = XtCreateManagedWidget("bookmarkForm", formWidgetClass,
					gopherPanel, NULL, (Cardinal) 0);

	/* create QUIT button */

	quitButton = XtCreateManagedWidget("quit", commandWidgetClass,
					statusForm, NULL, (Cardinal) 0);
		XtAddCallback(quitButton, XtNcallback, quitProc, NULL);

	/* create HELP button */

	helpButton = XtCreateManagedWidget("help", commandWidgetClass,
					statusForm, NULL, (Cardinal) 0);
		XtAddCallback(helpButton, XtNcallback, helpProc, NULL);

	/* create STATUS label */

		n=0;
		/* XtSetArg(args[n], XtNbackgroundPixmap, gray);  n++; */
	statusLabel = XtCreateManagedWidget("status", labelWidgetClass,
					statusForm, args, n);

	/* create GOTO button */

	fetchButton = XtCreateManagedWidget("fetch", commandWidgetClass,
					goBox, NULL, (Cardinal) 0);
		XtAddCallback(fetchButton, XtNcallback, fetchProc, NULL);

	/* create some space */

	spacer = XtCreateManagedWidget("spacer", simpleWidgetClass,
					goBox, NULL, (Cardinal) 0);

	/* create UP button */

	upButton = XtCreateManagedWidget("up", commandWidgetClass,
					goBox, NULL, (Cardinal) 0);
		XtAddCallback(upButton, XtNcallback, upProc, NULL);

	/* create MARK button */

	markButton = XtCreateManagedWidget("mark", commandWidgetClass,
					goBox, NULL, (Cardinal) 0);
		XtAddCallback(markButton, XtNcallback, markProc, NULL);

	/* create UNMARK button */

	unmarkButton = XtCreateManagedWidget("unmark", commandWidgetClass,
					goBox, NULL, (Cardinal) 0);
		XtAddCallback(unmarkButton, XtNcallback, unmarkProc, NULL);

	/* create UNMARK ALL button */

	unmarkAllButton = XtCreateManagedWidget("unmarkAll", commandWidgetClass,
					goBox, NULL, (Cardinal) 0);
		XtAddCallback(unmarkAllButton, XtNcallback, unmarkAllProc,NULL);


	/* ============ DIRECTORY PANEL =========== */

	/* the directory panel will have this heirarchy:
	      directoryForm
		 directoryTitle
		 directoryView
		     directory
		     (scrollbar: automatic)
	*/

	/* create DIRECTORY TITLE label */

		n=0;
		/*
		XtSetArg(args[n], XtNborderWidth, 0);  n++;
		*/
	dirLabel = XtCreateManagedWidget("directoryTitle", labelWidgetClass,
					dirForm, args, n);

	/* create DIRECTORY VIEWPORT */

		n = 0;
		XtSetArg(args[n], XtNfromVert, dirLabel);  n++;
		XtSetArg(args[n], XtNallowVert, True);  n++;
	dirView = XtCreateManagedWidget("directoryView", viewportWidgetClass,
					dirForm, args, n);

	/* create CURRENT DIRECTORY LIST display */

		n = 0;
		XtSetArg(args[n], XtNforceColumns, True);  n++;
		XtSetArg(args[n], XtNdefaultColumns, 1);  n++;
		XtSetArg(args[n], XtNlist, emptyList);  n++;
		XtSetArg(args[n], XtNhorizDistance, 0);  n++;
	dirList = XtCreateManagedWidget("directory", listWidgetClass,
					dirView, args, n);
		XtAddCallback(dirList, XtNcallback, dirSelectProc,NULL);

	/* ============ BOOKMARK PANEL =========== */

	/* the bookmark panel will have this heirarchy:
	      bookmarkForm
		 bookmarkTitle
		 bookmarkView
		     bookmark
		     (scrollbar: automatic)
	*/

	/* create BOOKMARK TITLE label */

		n=0;
		/*
		XtSetArg(args[n], XtNborderWidth, 0);  n++;
		*/
	markLabel = XtCreateManagedWidget("bookmarkTitle", labelWidgetClass,
					markForm, args, n);

	/* create BOOKMARK VIEWPORT */

		n=0;
		XtSetArg(args[n], XtNfromVert, markLabel);  n++;
		XtSetArg(args[n], XtNallowVert, True);  n++;
	markView = XtCreateManagedWidget("bookmarkView", viewportWidgetClass,
					markForm, args, n);

	/* create BOOKMARK LIST display */

		n = 0;
		XtSetArg(args[n], XtNforceColumns, True);  n++;
		XtSetArg(args[n], XtNdefaultColumns, 1);  n++;
		XtSetArg(args[n], XtNlist, emptyList);  n++;
		XtSetArg(args[n], XtNhorizDistance, 0);  n++;
	markList = XtCreateManagedWidget("bookmark", listWidgetClass,
					markView, args, n);
		XtAddCallback(markList, XtNcallback, markSelectProc,NULL);

	isUpOK();
	isBookmarkOK();

	return;
}

