/****************************************************************************/
/*                                                                          */
/* STR_DEMO.C                                                               */
/*                                                                          */
/* We have had several customers experience difficulty understanding the    */
/* wn_gets function.  This is understandable, it is somewhat confusing.     */
/* This demo will help you understand the features, including several new   */
/* powerful features, and implement simpler forms to get basic items        */
/* such as time, date, phone numbers, etc.  The modified wn_gets is fully   */
/* compatible with the previous version so none of your code need change.   */
/* However, a new function called wn_gets_ll (which wn_gets calls)          */
/* has added the capability to uppercase the first char of each word,       */
/* strip the mask completely, only strip the end, or not strip at all.      */
/* It can also get input right-to-left, clear the entry on the first valid  */
/* key, and return when the last character of the input is typed.           */
/* Most importantly, it can allow the input of a string longer than the     */
/* display width of the field and will scroll within this region auto-      */
/* matically!  It can also display arrows to show the user that the string  */
/* has data to the left or right of the current display field.              */
/*                                                                          */
/* Two newer capabilities of wn_gets_ll are the validation function hook,   */
/* which can be called on each valid key pressed, and the gets hook, which  */
/* is called on wn_gets_ll entry, exit, and for every key pressed.  We will */
/* use the validation hook to show how you can do simple date validation,   */
/* and we will use the gets hook to print out the text, mask and template   */
/* strings for each key pressed, as well as make the F1 key perform a clear */
/* on the input.                                                            */
/*                                                                          */
/* Note:  Compile this file with the warning "parameter 'ident' is never    */
/*        used" turned off, as we don't have to actually use each parameter */
/*        included in the validation and gets hook functions.               */
/*                                                                          */
/*------------------------- flags for wn_gets_ll ---------------------------*/
/*                                                                          */
/* G_STRIP          strips the entire mask from the string.                 */
/*                * 12/04/91 = 120491, (432)-555-3421 = 4325553421					*/
/*                                                                          */
/* G_STRIP_END      strips the end of the string only only.					        */
/*                * John Doe______ = John Doe            										*/
/*                                                                          */
/* G_UP_FST_CHAR    converts the first letter of each word to uppercase.    */
/*                * this is a test = This Is A Test                         */
/*                                                                          */
/* G_ARROW          displays left and right arrows if display width is less */
/*                  than field width. NOTE: This requires an additional     */
/*                  screen/window space before and after the field.         */
/*                                                                          */
/* G_RIGHT_TO_LEFT  gets input from the right side of the string, scooting  */
/*                  characters over to the left for each valid press.       */
/*                                                                          */
/* G_CLEAR_ON_FIRST clears out the entry when the first valid key is        */
/*                  pressed.  This saves a CTRL-Y keystroke to clear the    */
/*                  entry.                                                  */
/*                                                                          */
/* G_EXIT_ON_FILL   causes the routine to exit whenever the last valid key  */
/*                  is pressed.  This saves an extra <Enter> press.         */
/*                                                                          */
/*--------------------------------------------------------------------------*/
/*                                                                          */
/* Understanding these few flags and looking at the below examples make     */
/* a very complex input routine much more managable!                        */
/*                                                                          */
/****************************************************************************/
#include <stdlib.h>
#include "uw.h"
#include "uw_globx.h"
#include "uw_keys.h"


/*-------------------------- a few global variables ------------------------*/
WINDOW Main_wn;
char name1[32],  name2[32],  name3[32],
		 phone1[16], phone2[16], phone3[16],
		 date1[16],  date2[16],  date3[16],
		 time1[16],  time2[16],  time3[16];


/*-------------------------- just some prototypes --------------------------*/
void msg_line( char *msg );
int my_gets(char *s, int max_len, int disp_width, int flags, int clear, WINDOW *wnp);
int my_get_phone(char *s, int disp_width, int flags, WINDOW *wnp);
int my_get_date(char *s, int disp_width, int flags, int clear, WINDOW *wnp);
int my_get_time(char *s, int disp_width, int flags, WINDOW *wnp);
int date_vld(char *w, char *t, char *m, int pos, int max_pos, WINDOW *wnp );
int time_vld(char *w, char *t, char *m, int pos, int max_pos, WINDOW *wnp );
int super_hook( char *text, char *template, char *mask, int pos,
								int max_pos, int p_flag, EVENT *eventp, WINDOW *wnp );


/*********/
/* ~main */
/*       ********************************************************************/
/****************************************************************************/
int main()
{
	int r;
	WINDOW *wnp;

	init_video(80, 25);
	init_clock(0x3333);
	wnp = &Main_wn;
	wn_create( 0, 0, V_cols-1, V_rows-1, DBL_BDR, WN_NORMAL, wnp );
	wn_color( WHITE, BLUE, wnp );
	wn_bdr_color( WHITE, BLUE, wnp );
	wn_set(wnp);
	wnp->inside = OFF;
	wn_plst(CENTERED, 0, "<<< EnQue's String Entry Demonstration >>>", wnp);
	wn_color(LIGHTGRAY, BLUE, wnp);
	wn_plst(CENTERED, 1, "F1 is translated to CTRL-Y and parameters displayed by the new gets hook.", wnp);

	/* NOTE:
		 When we use set_gets_hook or set_validation_func, we can just call the
		 name of the function when using good old "C", but we have to do the
		 wild-looking function pointer cast when we use the C++ compiler.
		 If you rename this "C" file to a "CPP" file and compile under Turbo or
		 Borland C++ you will get a "Type mismatch in parameter func_ptr"
		 compiler error (not warning) if you just use the function name without
		 the cast!
	*/

#ifdef __cplusplus
	set_gets_hook( (int (*)(...)) super_hook );
#else
	set_gets_hook( super_hook );
#endif

	wn_color( WHITE, BLUE, wnp );
	wnp->inside = ON;

/*---------- display full width and convert first char to uppercase --------*/
	r = 2;
	msg_line("Entry with first letters capped and no strip");
	wn_plst(  2, r, "Enter your name  : ", wnp );
	my_gets(name1, 22, 22, G_UP_FST_CHAR, 1, wnp);
	wn_plst( 50, r, name1, wnp );

/*----------- display full width with strip to end and exit on fill --------*/
	r++;
	msg_line("Entry with strip to end and exit on fill");
	wn_plst(  2, r, "Enter your name  : ", wnp );
	my_gets(name2, 22, 22, G_STRIP_END | G_EXIT_ON_FILL, 1, wnp);
	wn_plst( 50, r, name2, wnp );

/*---------- display only 6 characters, strip the entire mask, -------------*/
/*---------- convert first char, and display arrows...         -------------*/
	r++;
	msg_line("Entry with first letters capped, strip, scrolling, and arrow chars");
	wn_plst(  2, r, "Enter your name  :  ", wnp );
	my_gets(name3, 22, 6, G_STRIP | G_UP_FST_CHAR | G_ARROW, 1, wnp);
	wn_plst( 50, r, name3, wnp );

/*---------- display full width, strip the entire mask, --------------------*/
/*---------- convert first char, and clear on first key --------------------*/
	r++;
	msg_line("Entry with first letters capped, strip, and clear on first");
	wn_plst(  2, r, "Enter your name  : ", wnp );
/*	my_gets(name3, 22, 22, G_STRIP | G_UP_FST_CHAR | G_CLEAR_ON_FIRST, 0, wnp);*/
	my_gets(name3, 22, 22, G_STRIP | G_UP_FST_CHAR | G_INSERT | G_MOVE_TO_END, 0, wnp);
	wn_plst( 50, r, name3, wnp );

/*--------- display full width, strip to end, enter right-to-left ----------*/
	r += 2;
	msg_line("Right-to-left entry with strip to end");
	wn_plst(  2, r, "Enter your phone # : ", wnp );
	my_get_phone(phone1, 14, G_STRIP_END | G_RIGHT_TO_LEFT, wnp);
	wn_plst( 50, r, phone1, wnp );

/*------------------- display full width, don't strip mask -----------------*/
/*------------------- and exit when the last char is entered ---------------*/
	r++;
	msg_line("Entry without strip and exit on fill");
	wn_plst(  2, r, "Enter your phone # : ", wnp );
	my_get_phone(phone2, 14, G_EXIT_ON_FILL, wnp);
	wn_plst( 50, r, phone2, wnp );

/*----------------- display 5 chars and strip the entire mask --------------*/
	r++;
	msg_line("Entry with strip and scrolling, but without arrow chars");
	wn_plst(  2, r, "Enter your phone # : ", wnp );
	my_get_phone(phone3, 5, G_STRIP, wnp);
	wn_plst( 50, r, phone3, wnp );

#ifdef __cplusplus
	set_validation_func( (int (*)(...)) time_vld );
#else
	set_validation_func( date_vld );
#endif

/*--------------- display full width, strip the entire mask,----------------*/
/*--------------- use the validation hook to validate the date -------------*/
/*--------------- and exit when the last char is entered -------------------*/
	r += 2;
	msg_line("Entry with strip, validation, and exit on fill");
	wn_plst(  2, r, "Enter today's date: ", wnp );
	my_get_date(date1, 8, G_STRIP | G_VALIDATE | G_EXIT_ON_FILL, 1, wnp);
	wn_plst( 50, r, date1, wnp );

/*------------------- display full width, don't strip mask, ----------------*/
/*------------------- get the input right-to-left, and ---------------------*/
/*------------------- exit when the last char is entered -------------------*/
	r++;
	msg_line("Right-to-left entry without strip and with exit on fill");
	wn_plst(  2, r, "Enter today's date: ", wnp );
	my_get_date(date2, 8, G_RIGHT_TO_LEFT | G_EXIT_ON_FILL, 0, wnp);
	wn_plst( 50, r, date2, wnp );

/*----------------- display 5 chars, strip the entire mask, ----------------*/
/*----------------- and display with arrows --------------------------------*/
	r++;
	msg_line("Entry with strip, scrolling, and arrow characters");
	wn_plst(  2, r, "Enter today's date:  ", wnp );
	my_get_date(date3, 2, G_STRIP | G_ARROW, 1, wnp);
	wn_plst( 50, r, date3, wnp );

#ifdef __cplusplus
	set_validation_func( (int (*)(...)) time_vld );
#else
	set_validation_func( time_vld );
#endif

/*--------------- display full width and strip to the end ------------------*/
/*--------------- geting the input right-to-left ---------------------------*/
	r += 2;
	msg_line("Right-to-left entry with strip to end");
	wn_plst(  2, r, "Enter current time: ", wnp );
	my_get_time(time1, 5, G_STRIP_END | G_RIGHT_TO_LEFT, wnp);
	wn_plst( 50, r, time1, wnp );

/*------------- display full width, don't strip mask -----------------------*/
/*------------- and use the validation hook to validate the time -----------*/
	r++;
	msg_line("Entry without strip and with validation");
	wn_plst(  2, r, "Enter current time: ", wnp );
	my_get_time(time2, 5, G_VALIDATE, wnp);
	wn_plst( 50, r, time2, wnp );

/*----------------- display 5 chars and strip the entire mask, -------------*/
/*----------------- displaying arrows for scrolling ------------------------*/
	r++;
	msg_line("Entry with strip, scrolling, and arrow characters");
	wn_plst(  2, r, "Enter current time:  ", wnp );
	my_get_time(time3, 2, G_STRIP | G_ARROW, wnp);
	wn_plst( 50, r, time3, wnp );
	set_validation_func( NULL );

	set_gets_hook(NULL);

	msg_line("Demo complete, press any key to quit!");
	wait_event();
	wn_destroy(wnp);
	end_video();
	return(0);
}
/*** end of main ***/

/*************/
/* ~msg_line */
/*           ****************************************************************/
/* Display the message at the last line on the screen.                      */
/****************************************************************************/
void msg_line( char *msg )
{
	push(Main_wn.att);
	push(Main_wn.inside);
	Main_wn.inside = OFF;
	wn_color(BLACK, LIGHTGRAY, &Main_wn);
	mv_cs(0, 24, &Main_wn);
	wn_claol(&Main_wn);
	wn_plst(CENTERED, 24, msg, &Main_wn);
	pop(Main_wn.inside);
	pop(Main_wn.att);
}
/*** end of message_line ***/

/************/
/* ~my_gets */
/*          *****************************************************************/
/* This routine just sets up the mask and template strings and calls the    */
/* wn_gets_ll function.                                                     */
/****************************************************************************/
int my_gets(char *s, int max_len, int disp_width, int flags, int clear, WINDOW *wnp)
{
	char mask[81], template[81];

	if( clear )
		setmem(s,max_len,0);
	setmem(mask,max_len,'_'), mask[max_len] = '\0';
	setmem(template,max_len,'*'), template[max_len] = '\0';
	return(wn_gets_ll(s, mask, template, swap_nibbles(wnp->att),
		flags, disp_width, wnp));
}
/*** end of my_gets ***/

/*****************/
/* ~my_get_phone */
/*               ************************************************************/
/* This routine just sets up the mask and template strings and calls the    */
/* wn_gets_ll function.                                                     */
/****************************************************************************/
int my_get_phone(char *s, int disp_width, int flags, WINDOW *wnp)
{
	char *mask, *template;

	setmem(s,15,0);
	mask     = "(___)-___-____";
	template = " ###  ### ####";
	return(wn_gets_ll(s, mask, template, swap_nibbles(wnp->att),
		flags, disp_width, wnp));
}
/*** end of my_get_phone ***/

/****************/
/* ~my_get_date */
/*              *************************************************************/
/* This routine just sets up the mask and template strings and calls the    */
/* wn_gets_ll function.                                                     */
/****************************************************************************/
int my_get_date(char *s, int disp_width, int flags, int clear, WINDOW *wnp)
{
	char *mask, *template;

	if( clear )
		setmem(s,9,0);
	mask     = "__/__/__";
	template = "## ## ##";
	return(wn_gets_ll(s, mask, template, swap_nibbles(wnp->att),
		flags, disp_width, wnp));
}
/*** end of my_get_date ***/

/****************/
/* ~my_get_time */
/*              *************************************************************/
/* This routine just sets up the mask and template strings and calls the    */
/* wn_gets_ll function.                                                     */
/****************************************************************************/
int my_get_time(char *s, int disp_width, int flags, WINDOW *wnp)
{
	char *mask, *template;

	setmem(s,6,0);
	mask     = "__:__";
	template = "## ##";
	return(wn_gets_ll(s, mask, template, swap_nibbles(wnp->att),
		flags, disp_width, wnp));
}
/*** end of my_get_time ***/

/*************/
/* ~date_vld */
/*           ****************************************************************/
/* This is the validation function for dates.  The format is mm/dd/yy.      */
/****************************************************************************/
int date_vld(char *w, char *t, char *m, int pos, int max_pos, WINDOW *wnp )
{
	int ok = 1;

	if( !range('0',w[0],'1') && (w[0] != m[0]) )
			ok = 0, w[0] = m[0];
	if( w[0] == '0' )
	{
		if( !range('1',w[1],'9') && (w[1] != m[1]) )
				ok = 0, w[1] = m[1];
	}
	else if( w[0] == '1' )
	{
		if( !range('0',w[1],'2') && (w[1] != m[1]) )
				ok = 0, w[1] = m[1];
	}

	if( !range('0',w[3],'3') && (w[3] != m[3]) )
			ok = 0, w[3] = m[3];;
	if( w[3] == '3' )
	{
		if( !range('0',w[4],'1') && (w[4] != m[4]) )
				ok = 0, w[4] = m[4];;
	}else{
		if( !range('0',w[4],'9') && (w[4] != m[4]) )
				ok = 0, w[4] = m[4];;
	}
	if( !range('0',w[6],'9') && (w[6] != m[6]) )
			ok = 0, w[6] = m[6];;
	if( !range('0',w[7],'9') && (w[7] != m[7]) )
			ok = 0, w[7] = m[7];;

	if( !ok )
	{
		tone(1024,20);
		wn_plst( CENTERED, 18, "Invalid Date - Hit any key to continue", wnp );
		wait_event();
		wn_claol(wnp);
		return(0);
	}
	return(1);
}
/*** end of date_vld ***/

/*************/
/* ~time_vld */
/*           ****************************************************************/
/* This is the validation function for time.  The format is hh:mm.          */
/****************************************************************************/
int time_vld(char *w, char *t, char *m, int pos, int max_pos, WINDOW *wnp )
{
	int ok = 1;

	if( !range('0',w[0],'2') && (w[0] != m[0]) )
			ok = 0, w[0] = m[0];

	if( w[0] == '2' )
	{
		if( !range('0',w[1],'3') && (w[1] != m[1]) )
				ok = 0, w[1] = m[1];
	}else{
		if( !range('0',w[1],'9') && (w[1] != m[1]) )
				ok = 0, w[1] = m[1];
	}
	if( !range('0',w[3],'5') && (w[3] != m[3]) )
			ok = 0, w[3] = m[3];;
	if( !range('0',w[4],'9') && (w[4] != m[4]) )
			ok = 0, w[4] = m[4];;

	if( !ok )
	{
		tone(1024,20);
		wn_plst( CENTERED, 18, "Invalid Time - Hit any key to continue", wnp );
		wait_event();
		wn_claol(wnp);
		return(0);
	}
	return(1);
}
/*** end of time_vld ***/

/***************/
/* ~super_hook */
/*             **************************************************************/
/* This is the overall wn_gets_ll "super" hook.  We will use it for all     */
/* entries in this demo to show the parameters on the fly!  Note that this  */
/* function is only called when you call set_gets_hook(super_hook).  When   */
/* you want the wn_gets_ll function quit calling this function, just use    */
/* set_gets_hook(NULL).                                                     */
/* Notice that the display here at the bottom of the window stays "one      */
/* behind" the regular display above!  This is because this function is     */
/* called from withing wn_gets_ll BEFORE the key is processed.  What this   */
/* means to you is that you can take the key in the event and set it to     */
/* something you like better!!!  We will take the F1 key and translate it   */
/* into a CTRL-Y, commonly used to clear a string.                          */
/****************************************************************************/
int super_hook( char *text, char *template, char *mask, int pos,
								int max_pos, int p_flag, EVENT *eventp, WINDOW *wnp )
{
	switch(p_flag)
	{
		case H_ENTRY:																/* wn_gets_ll start					*/
			break;

		case H_EXIT:																/* wn_gets_ll end						*/
			break;

		case H_PROCESS:															/* each wn_gets_ll key!			*/
			if (eventp->key == KEY_F1)								/* make F1 clear the entry!	*/
				eventp->key = KEY_CTRL_Y;
			break;
	}
	push(wnp->csr_x);															/* we need to save the att  */
	push(wnp->csr_y);															/* and window cursor, since */
	push(wnp->att);																/* we are being called from */
	wn_color(YELLOW, BLUE, wnp);									/* within wn_gets_ll!       */
	mv_cs(10, 19, wnp);
	wn_printf(wnp, "    Text: %-25s     Pos: %02d", text, pos);
	wn_cleol(wnp);
	mv_cs(10, 20, wnp);
	wn_printf(wnp, "    Mask: %-25s Max Pos: %02d", mask, max_pos);
	wn_cleol(wnp);
	mv_cs(10, 21, wnp);
	wn_printf(wnp, "Template: %-25s     Key: 0x%04X", template, eventp->key);
	wn_cleol(wnp);
	pop(wnp->att);
	pop(wnp->csr_y);
	pop(wnp->csr_x);
	return(1);
}
/*** end of super_hook ***/


/**** END OF FILE ****/
