/* 
 * Copyright (C) 1992 by Gustaf Neumann, Stefan Nusser
 *
 *      Wirtschaftsuniversitaet Wien,
 *      Abteilung fuer Wirtschaftsinformatik
 *      Augasse 2-6,
 *      A-1090 Vienna, Austria
 *      neumann@@wu-wien.ac.at, nusser@@wu-wien.ac.at
 *
 * 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 appears in all copies and that both that
 * copyright notice and this permission notice appear in all supporting
 * documentation.  This software is provided "as is" without expressed or
 * implied warranty.
 *
 * Date: Mon, Apr 13 1992
 * Author: Stefan Nusser, Gustaf Neumann
 * Version: 0.9
 */

/*
 *             ACTIONSCB.C
 *
 *             This file contains all commands dealing with actions,
 *             callbacks, accelerators, etc and all related functions:
 *
 *             positionCursorCallbackProc
 *             positionCallbackProc
 *             execActionProc
 *             execCallbackProc
 */

#define ACTIONSCB_C

#include "wafe.h"

#ifdef ATHENA
#include<X11/Xaw/AsciiText.h>
#ifdef XEDW
#include "Xedw/XedwList.h"
#endif
#endif

#ifndef PRER5
#include <X11/Xaw/Panner.h>
#include <X11/Xaw/Porthole.h>
#endif



/*
 * Additionally, we need the following handler procedures, which are located in the
 * files list.c and scrollbar.c.
 */


#ifdef XEDW
extern void edwListCallbackProc(
#if NeedFunctionPrototypes
     Widget, XtPointer, XtPointer
#endif
);
#endif

typedef struct {
        Widget widget;
        int xoffset;
        int yoffset;
} widgetAndOffset;

 
void
execActionProc(w, event, argv, argc)
Widget     w;
XEvent    *event;
char     **argv;
Cardinal  *argc;
    {
    char   assembled[500];        /* Concat the arguments */
    char   command[500];          /* Do % substitution    */
    int    index;
    char  *input = assembled;
    char  *output = command;
    char   buffer[50];
    char  *ptr;    
    KeySym dummy;

    DBUG_ENTER("execActionProc");

    wafeCurrentEvent = event;

    assembled[0] = '\0';

    for (index = 0; index < *argc; index++)
	{
	strcat(assembled, argv[index]);
	strcat(assembled, " ");
	}

    DBUG_PRINT("action", ("Assembled command: %s", assembled));

    for (; *input != '\0'; input++)
	{
	if (*input == '%')
	    {
	    switch (*(++input)) 
		{
	        case 't':
		   switch (event->type)
		       {
		       case ButtonPress:
		           strcpy(output, "ButtonPress");
			   output += strlen("ButtonPress");
			   break;

		       case ButtonRelease:
			   strcpy(output, "ButtonRelease");
			   output += strlen("ButtonRelease");
			   break;


		       case MotionNotify:
		           strcpy(output, "MotionNotify");
			   output += strlen("MotionNotify");
			   break;


		       case KeyPress:
			   strcpy(output, "KeyPress");
			   output += strlen("KeyPress");
			   break;

		       case KeyRelease:
			   strcpy(output, "KeyRelease");
			   output += strlen("KeyRelease");
			   break;


		       case EnterNotify:
			   strcpy(output, "EnterNotify");
			   output += strlen("EnterNotify");
			   break;

		       case LeaveNotify:
			   strcpy(output, "LeaveNotify");
			   output += strlen("LeaveNotify");
			   break;


		       default:
			   strcpy(output, "Unknown");
			   output += strlen("Unknown");
			   break;
			   }
		   break;                     

	       case 'w':
		   strcpy(output, XtName(w));
		   output += strlen(output);
		   break;

	       case 'W':
                   sprintf(output, "%ld", (long)w);
                   output += strlen(output);
		   break;

	       case 'x':
		   sprintf(output, "%d", event->xbutton.x);
		   output += strlen(output);
		   break;                         

	       case 'y':
		   sprintf(output, "%d", event->xbutton.y);
		   output += strlen(output);
		   break;                         

	       case 'X':
		   sprintf(output, "%d", event->xbutton.x_root);
		   output += strlen(output);
		   break;                         

	       case 'Y':
		   sprintf(output, "%d", event->xbutton.y_root);
		   output += strlen(output);
		   break;                         

	       case 'a':
		   index = XLookupString((XKeyEvent *)event, 
					 output, 50, &dummy, NULL);
		   output += index;
		   break;                         

	       case 'k':
		   sprintf(output, "%d", event->xkey.keycode);
		   output += strlen(output);
		   break;

	       case 's':
		   XLookupString((XKeyEvent *)event, buffer, 50, &dummy, NULL);
		   ptr = XKeysymToString(dummy);
		   strcpy(output, ptr);
		   output += strlen(ptr);
		   break;                         

	       case 'b':
		   sprintf(output, "%d", event->xbutton.button);
		   output += strlen(output);
		   break;

	       default:
		   *output++ = '%';
		   *output++ = *input;
		   break;
		   }
	    }
	else 
	    {
	    *output++ = *input;
/*	    output++;*/
	    }
	}

    *output = '\0';

    DBUG_PRINT("action", ("command:<<%s>>", command));
    (void) wafeEval(wafeInterpreter, command, "execActionProc");
    wafeCurrentEvent = NULL;
    DBUG_VOID_RETURN;
    }


void
positionCallbackProc(w, clientData, callData)
Widget     w;
XtPointer  clientData, callData;
     {
     Position  x, y, xRoot, yRoot;
     widgetAndOffset *wao;

     DBUG_ENTER("positionCallbackProc");

     wao = (widgetAndOffset *)clientData;
     XtVaGetValues(wao->widget,
                   XtNx, &x,
                   XtNy, &y,
                   NULL);

     XtTranslateCoords(wafeTopLevel, x, y, &xRoot, &yRoot);
     XtVaSetValues(w,
                         XtNx, xRoot+(wao->xoffset),
                         XtNy, yRoot+(wao->yoffset),
                         NULL);

     DBUG_VOID_RETURN;
     }

void
positionCursorCallbackProc(w, clientData, callData)
Widget     w;
XtPointer  clientData, callData;
     {
     Window root, child;
     int  x, y, win_x,win_y;
     unsigned int mask;
     int  offset = (int)clientData;

     DBUG_ENTER("positionCursorCallbackProc");

     (void) XQueryPointer(XtDisplay(w), XtWindow(wafeTopLevel),
                         &root, &child,
                         &x, &y, &win_x, &win_y,
                         &mask);

     XtVaSetValues(w,
                         XtNx, x-offset,
                         XtNy, y-offset,
                         NULL);

     DBUG_VOID_RETURN;
     }

void
action(w, TranslationModifier, translationTable)
Widget	w;
int	TranslationModifier;
XtTranslations translationTable;
    {
    switch (TranslationModifier) 
        {
	case 1: XtOverrideTranslations(w, translationTable);
		break;
	case 2: XtAugmentTranslations(w, translationTable);
		break;
	case 3: XtVaSetValues (w, XtNtranslations, translationTable, NULL);
		break;
        }
    }

/*
 *  FUNCTION: callback
 *  Arguments:
 *            Widget - Widget whose attribute is to be set
 *            char * - Name of attribute
 *            proc   - Name of callback procedure to use
 *            arg    - clientData argument
 *
 *  This function is called by the genereated callback procedure (XtGen) and 
 *  cares for the special callData handling with list and scrollbar Widgets as 
 *  well as for the clientData argument of the XtPopdown callback (a so 
 *  called XtPopdownID).
 */


void
callback(w, cbAttribute, proc, arg)
Widget          w;
char           *cbAttribute;
XtCallbackProc  proc;
char           * arg;
    {   
    Widget           pop;

    if (proc == positionCursorCallbackProc)   /* Additional argument is offset... */
	{
	int offset;

	if (!sscanf(arg, "%d", &offset))
	    {
	    convError("callback", "4", arg, "int");
	    return;
	    }

	XtAddCallback(w, cbAttribute, positionCursorCallbackProc, 
		      (XtPointer)offset);
	XtFree(arg);
	}
    else
    if (proc == positionCallbackProc)   /* Additional argument is widget/offset */
	{
	widgetAndOffset *wao;
	char *colon, *slash;

	wao = (widgetAndOffset *)XtMalloc(sizeof(widgetAndOffset));
	if ((colon = (char*)strrchr(arg,':')))
	    {
	    *colon = '\0'; colon ++;
	    if ((slash = (char*)strrchr(colon,'/')))
		{
		*slash = '\0'; slash ++;
		if (!sscanf(slash, "%d", &(wao->yoffset))) 
		    {
		    convError("callback", "4", arg, "Widget:xoffset/yoffset");
		    return;
		    }
		}

	    if (!sscanf(colon, "%d", &(wao->xoffset))) 
		{
		convError("callback", "4", arg, "Widget:xoffset/yoffset");
		return;
		}
	    if (!slash) wao->yoffset = wao->xoffset;
	    }
	else 
	    { 
	    wao->xoffset = 50;
	    wao->yoffset = 50;
	    }
	if (!(wao->widget = name2Widget(arg)))  
	    {
	    convError("callback", "4", arg, "Widget:xoffset/yoffset");
	    return;
	    }

	XtAddCallback(w, cbAttribute, positionCallbackProc, (XtPointer)wao);
	XtFree(arg);
	}
    else
    if (proc == XtCallbackPopdown)   /* Build up XtPopdownID... */
	{
	XtPopdownID      pdPtr;
	pdPtr = (XtPopdownID)XtMalloc(sizeof(XtPopdownIDRec));

	if (!(pdPtr->shell_widget = name2Widget(strtok(arg, " "))))
	    {
	    convError("callback-popdown", "4", arg, "Widget");
	    return;
	    }

	if (!(pdPtr->enable_widget = name2Widget(strtok(NULL, " "))))
	    {
	    convError("callback-popdown", "4", arg, "Widget");
	    return;
	    }
	XtAddCallback(w, cbAttribute, XtCallbackPopdown, pdPtr);

	XtFree(arg);
	}
    else
	{
	if (!(pop = name2Widget(arg)))  /* For all other callbacks: arg is a Widget */
	    {
	    convError("callback", "4", arg, "Widget");
	    return;
	    }
	XtAddCallback(w, cbAttribute, proc, (XtPointer)pop);                         
	XtFree(arg);
	}
    return;
    }


#ifndef PRER5

/*      Function Name: PannerCallback
 *      Description: called when the panner has moved.
 *      Arguments: panner - the panner widget.
 *                 child - child to be moved.
 *                 report_ptr - the panner record.
 *      Returns: none.
 */

void 
pannerCallbackProc(w, child, report_ptr)
Widget w;
XtPointer child, report_ptr;
    {
    Arg args[2];
    XawPannerReport *report = (XawPannerReport *) report_ptr;

    XtSetArg (args[0], XtNx, -report->slider_x);
    XtSetArg (args[1], XtNy, -report->slider_y);
    
    XtSetValues(child, args, 2);
    }


/*      Function Name: PortholeCallback
 *      Description: called when the porthole or its child has
 *                   changed 
 *      Arguments: porthole - the porthole widget.
 *                 panner_ptr - the panner widget.
 *                 report_ptr - the porthole record.
 *      Returns: none.
 */


void 
portholeCallbackProc(w, panner_ptr, report_ptr)
Widget w;
XtPointer panner_ptr, report_ptr;
    {
    Arg args[10];
    Cardinal n = 0;
    XawPannerReport *report = (XawPannerReport *) report_ptr;
    Widget panner = (Widget) panner_ptr;

    XtSetArg (args[n], XtNsliderX, report->slider_x); n++;
    XtSetArg (args[n], XtNsliderY, report->slider_y); n++;
    if (report->changed != (XawPRSliderX | XawPRSliderY)) 
	{
        XtSetArg (args[n], XtNsliderWidth, report->slider_width); n++;
        XtSetArg (args[n], XtNsliderHeight, report->slider_height); n++;
        XtSetArg (args[n], XtNcanvasWidth, report->canvas_width); n++;
        XtSetArg (args[n], XtNcanvasHeight, report->canvas_height); n++; 
	}
    XtSetValues (panner, args, n);
    }

#endif
