/* Next available MSG number is  21 */
/*
	       ADS Programmable Dialog Box Test Program 

   DLGTEST.C

   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994 by Autodesk, Inc.
 
   Permission to use, copy, modify, and distribute this software in 
   object code form 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 the limited warranty and 
   restricted rights notice below appear in all supporting 
   documentation.
 
   AUTODESK PROVIDES THIS PROGRAM "AS IS" AND WITH ALL FAULTS.  
   AUTODESK SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTY OF 
   MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE.  AUTODESK, INC.
   DOES NOT WARRANT THAT THE OPERATION OF THE PROGRAM WILL BE 
   UNINTERRUPTED OR ERROR FREE.
 
   Use, duplication, or disclosure by the U.S. Government is subject to 
   restrictions set forth in FAR 52.227-19 (Commercial Computer 
   Software - Restricted Rights) and DFAR 252.227-7013(c)(1)(ii) 
   (Rights in Technical Data and Computer Software), as applicable.
    
   .

    Programmable Dialog Box Test Program

	 This program is the ADS counterpart to the LISP test
    program, dlgtest.lsp.  It provides a simple dimensioning
    dialog invoked with the command "dimen" and a simple color
    dialog invoked with the command "setcolor".

	 The purposes of providing this program:
    1) Demonstrate Programmable Dialog Box use with minimum of code
	to sort through
    2) Demonstrate differences between LISP and ADS dialog 
	programming
    3) Use as a starting point to try out new dialog code

	 Dlgtest uses the file dlgtest.dcl as the DCL (Dialog 
    Control Language) file.

	 ADS functions are associated with dialog buttons with 
    the ads_action_tile functions.  These functions are called 
    when the user presses buttons during the ads_start_dialog 
    function.

    Special tile names (keys): 
        "accept" - Ok button
        "cancel" - Cancel button

*/


#include <stdio.h>
#include <string.h>

#include "adslib.h"
#include "adsdlg.h"


/* All Function Prototypes for DLGTEST.C */

void main _((int argc, char *argv[]));
int loadfuncs _((void));
int dofun _((void));
void setdimen _((void));
void get_dimvars _((ads_hdlg hdlg));
void set_dimvars _((ads_hdlg hdlg));
void CALLB dimen_ok   _((ads_callback_packet *cpkt));
void CALLB editcol_cb _((ads_callback_packet *cpkt));
void CALLB listcol_cb _((ads_callback_packet *cpkt));
void CALLB help_cb    _((ads_callback_packet *cpkt));
int setcolor _((void));

#ifdef __STDC__
/* With an old style definition, the short code parameter is promoted to an
   int, and so a short parameter should be prototyped as an int.  This is
   ANSI C. */
void dlg_colortile _((ads_hdlg hdlg, char *key, int color, int borderflag));
void dlg_rect _((int x, int y, int width, int height, int color));
#else
void dlg_colortile _((ads_hdlg hdlg, char *key, short color, int borderflag));
void dlg_rect _((short x, short y, short width, short height, short color));
#endif


/* Subroutines names to be registered with AutoLisp and provided in this
   application. */

static char *exfun[] = {/*MSG0*/"C:dimen", /*MSG0*/"C:setcolor", NULL};


static char *dimbools[] = {
    /*MSG0*/"dimse1", 
    /*MSG0*/"dimse2", 
    /*MSG0*/"dimtih", 
    /*MSG0*/"dimtoh",
    /*MSG0*/"dimtad",
    /*MSG0*/"dimtol", 
    /*MSG0*/"dimlim", 
    /*MSG0*/"dimalt", 
    /*MSG0*/"dimaso",
    /*MSG0*/"dimsho",
    NULL
   };

static char *dimreals[] = {
    /*MSG0*/"dimasz", 
    /*MSG0*/"dimtsz", 
    /*MSG0*/"dimtxt", 
    /*MSG0*/"dimcen",
    /*MSG0*/"dimexo",
    /*MSG0*/"dimexe", 
    /*MSG0*/"dimdle", 
    NULL
   };

#ifndef BLACK
#define    BLACK    0
#define    RED	    1
#define    YELLOW   2
#define    GREEN    3
#define    CYAN     4
#define    BLUE     5
#define    MAGENTA  6
#define    WHITE    7
#endif

static short color;
#define CLEN 32
static char colorstr[CLEN+1];

static char *colorlist[] = {
    /*MSG1*/"black", 
    /*MSG2*/"red", 
    /*MSG3*/"yellow", 
    /*MSG4*/"green", 
    /*MSG5*/"cyan", 
    /*MSG6*/"blue",
    /*MSG7*/"magenta", 
    /*MSG8*/"white"
   };



/* MAIN -- the main routine */
void
/*FCN*/main(argc,argv)
  int argc; char *argv[];
{
    short scode = RSRSLT;
    int stat;
    char errmsg[80];

    ads_init(argc, argv);

    for ( ;; ) {

	if ((stat = ads_link(scode)) < 0) {
	    sprintf(errmsg,
                    /*MSG9*/"DLGTEST: bad status from ads_link() = %d\n",
		    stat);
#ifdef Macintosh
	    macalert(errmsg);
#else
	    puts(errmsg);
	    fflush(stdout);
#endif /* Macintosh */
	    exit(1);
	}

	scode = RSRSLT; 	      /* default return code */

	/* Check for AT LEAST the following cases here */
	switch (stat) {

	    /* Load or define Lisp functions */
	case RQXLOAD:		      /* Load request.	Send function defuns */
	    scode = loadfuncs() ? -RSRSLT : -RSERR;
	    break;

	    /* Unload or undefine ALL functions previously defined. */
	case RQXUNLD:		      /* Unload request. Do cleanup */
	    /* This defaults to sending an RSRSLT.  If you send an 
	       RSERR, you can refuse to unload the program, but Lisp
	       will still ask you to terminate. */
	    break;

            /* Execute a "loaded" function that was defined via RQXLOAD */
	case RQSUBR:
	    dofun();
	    break;

	default:
	    break;
	}
    }
}



/* LOADFUNCS  --  Define external functions with AutoLISP */
static int
/*FCN*/loadfuncs()
{
    int i;

    for (i = 0; exfun[i] != NULL; i++) {
	if (!ads_defun(exfun[i], i))
	    return FALSE;
    }
    ads_printf(/*MSG10*/"Functions: 1-dimen 2-setcolor.\n");
    return TRUE;

}

/* Execute a defined function. */

static int
/*FCN*/dofun()
{
    int id;
    struct resbuf *rb;

    /* Get the function code from the combuf */
    if ((id = ads_getfuncode()) < 0)
	return 0;

    if ((rb = ads_getargs()) != NULL) {
        ads_printf("No arguments expected");
	ads_relrb(rb);
    }

    switch (id) {		      /* Which function is called? */

    case 0:
	/* dimen -- AutoCAD dimensioning dialog */
	setdimen();
	break;

    case 1:
	/* setcolor -- AutoCAD color dialog */
	setcolor();
	break;

    default:
	break;
    }
    return 1;
}


/* 

		DIMEN -- Dimensioning Dialog

*/

/* Position of dialog, centered to start */
static int dimx = -1, 
	   dimy = -1; 

void
/*FCN*/setdimen()
{
    ads_hdlg hdlg;
    int dlg_status;
    int dcl_id;

    ads_load_dialog(/*MSG0*/"dlgtest.dcl", &dcl_id);
    if (dcl_id < 0) {
        ads_printf(/*MSG13*/"Error loading \"dlgtest.dcl\"\n");
	return;
    }
    /* Display the "dimensions" dialog */
    ads_new_positioned_dialog(/*MSG14*/"dimensions", dcl_id, 
			(CLIENTFUNC)0, dimx, dimy, &hdlg);
    if (hdlg == NULL) {
        ads_printf(/*MSG15*/"The ads_new_dialog function failed\n");
	ads_unload_dialog(dcl_id);
	return;
    }

    /* Register dimen_ok function with the OK button */
    ads_action_tile(hdlg, /*MSG0*/"accept", (CLIENTFUNC)dimen_ok);

    /* show current values in dialog */
    get_dimvars(hdlg);

    /* run the dialog */
    ads_start_dialog(hdlg, &dlg_status);

    /* free all memory for dialog */
    ads_unload_dialog(dcl_id);
}


/* DIMEN_OK -- callback function for OK button of dimension dialog.  */

static void CALLB
/*FCN*/dimen_ok(cpkt)
  ads_callback_packet *cpkt;
{
    /* User pressed OK button to end dialog.  Check modified data
       and send to AutoCAD. */
    set_dimvars(cpkt->dialog);
    ads_done_positioned_dialog(cpkt->dialog, 1, &dimx, &dimy);
}


/* Show current values in dialog */

void
/*FCN*/get_dimvars(hdlg)
  ads_hdlg hdlg;
{
    char *bitem;
    char *ritem;
    char **blist = dimbools;
    char **rlist = dimreals;
    char value[80];
    struct resbuf rb;

    for ( ; (bitem = *blist) != NULL; ++blist) {
	ads_getvar(bitem, &rb);
	if (rb.restype != RTSHORT) {
            ads_printf(/*MSG17*/"No such AutoCAD variable: %s\n", bitem);
	    if (rb.restype == RTSTR)
		free(rb.resval.rstring);
	    continue;
	}
        sprintf(value, "%d", rb.resval.rint);
	ads_set_tile(hdlg, bitem, value);
    }
    for ( ; (ritem = *rlist) != NULL; ++rlist) {
	ads_getvar(ritem, &rb);
	if (rb.restype != RTREAL) {
            ads_printf(/*MSG18*/"No such AutoCAD variable: %s\n", ritem);
	    if (rb.restype == RTSTR)
		free(rb.resval.rstring);
	    continue;
	}
	ads_rtos(rb.resval.rreal, -1, -1, value);
	ads_set_tile(hdlg, ritem, value);
    }
    ads_set_tile(hdlg, /*MSG0*/"test_item", /*MSG0*/"test_value");
}


/* set modified dimension variables in AutoCAD */

static void
/*FCN*/set_dimvars(hdlg)
  ads_hdlg hdlg;
{
    char *bitem;
    char *ritem;
    char **blist = dimbools;
    char **rlist = dimreals;
    char val[MAX_TILE_STR+1];
    struct resbuf rb;

    /* Check all the checkbox tiles for new values */
    for ( ; (bitem = *blist) != NULL; ++blist) {
	/* Get the new value of tiles */
	ads_get_tile(hdlg, bitem, val, MAX_TILE_STR);

	rb.restype = RTSHORT;
	rb.resval.rint = atoi(val);
	ads_setvar(bitem, &rb);
    }
    /* Check all the edit box tiles for new values */
    for ( ; (ritem = *rlist) != NULL; ++rlist) {
	/* Get the new value of tiles */
	ads_get_tile(hdlg, ritem, val, MAX_TILE_STR);
	rb.restype = RTREAL;
	ads_distof(val, -1, &rb.resval.rreal);
	ads_setvar(ritem, &rb);
    }
    ads_get_tile(hdlg, /*MSG0*/"test_item", /*MSG0*/"test_value", 50);
}



/* 

		SETCOLOR -- Color Dialog

*/

int
/*FCN*/setcolor()
{
    int idx;
    ads_hdlg hdlg;
    int dlg_status;
    struct resbuf rb;
    char *cptr, *ptr;
    short colorsave;
    char cname[10];
    int dcl_id;

    /* Load the dialog file */
    ads_load_dialog(/*MSG0*/"dlgtest.dcl", &dcl_id);
    if (dcl_id < 0) {
        ads_printf(/*MSG19*/"Error loading \"dlgtest.dcl\"\n");
	return -1;
    }
    /* initialize the setcolor dialog, no default callback function */
    ads_new_dialog(/*MSG0*/"setcolor", dcl_id, (CLIENTFUNC)0, &hdlg);
    if (hdlg == NULL) {
        ads_printf(/*MSG20*/"new_dialog for setcolor failed\n");
	ads_unload_dialog(dcl_id);
	return -1;
    }
    /* Get the current color from AutoCAD */
    ads_getvar(/*MSG0*/"CECOLOR", &rb);
    /* AutoCAD  currently returns  "human readable" colour strings
       like "1 (red)" for the standard colours.  Trim  the  string
       at  the	first space to guarantee we have a valid string to
       restore the colour later.  */
    cptr = rb.resval.rstring;
    ptr = strchr(cptr, ' ');
    if (ptr != NULL)
	*ptr = EOS;
    strcpy(colorstr, cptr);
    color = colorsave = atoi(colorstr);

    /* Update other tiles when one is changed by using callback
       functions */
    ads_action_tile(hdlg, /*MSG0*/"edit_col", (CLIENTFUNC)editcol_cb);
    ads_action_tile(hdlg, /*MSG0*/"list_col", (CLIENTFUNC)listcol_cb);

    ads_action_tile(hdlg, /*MSG0*/"help", (CLIENTFUNC)help_cb);

    /* Use the client data pointer to store the key of each tile,
       for convenient access during callbacks.	 We could use
       get_attr_string during the callbacks instead. */
    ads_client_data_tile(hdlg, /*MSG0*/"edit_col", /*MSG0*/"edit_col");
    ads_client_data_tile(hdlg, /*MSG0*/"list_col", /*MSG0*/"list_col");

    /* Fill list box */
    ads_start_list(hdlg, /*MSG0*/"list_col", LIST_NEW, 0);
    for (idx = 0; idx < 8; ++idx)
	ads_add_list(colorlist[idx]);
    for (idx = 8; idx < 256; ++idx) {
        sprintf(cname, "%d", idx);
	ads_add_list(cname);
    }
    ads_end_list();

    /* Show initial values in edit box, list box, and image tile */
    ads_set_tile(hdlg, /*MSG0*/"edit_col", colorstr);
    ads_set_tile(hdlg, /*MSG0*/"list_col", colorstr);
    dlg_colortile(hdlg, /*MSG0*/"show_image", color, TRUE);

    /* Hand control over to the dialog until OK or CANCEL is pressed */
    ads_start_dialog(hdlg, &dlg_status);

    /* Dialog ended with OK button, "accept"? */
    if (dlg_status == DLGOK) {
	if (color == 0)
            ads_command(RTSTR, /*MSG0*/"_.COLOUR", RTSTR, /*MSG0*/"_BYLAYER",
			RTNONE);
	else
            ads_command(RTSTR, /*MSG0*/"_.COLOUR", RTSHORT, color, RTNONE);
    }
    /* free all memory for dialog */
    ads_unload_dialog(dcl_id);

    return (dlg_status == DLGOK) ? color : colorsave;
}


/* EDITCOL_CB -- ADS callback for color edit box.  */

static void CALLB
/*FCN*/editcol_cb(cpkt)
  ads_callback_packet *cpkt;
{
    if (cpkt->value == NULL || cpkt->value[0] == EOS)
	return;

    ads_set_tile(cpkt->dialog, /*MSG0*/"list_col", cpkt->value);
    color = atoi(cpkt->value);
    dlg_colortile(cpkt->dialog, /*MSG0*/"show_image", color, TRUE);
}

#define MAXKEYLEN 32

/* LISTCOL_CB -- ADS callback for color edit box.  */

static void CALLB
/*FCN*/listcol_cb(cpkt)
  ads_callback_packet *cpkt;
{
    char akey[MAXKEYLEN];

    if (cpkt->value == NULL || cpkt->value[0] == EOS)
	return;

    /* Get key */
    ads_get_attr_string(cpkt->tile, /*MSG0*/"key", akey, MAXKEYLEN);

    ads_set_tile(cpkt->dialog, /*MSG0*/"edit_col", cpkt->value);
    color = atoi(cpkt->value);
    dlg_colortile(cpkt->dialog, /*MSG0*/"show_image", color, TRUE);
}

/*HELP_CB -- ADS callback for help button.  */

static void CALLB
/*FCN*/help_cb(cpkt)
  ads_callback_packet *cpkt;
{
    /* request main Acad help, just to show you can do it. */
    ads_help(NULL, NULL, 0);
}





/* DLG_COLORTILE -- Color a tile.  "dialog" can be NULL to use the
                    current dialog.  Values for "color" may be 0 to
                    255.  "color" may be one of the defines in
		    colours.h, such as RED.   Draws border if
		    borderflag is TRUE. */

void
/*FCN*/dlg_colortile(hdlg, key, color, borderflag)
  ads_hdlg hdlg;
  char *key;
  short color;
  int borderflag;
{
    short width, height;

    ads_dimensions_tile(hdlg, key, &width, &height);
    ads_start_image(hdlg, key);
    ads_fill_image(0, 0, width, height, color);

    if (borderflag) {
	/* Put border around color */
	dlg_rect(0, 0, width, height, WHITE);
    }
    ads_end_image();
}



/* DLG_RECT -- Draw a rectangle in an image tile.  Use tile dimensions
	       to draw border around tile.  Assumes start_image
	       has been called. */

void
/*FCN*/dlg_rect(x, y, width, height, color)
  short x;
  short y;
  short width;
  short height;
  short color;
{
    short x2, y2;

    x2 = x + width - 1;
    y2 = y + height - 1;
    ads_vector_image(x,  y,  x,  y2, color);
    ads_vector_image(x,  y2, x2, y2, color);
    ads_vector_image(x2, y2, x2, y,  color);
    ads_vector_image(x2, y,  x,  y,  color);
}


