/*
 *	$Source: /u1/X/Toolkit/DECToolkit/src/RCS/Command.c,v $
 *	$Header: Command.c,v 1.2 86/12/22 13:38:02 swick Exp $
 */

#ifndef lint
static char *rcsid_Command_c = "$Header: Command.c,v 1.2 86/12/22 13:38:02 swick Exp $";
#endif	lint

#ifndef lint
static char *sccsid = "@(#)Command.c	1.13          12/11/86";
#endif lint
/*
 *			  COPYRIGHT 1986
 *		   DIGITAL EQUIPMENT CORPORATION
 *		       MAYNARD, MASSACHUSETTS
 *			ALL RIGHTS RESERVED.
 *
 * THE INFORMATION IN THIS SOFTWARE IS SUBJECT TO CHANGE WITHOUT NOTICE AND
 * SHOULD NOT BE CONSTRUED AS A COMMITMENT BY DIGITAL EQUIPMENT CORPORATION.
 * DIGITAL MAKES NO REPRESENTATIONS ABOUT THE SUITABILITY OF THIS SOFTWARE FOR
 * ANY PURPOSE.  IT IS SUPPLIED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
 *
 * IF THE SOFTWARE IS MODIFIED IN A MANNER CREATING DERIVATIVE COPYRIGHT RIGHTS,
 * APPROPRIATE LEGENDS MAY BE PLACED ON THE DERIVATIVE WORK IN ADDITION TO THAT
 * SET FORTH ABOVE.
 *
 *
 * 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 Digital Equipment Corporation not be used in advertising
 * or publicity pertaining to distribution of the software without specific, 
 * written prior permission.
 */


/*
 *
 * Author: K. Langone
 *
 */	

#include <stdio.h>
#include <X/Xlib.h>
#include <string.h>
#include "Toolkit.h"

/* Private Definitions */


/* -----> defines */



#define anyButtons		0x0703
	
#define cmdEvents (ExposeRegion | ExposeWindow | LeaveWindow | \
EnterWindow | ButtonPressed | ButtonReleased)

extern char *malloc (), *calloc ();

typedef struct _CommandData {
    int     type;		/* (text=0, pixmap=1 */
    char   *text;		/* button text */
    Pixmap pixm;		/* button pixmap */
    short   width, height;	/* width/height in pixles */
    Pixmap  backgrcolor;	/* color index for background */
    Pixmap  brcolor;		/* color index for border */
    int     brwidth;		/* minimum border width in pixels */
    int     txcolor;		/* color index for text */
    int     hitype;		/* highlight mask */
    int     histate;		/* state of highlighting(on/off) */
    int     selstate;		/* current state of highlighting */
    FontInfo *fontinfo;	/* font for text */
    int     twidth, theight;	/* text width/height */
    int     (*Proc) ();		/* procedure for selected command 
				button */
    caddr_t tag;		/* additional tool data */
    int onhi;			/* events to highlight for*/
    int offhi;			/* events to unhighlight for*/
    int notify;			/* events to notify w/ callback */
    int refresh;		/* event to refresh for*/
} CommandData, *CommandDataPtr;

/* -----> static variables */

static int  initDone = 0;	/* initialization flag */
static int  cmdContext;		/* context of type command */
static int  borderdelta = 3;	/* border delta for highlighting */
static Window tw;		/* tool window */
static  FontInfo * gfontinfo;



static  Initialize () 
{
    cmdContext = UniqueEntryType ();
    initDone = 1;
    gfontinfo = XOpenFont ("/usr/lib/Xfont/9x15.onx");
}


static Dummy()
{
	printf("dummy call back for Command\n");
}

/* -----> Utilities */

static  void DisplayCommandTx (w, data, dohilite)
        Window w;
CommandData * data;
int     dohilite;

{

    int     linewidth;
    int     textx, texty;

    if (dohilite) {
	linewidth = data -> brwidth + borderdelta;
	data->histate = TRUE;
    }
    else {
	linewidth = data -> brwidth;
	data->histate = FALSE;
    }


 /* -----> Calculate Text x,y given window width and height */

    textx = (data -> width - data -> twidth) / 2;
    texty = (data -> height - data -> theight) / 2;

 /* -----> create the button by: 
	1. drawing a background rectangle 
	2. drawing a an inner rectangle sized by highlighting 
	3. Draw text string 
 */

    XTileSet (w, 0, 0, data -> width, data -> height, data -> brcolor);

    XTileSet (w, 0 + linewidth, 0 + linewidth, data -> width - (2 * linewidth),
	    data -> height - (2 * linewidth), data -> backgrcolor);

    XTextMask(w, textx, texty, data -> text, strlen (data -> text),
	    data -> fontinfo -> id, data -> txcolor);

    XFlush ();
}


/* -----> Utilities */

static  void DisplayCommandPx (w, data, dohilite)
        Window w;
CommandData * data;
int     dohilite;

{

    Vertex vlist[5];
    int     linewidth;
    int     textx, texty;

    if (dohilite) {
	linewidth = data -> brwidth + borderdelta;
	data->histate = TRUE;
    }
    else {
	linewidth = data -> brwidth;
	data->histate = FALSE;
    }




 /* -----> Initialize vertex list for border of button */

    vlist[0].x = 0;
    vlist[0].y = 0;
    vlist[0].flags = VertexDontDraw;
    vlist[1].x = data -> width - linewidth;
    vlist[1].y = 0;
    vlist[1].flags = VertexDrawLastPoint;
    vlist[2].x = data -> width - linewidth;
    vlist[2].y = data -> height - linewidth;
    vlist[2].flags = VertexDrawLastPoint;
    vlist[3].x = 0;
    vlist[3].y = data -> height - linewidth;
    vlist[3].flags = VertexDrawLastPoint;
    vlist[4].x = 0;
    vlist[4].y = 0;
    vlist[4].flags = VertexDrawLastPoint;





 /* -----> Create the button by: 
	1. drawing a pixmap 
	2. drawing a border 
 */


    XPixmapPut (w, 0, 0, 0, 0, data -> width, data -> height,
	    data -> pixm, GXcopy, AllPlanes);

    if (data -> brwidth || dohilite)
	XDraw (w, vlist, 5, linewidth, linewidth, BlackPixel, GXcopy,
	AllPlanes);

    XFlush ();
}


/* =================================================================== */

/* Private Procedures */


static int TProcessCommandEvent (event)
	XEvent *event;

  {
  int x, y, subW, error;
  int returnCode;
  int eventmatch;
  short state;
  CommandData *data;
  Status status;
  caddr_t tooldata;
  XMouseOrCrossingEvent *button;

  error = FindEntry(event->window, cmdContext, &data);
  if (error != ERRNONE) return (NOTHANDLED);
  returnCode = PROCESSED;

  /* -----> Initialize event match to false */
  eventmatch = FALSE;


  /* -----> Check for call back event */

  if (event->type & data->notify) {
	tooldata = data->tag;
        data->Proc(event, tooldata);
  }


  /* -----> Check for hilight or unhilight event */
  if (event->type & data->onhi) {
        /* -----> Check for button conditions */
	if (data->onhi & ButtonPressed) {
            button = (XMouseOrCrossingEvent *)event;
	    if (button->detail & anyButtons)
		eventmatch = TRUE;
	    else
		eventmatch = FALSE;
		
	}
	else
	    eventmatch = TRUE;
		
	if (eventmatch) {
	    if (data->type == 0)
		DisplayCommandTx(event->window, data, TRUE);
	    else 
		DisplayCommandPx(event->window, data, TRUE);
	}
		
  }
  else if (event->type & data->offhi) {
        /* -----> Check for button conditions */
	if (data->offhi & ButtonPressed) {
            button = (XMouseOrCrossingEvent *)event;
	    if (button->detail & anyButtons)
		eventmatch = TRUE;
	    else
		eventmatch = FALSE;
	}
	else
	    eventmatch = TRUE;

	if (eventmatch) {
	    if (data->type == 0)
		DisplayCommandTx(event->window, data, FALSE);
	    else 
		DisplayCommandPx(event->window, data, FALSE);
	}	
  }

  /* -----> Check for refresh event */
  if (event->type & data->refresh) {
      	if (data->type == 0)
      		DisplayCommandTx(event->window, data, data->histate);
      	else
		DisplayCommandPx(event->window, data, data->histate);
  }

  return (returnCode);
  }


/* =================================================================== */

/*
 * This procedure will destroy a command button 
 *
 */

Status TDestroyCommand (tw)
Window tw;
{

 /* -----> Delete the data in the table */
    DeleteEntry (tw, cmdContext);

 /* Other code, tbd... */
}

/* =================================================================== */

/*
 * This procedure will create a command button and will set predefined
 * values colors,font,and state selection. If any errors are detected
 * during the parsing of the input arguments, an exit will occur.
 *
 */

Status TGetCommandAttr (tw, arglist)
Window tw;			/* tool window */
Targ * arglist;
{
    CommandData * data;
    int     return_code;	/* return code from window creation */
    int     i, error;

    error = FindEntry (tw, cmdContext, &data);

 /* -----> Parsing input parameters */

    while (arglist -> name) {
	switch (arglist -> name) {
	    case T_COMMAND_TYPE: 
		arglist -> data = (caddr_t) data -> type;
		break;
	    case T_COMMAND_TEXT: 
		arglist -> data = (caddr_t) data -> text;
		break;
	    case T_COMMAND_PIXM: 
		arglist -> data = (caddr_t) data -> pixm;
		break;
	    case T_COMMAND_FONTINFO: 
		arglist -> data = (caddr_t) data -> fontinfo;
		break;
	    case T_COMMAND_TXCOLOR: 
		arglist -> data = (caddr_t) data -> txcolor;
		break;
	    case T_COMMAND_PIXMW: 
		arglist -> data = (caddr_t) data -> width;
		break;
	    case T_COMMAND_PIXMH: 
		arglist -> data = (caddr_t) data -> height;
		break;
	    case T_COMMAND_HITYPE: 
		arglist -> data = (caddr_t) data -> hitype;
		break;
	    case T_COMMAND_BACKGRCOLOR: 
		arglist -> data = (caddr_t) data -> backgrcolor;
		break;
	    case T_COMMAND_BRCOLOR: 
		arglist -> data = (caddr_t) data -> brcolor;
		break;
	    case T_COMMAND_BRWIDTH: 
		arglist -> data = (caddr_t) data -> brwidth;
		break;
	    case T_COMMAND_SELSTATE: 
		arglist -> data = (caddr_t) data -> selstate;
		break;
	    case T_COMMAND_PROC: 
		arglist -> data = (caddr_t) data -> Proc;
		break;
	    case T_COMMAND_TAG: 
		arglist -> data = data -> tag;
		break;
	    case T_COMMAND_ONHI: 
		arglist -> data = (caddr_t) data -> onhi;
		break;
	    case T_COMMAND_OFFHI: 
		arglist -> data = (caddr_t) data -> offhi;
		break;
	    case T_COMMAND_NOTIFY: 
		arglist -> data = (caddr_t) data -> notify; 
		break;
	    case T_COMMAND_REFRESH: 
		arglist -> data = (caddr_t) data -> refresh; 
		break;
	    default: 
	    /* eventually put in error message */
		break;
	}
	arglist++;
    }


}
/* =================================================================== */

/*
 * This procedure will create a command button and will set predefined
 * values colors,font,and state selection. If any errors are detected
 * during the parsing of the input arguments, an exit will occur.
 *
 */

Status TSetCommandAttr (tw, arglist)
Window tw;			/* tool window */
Targ * arglist;
{
    extern  FontInfo * gfontinfo;
    CommandData * data;
    int     return_code;	/* return code from window creation */
    int     twidth, theight;
    int     error;

    error = FindEntry (tw, cmdContext, &data);

 /* -----> Parsing input parameters */

    while (arglist -> name) {
	switch (arglist -> name) {
	    case T_COMMAND_TYPE: 
		data -> type = (int) arglist->data;
		break;
	    case T_COMMAND_TEXT: 
		data -> text = 
		strcpy(Tmalloc (strlen ((char *) arglist -> data) + 1),
		(char *) arglist -> data);
	        /* -----> window size is not changed at this time */
		if (data -> type == 0) {
		/* -----> obtain text dimensions and calculate 
		the window size */
		twidth = XStringWidth (data -> text, data -> fontinfo, 0, 0);
		theight = data -> fontinfo -> height;
		data -> twidth = twidth;
		data -> theight = theight;
		data -> width = (short) twidth + 
		    data -> brwidth + borderdelta + 4;
		data -> height = (short) theight + 
		    data -> brwidth + borderdelta + 8;
		}
		break;
	    case T_COMMAND_PIXM: 
		data -> pixm = (Pixmap) arglist -> data;
	    /* -----> obtain window size from pixmap dimensions */
		break;
	    case T_COMMAND_FONTINFO: 
		data -> fontinfo = (FontInfo *) arglist -> data;
		break;
	    case T_COMMAND_TXCOLOR: 
		data -> txcolor = (int) arglist -> data;
		break;
	    case T_COMMAND_PIXMW: 
	    /* -----> Note window size is not changed at this time */
		data -> width = (int) arglist -> data;
		break;
	    case T_COMMAND_PIXMH: 
	    /* -----> Note window size is not changed at this time */
		data -> height = (int) arglist -> data;
		break;
	    case T_COMMAND_HITYPE: 
		data -> hitype = (int) arglist -> data;
		break;
	    case T_COMMAND_BACKGRCOLOR: 
		data -> backgrcolor = (int) arglist -> data;
		break;
	    case T_COMMAND_BRCOLOR: 
		data -> brcolor = (int) arglist -> data;
		break;
	    case T_COMMAND_BRWIDTH: 
		data -> brwidth = (int) arglist -> data;
		break;
	    case T_COMMAND_SELSTATE: 
		data -> selstate = (int) arglist -> data;
		break;
	    case T_COMMAND_PROC: 
		data -> Proc = (int (*) ()) arglist -> data;
		break;
	    case T_COMMAND_TAG: 
		data -> tag = arglist -> data;
		break;
	    case T_COMMAND_ONHI: 
		data -> onhi = (int) arglist -> data;
		break;
	    case T_COMMAND_OFFHI: 
		data -> offhi = (int) arglist -> data;
		break;
	    case T_COMMAND_NOTIFY: 
		data -> notify = (int) arglist -> data;
		break;
	    case T_COMMAND_REFRESH: 
		data -> refresh = (int) arglist -> data;
		break;
	    default: 
		break;
	}
	arglist++;
    }


    if (data -> type == 0)
	DisplayCommandTx (tw, data, 0);
    else
	DisplayCommandPx (tw, data, 0);

}

/* =================================================================== */

/*
 * This procedure will create a command button and will set predefined
 * values colors,font,and state selection. If any errors are detected
 * during the parsing of the input arguments, an exit will occur.
 *
 */

Window TCreateCommand (pw, arglist)
Window pw;			/* parent window */
Targ * arglist;
{
    extern  FontInfo * gfontinfo;
    CommandData * data;
    int     return_code;	/* return code from window creation */
    int     twidth, theight;
    int     i;
    int    *ptr;
    int     dummy;
    OpaqueFrame * frame;	/* frame for data */

 /* -----> Perform initialization */
    if (!initDone)
	Initialize ();

 /* -----> Allocate space for data structure */
    data = (CommandData *) Tmalloc (sizeof (CommandData));

 /* -----> Set Default Values */
    data -> type = 0;
    data -> text = "DEFAULT";
    data -> pixm = WhitePixmap;
    data -> fontinfo = gfontinfo;
    data -> txcolor = BlackPixel;
    data -> width = 70;
    data -> height = 50;
    data -> hitype = NULL;	/* TBD */
    data -> Proc = Dummy;
    data -> tag = NULL;
    data -> backgrcolor = WhitePixmap;
    data -> brcolor = BlackPixmap;
    data -> brwidth = 2;
    data -> histate = FALSE;
    data -> selstate = TRUE;
    data -> onhi = EnterWindow;
    data -> offhi = LeaveWindow;
    data -> notify = (ButtonReleased);
    data -> refresh = (ExposeWindow | ExposeRegion);

 /* -----> Parsing input parameters */

    while (arglist -> name) {
	switch (arglist -> name) {
	    case T_COMMAND_TYPE: 
		data -> type = (int) arglist -> data;
		break;
	    case T_COMMAND_TEXT: 
		data -> text = 
		strcpy (Tmalloc (strlen ((char *) arglist -> data) + 1),
		(char *) arglist -> data);
		break;
	    case T_COMMAND_PIXM: 
		data -> pixm = (Pixmap) arglist -> data;
		break;
	    case T_COMMAND_FONTINFO: 
		data -> fontinfo = (FontInfo *) arglist -> data;
		break;
	    case T_COMMAND_TXCOLOR: 
		data -> txcolor = (int) arglist -> data;
		break;
	    case T_COMMAND_PIXMW: 
		data -> width = (int) arglist -> data;
		break;
	    case T_COMMAND_PIXMH: 
		data -> height = (int) arglist -> data;
		break;
	    case T_COMMAND_HITYPE: 
		data -> hitype = (int) arglist -> data;
		break;
	    case T_COMMAND_BACKGRCOLOR: 
		data -> backgrcolor = (int) arglist -> data;
		break;
	    case T_COMMAND_BRCOLOR: 
		data -> brcolor = (int) arglist -> data;
		break;
	    case T_COMMAND_BRWIDTH: 
		data -> brwidth = (int) arglist -> data;
		break;
	    case T_COMMAND_SELSTATE: 
		data -> selstate = (int) arglist -> data;
		break;
	    case T_COMMAND_PROC: 
		data -> Proc = (int (*) ()) arglist -> data;
		break;
	    case T_COMMAND_TAG: 
		data -> tag = arglist -> data;
	    case T_COMMAND_ONHI: 
		data -> onhi = (int) arglist -> data;
		break;
	    case T_COMMAND_OFFHI: 
		data -> offhi = (int) arglist -> data;
		break;
	    case T_COMMAND_NOTIFY: 
		data -> notify = (int) arglist -> data;
		break;
	    case T_COMMAND_REFRESH: 
		data -> refresh = (int) arglist -> data;
		break;
	    default: 
		break;
	}
	arglist++;
    }


    if (data -> type == 0) {
    /* -----> obtain text dimensions and calculate the window size */
	twidth = XStringWidth (data -> text, data -> fontinfo, 0, 0);
	theight = data -> fontinfo -> height;
	data -> twidth = twidth;
	data -> theight = theight;
	data -> width = (short) twidth + data -> brwidth +
	    borderdelta + 4;
	data -> height = (short) theight + data -> brwidth +
	    borderdelta + 8;
    }

 /* -----> Create the tool window */
    tw = XCreateWindow(pw, 0, 0, data -> width, data -> height,
	data -> brwidth, data -> brcolor, data -> backgrcolor);

    SaveEntry (tw, cmdContext, data);

    TSetXEventDispatch (tw, TProcessCommandEvent, cmdEvents, 0);

    return (tw);
}
