/*
	Checkbook - a demo of GIL scrolling list functions
	
	Version 1: This version supports editing checks in
	           the popup window.  The scrolling list
	           of checks is not implemented in this version.
*/

#include "geosim.h"
#include 

/* Application parameters */
#define NAME "Checkbook"
#define IFILE "sclist1.inf"
#define USE_BSTORE 1

#define MIN_NUMBER 100
#define MAX_NUMBER 500

#define MIN_AMOUNT 1
#define MAX_AMOUNT 1000

#define MAX_PAYEE_LEN 30
/*   */


/* Interface element names */
#define LIST_WINDOW "ListWindow"

#define UP_BTN "list_up"
#define DOWN_BTN "list_down"
#define LIST_DA "list"
#define SCROLLBAR_DA "scroll_bar"

#define CHECK_WINDOW "CheckWindow"

#define NUMBER_FLD "number"
#define PAYEE_FLD "payee"
#define AMOUNT_FLD "amount"

#define NUMBER_INC_BTN "number_inc"
#define NUMBER_DEC_BTN "number_dec"
#define AMOUNT_INC_BTN "amount_inc"
#define AMOUNT_DEC_BTN "amount_dec"

#define CHAR_FUNC "char_func"
/*   */


/* Typedefs */
typedef struct {
	int number, amount;
	BigString payee;
	} CheckType;
	
typedef enum {
	NOT_SHOWN, ADD_STATE, EDIT_STATE
	} CheckWindState;
/*   */

/* Interface function prototypes */
bool redraw_func();
bool quit();
bool null_func();
bool add();
bool edit();
bool check_ok();
bool check_cancel();
bool char_func(int, int, char);

bool number_inc();
bool number_dec();
bool amount_inc();
bool amount_dec();
/*   */


/* Other prototypes */
void initialize();
void init_data_window();
void display_checkwind();
void display_amount();
void display_payee();
void display_number();
/*   */

/* Globals */
CheckWindState wind_state = NOT_SHOWN;
CheckType edit_check;
int next_number;
int payee_len, ins_point;
/*   */


void main(int argc, char *argv[])
{
	GSinterfaceinit(NAME, IFILE, USE_BSTORE, "wc", G640x480x256, argc, argv);
	initialize();
	GSinterface();
}


/* 
	initialize()
*/

void initialize()
{
	GScharfunc(CHAR_FUNC);
	next_number=MIN_NUMBER;
}


/*
	redraw_func() : called when the GIL window needs to be redrawn
*/

bool redraw_func()
{
	GSredrawnamedwindow("root");
	GSredrawnamedwindow(LIST_WINDOW);
	
	if (wind_state != NOT_SHOWN) {
		GSredrawnamedwindow(CHECK_WINDOW);
		display_checkwind();
		}
}


/*
	quit() : called when the "Quit" button is pressed
*/

bool quit()
{
	GSquit(NULL);
	return TRUE;
}


/*
	add() : called when the "add" button is pressed
	Displays check entry window.
*/

bool add()
{
	edit_check.number = next_number++;
	edit_check.amount = 100;
	sprintf(edit_check.payee, "Payee");
	wind_state = ADD_STATE;
	
	init_data_window();
	
	return TRUE;
}


/*
	edit() : called when the "edit" button is pressed
	Displays check entry window.
*/

bool edit()
{
	wind_state = EDIT_STATE;
	
	init_data_window();
	
	return TRUE;
}


/*
	init_data_window() : called from add() and edit()
	Initializes "+" and "-" buttons in check entry window,
	sets text entry variables (ins_point and payee_len),
	displays check window and draws contents.
*/

void init_data_window()
{
	if (edit_check.number <= MIN_NUMBER)
		GSdisablebutton(CHECK_WINDOW, NUMBER_DEC_BTN, FALSE);
	else
		GSenablebutton(CHECK_WINDOW, NUMBER_DEC_BTN, FALSE);
		
	if (edit_check.amount <= MIN_AMOUNT)
		GSdisablebutton(CHECK_WINDOW, AMOUNT_DEC_BTN, FALSE);
	else
		GSenablebutton(CHECK_WINDOW, AMOUNT_DEC_BTN, FALSE);
	
	if (edit_check.number >= MAX_NUMBER)
		GSdisablebutton(CHECK_WINDOW, NUMBER_INC_BTN, FALSE);
	else
		GSenablebutton(CHECK_WINDOW, NUMBER_INC_BTN, FALSE);
		
	if (edit_check.amount >= MAX_AMOUNT)
		GSdisablebutton(CHECK_WINDOW, AMOUNT_INC_BTN, FALSE);
	else
		GSenablebutton(CHECK_WINDOW, AMOUNT_INC_BTN, FALSE);
		
	payee_len = strlen(edit_check.payee);
	ins_point = payee_len;
	
	GSdrawnamedwindow(CHECK_WINDOW, POPUP, BSTORE);
	display_checkwind();
}


/*
	check_ok() : called when the "OK" button in the check entry
	             window is pressed
	Removes check entry window.
*/

bool check_ok()
{
	GSremovenamedwindow(CHECK_WINDOW);

	wind_state = NOT_SHOWN;
}


/*
	check_cancel() : called when the "Cancel" button in the check
	             entry window is pressed
	Removes check entry window.
*/

bool check_cancel()
{
	GSremovenamedwindow(CHECK_WINDOW);

	wind_state = NOT_SHOWN;
}


/*
	null_func() : "do-nothing" function;  fill-in for missing
	              interface functions
*/

bool null_func()
{
	return TRUE;
}


/*
	number_inc() : called when "+" button for check number
	               is pressed
*/

bool number_inc()
{
	if (edit_check.number == MIN_NUMBER)
		GSenablebutton(CHECK_WINDOW, NUMBER_DEC_BTN, TRUE);
		
	edit_check.number++;
	
	if (edit_check.number == MAX_NUMBER)
		GSdisablebutton(CHECK_WINDOW, NUMBER_INC_BTN, TRUE);
		
	display_number();
	
	return TRUE;
}


/*
	number_decc() : called when "-" button for check number
	               is pressed
*/

bool number_dec()
{
	if (edit_check.number == MAX_NUMBER)
		GSenablebutton(CHECK_WINDOW, NUMBER_INC_BTN, TRUE);
		
	edit_check.number--;
	
	if (edit_check.number == MIN_NUMBER)
		GSdisablebutton(CHECK_WINDOW, NUMBER_DEC_BTN, TRUE);
		
	display_number();
	
	return TRUE;
}


/*
	amount_inc() : called when "+" button for check amount
	               is pressed
*/

bool amount_inc()
{
	if (edit_check.amount == MIN_AMOUNT)
		GSenablebutton(CHECK_WINDOW, NUMBER_DEC_BTN, TRUE);
		
	edit_check.amount++;
	
	if (edit_check.amount == MAX_AMOUNT)
		GSdisablebutton(CHECK_WINDOW, NUMBER_INC_BTN, TRUE);
		
	display_amount();
	
	return TRUE;
}


/*
	number_dec() : called when "-" button for check amount
	               is pressed
*/

bool amount_dec()
{
	if (edit_check.amount == MAX_AMOUNT)
		GSenablebutton(CHECK_WINDOW, AMOUNT_INC_BTN, TRUE);
		
	edit_check.amount--;
	
	if (edit_check.amount == MIN_AMOUNT)
		GSdisablebutton(CHECK_WINDOW, AMOUNT_DEC_BTN, TRUE);
		
	display_amount();
	
	return TRUE;
}


/*
	display_amount() : called when check amount needs to be
	                   displayed
*/

void display_amount()
{
	int x, y, wd, ht;
	GSColor col;
	BigString str;
	
	GSsetcurrentnamedwindow(CHECK_WINDOW);
	GSsetfont(SMALL);
	
	GSgetfieldrect(AMOUNT_FLD, &x, &y, &wd, &ht, &col);
	
	GSsetcolor(col);	
	GSwfillrect(x, y, wd, ht);

	GSframefield(CHECK_WINDOW, AMOUNT_FLD, 
			GSconvertcolor("black"), GSconvertcolor("dgray"));

	GSsetcolor(GSconvertcolor("black"));

	sprintf(str, "$%d.%02d", edit_check.amount/100, /*(float)*/ (edit_check.amount%100));
	GSwwritemsg(x+1, y+SMALL+1, str);
}


/*
	display_payee() : called when check payee needs to be
	                  displayed
*/

void display_payee()
{
	int x, y, wd, ht;
	int curs_start, curs_len;
	char curs_char;
	
	GSColor col;
	BigString str;
	
	GSsetcurrentnamedwindow(CHECK_WINDOW);
	GSsetfont(SMALL);
	
	GSgetfieldrect(PAYEE_FLD, &x, &y, &wd, &ht, &col);
	
	GSsetcolor(col);	
	GSwfillrect(x, y, wd, ht);

	GSframefield(CHECK_WINDOW, PAYEE_FLD, 
			GSconvertcolor("black"), GSconvertcolor("dgray"));

	GSsetcolor(GSconvertcolor("black"));

	GSwwritemsg(x+1, y+SMALL+1, edit_check.payee);
	
	/* underline current position */
	
	sprintf(str, "%s", edit_check.payee);
	
	if (ins_point >= payee_len)
		curs_char = ' ';
	else
		curs_char = str[ins_point];
	
	str[ins_point] = '\0';
	curs_start = GStextwidth(str);
	str[0] = curs_char;
	str[1] = '\0';
	curs_len = GStextwidth(str);
	
	GSwdrawline(x+1+curs_start, y+SMALL+2, 
			x+1+curs_start+curs_len, y+SMALL+2);
}


/*
	display_number() : called when check number needs to be
	                   displayed
*/

void display_number()
{
	int x, y, wd, ht;
	GSColor col;
	BigString str;
	
	GSsetcurrentnamedwindow(CHECK_WINDOW);
	GSsetfont(SMALL);
	
	GSgetfieldrect(NUMBER_FLD, &x, &y, &wd, &ht, &col);
	
	GSsetcolor(col);	
	GSwfillrect(x, y, wd, ht);

	GSframefield(CHECK_WINDOW, NUMBER_FLD, 
			GSconvertcolor("black"), GSconvertcolor("dgray"));

	GSsetcolor(GSconvertcolor("black"));

	sprintf(str, "%d", edit_check.number);
	GSwwritemsg(x+1, y+SMALL+1, str);
}


/*
	display_checkwind() : called when entire check window 
	                      contents need to be displayed
*/

void display_checkwind()
{
	display_number();
	display_payee();
	display_amount();
}


/*
	char_func() : called by GIL when a key is pressed
	Processes key presses;  handles typing chars, backspace,
	and arrow keys.
*/

bool char_func(int x, int y, char ch)
{
	int i;
	
	/* if check entry window is not displayed, don't
	   do anything */
	   
	if (wind_state == NOT_SHOWN)
		return;
		
		
	/* update payee string and redraw payee field */
		
	switch (ch) {
	
		case KeyLeft:
			if (ins_point > 0)
				ins_point--;
			break;
			
		case KeyRight:
			if (ins_point < payee_len)
				ins_point++;
			break;
			
		case '\b':
			if (ins_point > 0) {
				
				/* delete character before ins_point */
				
				for (i=ins_point-1; i < payee_len; i++)
					edit_check.payee[i] = edit_check.payee[i+1];
					
				payee_len--;
				ins_point--;
				}
			break;
		
		default:
			if ((ch >= ' ') && (ch <= '~') && (payee_len < MAX_PAYEE_LEN)) {
				
				/* insert ch at ins_point */
				
				for (i=payee_len; i >= ins_point; i--)
					edit_check.payee[i+1] = edit_check.payee[i];
					
				edit_check.payee[ins_point] = ch;
				payee_len++;
				ins_point++;
				}
			break;
		}
	
	display_payee();
	
	return TRUE;
}
	
IntrFunction FuncNames[] = {
	{"redraw_func", redraw_func},
	{"quit", quit},
	{"add", add},
	{"edit", edit},
	{"delete", null_func},
	{"OK", check_ok},
	{"Cancel", check_cancel},
	{"number_inc", number_inc},
	{"number_dec", number_dec},
	{"amount_inc", amount_inc},
	{"amount_dec", amount_dec},
	{"char_func", (bool(*)())char_func},
	};
	
int NumFuncs = GSnumifuncs(FuncNames);

back