/*
 *	$Source: /u1/X/DECToolkit/src/RCS/Boolean.c,v $
 *	$Header: Boolean.c,v 1.1 86/12/17 09:00:31 swick Exp $
 */

#ifndef lint
static char *rcsid_Boolean_c = "$Header: Boolean.c,v 1.1 86/12/17 09:00:31 swick Exp $";
#endif	lint

#ifndef lint
static char *sccsid = "@(#)Boolean.c	1.10          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: Kathy Langone
 */


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

/* Private Definitions */


/* -----> defines */


#define EnterButtonUp		0x0001
#define EnterButtonDown   	0x0002
#define InButtonPressed		0x0004
#define InButtonReleased	0x0008
#define LeaveButtonUp		0x0010
#define LeaveButtonDown		0x0020
#define boolEvents (ExposeRegion | ExposeWindow | LeaveWindow | \
EnterWindow | ButtonPressed | ButtonReleased)
extern char *malloc (), *calloc ();

typedef struct _BooleanData {
    int     type;		/* (text=0, pixmap=1 */
    char   *text0;		/* button text for state 0 */
    char   *text1;		/* button text for state 1 */
    Pixmap pixm0;		/* button pixmap for state 0 */
    Pixmap pixm1;		/* button pixmap for state 1 */
    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     selstate;		/* current state of highlighting */
    FontInfo * fontinfo;	/* font for text */
    int     twidth0, twidth1;	/* text 0 and 1 widths */
    int     theight;		/* text width/height */
    int     (*Proc) ();		/* procedure for selected boolean */
    caddr_t tag;		/* additional tool data */
} BooleanData, *BooleanDataPtr;

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

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

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


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

/* -----> Utilities */

static  void DisplayBooleanTx (w, data, dohilite, doselect)
        Window w;
BooleanData * data;
int     dohilite;
int     doselect;

{

    int     linewidth;
    int     textx0, textx1, texty;

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


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

    textx0 = (data -> width - data -> twidth0) / 2;
    textx1 = (data -> width - data -> twidth1) / 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);

 /* -----> Toggle the state bit if selection has occured */

    if (doselect) {
	if (data -> selstate)
	    data -> selstate = 0;
	else
	    data -> selstate = 1;
    }


 /* -----> Display the Text */
    if (data -> selstate)	/* Display text for state 1 */
	XTextMask (w, textx1, texty, data -> text1, strlen (data -> text1),
		data -> fontinfo -> id, data -> txcolor);
    else
	XTextMask (w, textx0, texty, data -> text0, strlen (data -> text0),
		data -> fontinfo -> id, data -> txcolor);

    XFlush ();
}


/* -----> Utilities */

static  void DisplayBooleanPx (w, data, dohilite, doselect)
        Window w;
BooleanData * data;
int     dohilite;
int     doselect;

{

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

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




 /* -----> 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 
 */

 /* -----> Toggle the state bit if selection has occured */


    if (doselect) {
	if (data -> selstate)
	    data -> selstate = 0;
	else
	    data -> selstate = 1;
    }


 /* -----> Display the Pixmap */
    if (data -> selstate)	/* Display pixmap for state 1 */
	XPixmapPut (w, 0, 0, 0, 0, data -> width, data -> height,
		data -> pixm1, GXcopy, AllPlanes);
    else			/* Display pixmap for state 0 */
	XPixmapPut (w, 0, 0, 0, 0, data -> width, data -> height,
		data -> pixm0, GXcopy, AllPlanes);


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

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

/* Private Procedures */

static int  TProcessBooleanEvent (event)
            XEvent * event;
{
    int     x, y, subW, error;
    int     returnCode;
    short   state;
    BooleanData * data;
    Status status;
    caddr_t tooldata;

    error = FindEntry (event -> window, boolEntry, &data);
    if (error != ERRNONE)
	return (NOTHANDLED);
    returnCode = PROCESSED;
    switch (event -> type) {
	case ButtonPressed: 
	    if (data -> type == 0)
		DisplayBooleanTx (event -> window, data, TRUE, FALSE);
	    else
		DisplayBooleanPx (event -> window, data, TRUE, FALSE);
	    break;
	case ButtonReleased: 
	/* -----> send additional data to procedure */
	    tooldata = data -> tag;
	    data -> Proc (tooldata);
	    if (data -> type == 0)
		DisplayBooleanTx (event -> window, data, FALSE, TRUE);
	    else
		DisplayBooleanPx (event -> window, data, FALSE, TRUE);
	    break;
	case ExposeWindow: 
	    data -> width = ((XExposeWindowEvent *) event) -> width;
	    data -> height = ((XExposeWindowEvent *) event) -> height;
	/* fall through */
	case ExposeRegion: 
	    if (data -> type == 0)
		DisplayBooleanTx (event -> window, data, FALSE, FALSE);
	    else
		DisplayBooleanPx (event -> window, data, FALSE, FALSE);
	    break;
	case EnterWindow: 
	    status = XQueryMouseButtons (event -> window, 
	    	&x, &y, &subW, &state);
	    if (state & allButtons) {
		if (data -> type == 0)
		    DisplayBooleanTx (event -> window, data, TRUE, FALSE);
		else
		    DisplayBooleanPx (event -> window, data, TRUE, FALSE);
	    }
	    break;
	case LeaveWindow: 
	    status = XQueryMouseButtons (event -> window, 
		&x, &y, &subW, &state);
	    if (state & allButtons) {
		if (data -> type == 0)
		    DisplayBooleanTx (event -> window, data, FALSE, FALSE);
		else
		    DisplayBooleanPx (event -> window, data, FALSE, FALSE);
	    }
	    break;
	default: 
	    returnCode = NOTHANDLED;
    }
    return (returnCode);
}



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

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

Status TDestroyBoolean (tw)
Window tw;
{
 /* ----->Delete the data in the table */
    DeleteEntry (tw, boolEntry);

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

/*
 * This procedure will create a boolean 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 TGetBooleanAttr (tw, arglist)
Window tw;			/* tool window */
Targ * arglist;
{
    extern  FontInfo * gfontinfo;
    BooleanData * data;
    int     return_code;	/* return code from window creation */
    int     i, error;

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

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

    while (arglist -> name) {
	switch (arglist -> name) {
	    case T_BOOLEAN_TYPE: 
		arglist -> data = (caddr_t) data -> type;
		break;
	    case T_BOOLEAN_TEXT0: 
		arglist -> data = (caddr_t) data -> text0;
		break;
	    case T_BOOLEAN_TEXT1: 
		arglist -> data = (caddr_t) data -> text1;
		break;
	    case T_BOOLEAN_PIXM0: 
		arglist -> data = (caddr_t) data -> pixm0;
		break;
	    case T_BOOLEAN_PIXM1: 
		arglist -> data = (caddr_t) data -> pixm1;
		break;
	    case T_BOOLEAN_FONTINFO: 
		arglist -> data = (caddr_t) data -> fontinfo;
		break;
	    case T_BOOLEAN_TXCOLOR: 
		arglist -> data = (caddr_t) data -> txcolor;
		break;
	    case T_BOOLEAN_PIXMW: 
		arglist -> data = (caddr_t) data -> width;
		break;
	    case T_BOOLEAN_PIXMH: 
		arglist -> data = (caddr_t) data -> height;
		break;
	    case T_BOOLEAN_HITYPE: 
		arglist -> data = (caddr_t) data -> hitype;
		break;
	    case T_BOOLEAN_BACKGRCOLOR: 
		arglist -> data = (caddr_t) data -> backgrcolor;
		break;
	    case T_BOOLEAN_BRCOLOR: 
		arglist -> data = (caddr_t) data -> brcolor;
		break;
	    case T_BOOLEAN_BRWIDTH: 
		arglist -> data = (caddr_t) data -> brwidth;
		break;
	    case T_BOOLEAN_SELSTATE: 
		arglist -> data = (caddr_t) data -> selstate;
		break;
	    case T_BOOLEAN_PROC: 
		arglist -> data = (caddr_t) data -> Proc;
		break;
	    case T_BOOLEAN_TAG: 
		arglist -> data = data -> tag;
		break;
	    default: 
	    /* eventually put in error message */
		break;
	}
	arglist++;
    }


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

/*
 * This procedure will create a boolean 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 TSetBooleanAttr (tw, arglist)
Window tw;			/* tool window */
Targ * arglist;
{
    extern  FontInfo * gfontinfo;
    BooleanData * data;
    int     return_code;	/* return code from window creation */
    int     twidth, theight;
    int     error;

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

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

    while (arglist -> name) {
	switch (arglist -> name) {
	    case T_BOOLEAN_TYPE: 
		data -> type = (int) arglist -> data;
		break;
	    case T_BOOLEAN_TEXT0: 
		data -> text0 = 
		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 */
		    data -> twidth0 = 
		    XStringWidth (data -> text0, data -> fontinfo, 0, 0);
		    data -> width = 
		    (short) twidth + data -> brwidth + borderdelta + 4;
		    data -> height = 
		    (short) theight + data -> brwidth + borderdelta + 8;
		}
		break;
	    case T_BOOLEAN_TEXT1: 
		data -> text1 = 
		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 */
		    data -> twidth1 = 
		    XStringWidth (data -> text1, data -> fontinfo, 0, 0);
		    data -> width = 
		    (short) twidth + data -> brwidth + borderdelta + 4;
		    data -> height = 
		    (short) theight + data -> brwidth + borderdelta + 8;
		}
		break;
	    case T_BOOLEAN_PIXM0: 
		data -> pixm0 = (Pixmap) arglist -> data;
		break;
	    case T_BOOLEAN_PIXM1: 
		data -> pixm1 = (Pixmap) arglist -> data;
		break;
	    case T_BOOLEAN_FONTINFO: 
		data -> fontinfo = (FontInfo *) arglist -> data;
	    /* add data changes later */
		break;
	    case T_BOOLEAN_TXCOLOR: 
		data -> txcolor = (int) arglist -> data;
		break;
	    case T_BOOLEAN_PIXMW: 
	    /* -----> Note window size is not changed at this time */
		data -> width = (int) arglist -> data;
		break;
	    case T_BOOLEAN_PIXMH: 
	    /* -----> Note window size is not changed at this time */
		data -> height = (int) arglist -> data;
		break;
	    case T_BOOLEAN_HITYPE: 
		data -> hitype = (int) arglist -> data;
		break;
	    case T_BOOLEAN_BACKGRCOLOR: 
		data -> backgrcolor = (int) arglist -> data;
		break;
	    case T_BOOLEAN_BRCOLOR: 
		data -> brcolor = (int) arglist -> data;
		break;
	    case T_BOOLEAN_BRWIDTH: 
		data -> brwidth = (int) arglist -> data;
		break;
	    case T_BOOLEAN_SELSTATE: 
		data -> selstate = (int) arglist -> data;
		break;
	    case T_BOOLEAN_PROC: 
		data -> Proc = (int (*) ()) arglist -> data;
		break;
	    case T_BOOLEAN_TAG: 
		data -> tag = arglist -> data;
		break;
	    default: 
		break;
	}
	arglist++;
    }


    if (data -> type == 0)
	DisplayBooleanTx (tw, data, 0);
    else
	DisplayBooleanPx (tw, data, 0);

}

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

/*
 * This procedure will create a boolean 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 TCreateBoolean (pw, arglist)
Window pw;			/* parent window */
Targ * arglist;
{
    extern  FontInfo * gfontinfo;
    BooleanData * data;
    int     return_code;	/* return code from window creation */
    int     twidth0, twidth1, twidth, theight;
    int     i;
    int    *ptr;
    int     dummy;
    int     descenddelta;
    OpaqueFrame * frame;	/* frame for data */

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

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

 /* -----> Set Default Values */
    data -> type = 0;
    data -> text0 = "DEFAULT0";
    data -> text1 = "DEFAULT0";
    data -> pixm0 = WhitePixmap;
    data -> pixm1 = BlackPixmap;
    data -> fontinfo = gfontinfo;
    data -> txcolor = BlackPixel;
    data -> width = 70;
    data -> height = 50;
    data -> hitype = NULL;	/* TBD */
    data -> backgrcolor = WhitePixmap;
    data -> brcolor = BlackPixmap;
    data -> brwidth = 2;
    data -> selstate = 1;
    data -> Proc = Dummy;
    data -> tag = NULL;

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

    while (arglist -> name) {
	switch (arglist -> name) {
	    case T_BOOLEAN_TYPE: 
		data -> type = (int) arglist -> data;
		break;
	    case T_BOOLEAN_TEXT0: 
		data -> text0 = 
		strcpy (Tmalloc (strlen ((char *) arglist -> data) + 1),
			(char *) arglist -> data);
		break;
	    case T_BOOLEAN_TEXT1: 
		data -> text1 = 
		strcpy (Tmalloc (strlen ((char *) arglist -> data) + 1),
			(char *) arglist -> data);
		break;
	    case T_BOOLEAN_PIXM0: 
		data -> pixm0 = (Pixmap) arglist -> data;
		break;
	    case T_BOOLEAN_PIXM1: 
		data -> pixm1 = (Pixmap) arglist -> data;
		break;
	    case T_BOOLEAN_FONTINFO: 
		data -> fontinfo = (FontInfo *) arglist -> data;
		break;
	    case T_BOOLEAN_TXCOLOR: 
		data -> txcolor = (int) arglist -> data;
		break;
	    case T_BOOLEAN_PIXMW: 
		data -> width = (int) arglist -> data;
		break;
	    case T_BOOLEAN_PIXMH: 
		data -> height = (int) arglist -> data;
		break;
	    case T_BOOLEAN_HITYPE: 
		data -> hitype = (int) arglist -> data;
		break;
	    case T_BOOLEAN_BACKGRCOLOR: 
		data -> backgrcolor = (Pixmap) arglist -> data;
		break;
	    case T_BOOLEAN_BRCOLOR: 
		data -> brcolor = (Pixmap) arglist -> data;
		break;
	    case T_BOOLEAN_BRWIDTH: 
		data -> brwidth = (int) arglist -> data;
		break;
	    case T_BOOLEAN_SELSTATE: 
		data -> selstate = (int) arglist -> data;
		break;
	    case T_BOOLEAN_PROC: 
		data -> Proc = (int (*) ()) arglist -> data;
		break;
	    case T_BOOLEAN_TAG: 
		data -> tag = arglist -> data;
	    default: 
		break;
	}
	arglist++;
    }



    if (data -> type == 0) {
    /* -----> obtain text dimensions and calculate the window size */
	data -> twidth0 = XStringWidth (data -> text0, data -> fontinfo, 0, 0);
	data -> twidth1 = XStringWidth (data -> text1, data -> fontinfo, 0, 0);
	data -> theight = data -> fontinfo -> height;
	if (data -> twidth1 > data -> twidth0)
	    twidth = data -> twidth1;
	else
	    twidth = data -> twidth0;

	data -> width = twidth + data -> brwidth +
	    borderdelta + 8;
	data -> height = data -> theight + (2 * borderdelta);
    }

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

    SaveEntry (tw, boolEntry, data);

    TSetXEventDispatch (tw, TProcessBooleanEvent, boolEvents, 0);

    return (tw);
}
