/* Checkbook - a demo of GIL scrolling list functions Final version: This version allows the user to add, edit, and delete checks. Checks are displayed in a scrolling list. */ #include "geosim.h" #include#include /* Application parameters */ #define NAME "Checkbook" #define IFILE "sclist.inf" #define USE_BSTORE 1 #define NUM_COLUMNS 3 #define MAX_CHECKS 30 #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 ADD_BTN "Add" #define EDIT_BTN "Edit" #define DELETE_BTN "Delete" #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" #define LIST_UP_BTN "list_up" #define LIST_DOWN_BTN "list_down" #define LIST_DA "list" #define SCROLLBAR_DA "scroll_bar" #define LIST_FLD "list_fld" /* */ /* 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(); char *label_func(int slot); void text_func(GSlistHandle list, int slot); void in_func(int slot) { } void out_func() { } void click_func(int slot); bool list(int x, int y, DragStatusType status); bool scroll_bar(int x, int y, DragStatusType status); bool list_up(); bool list_down(); /* */ /* 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; GSlistHandle list_handle; GSsclistHandle sclist_handle; CheckType *check[MAX_CHECKS]; int num_checks, cur_item; /* */ #define NO_ITEM -1 void main(int argc, char *argv[]) { GSinterfaceinit(NAME, IFILE, USE_BSTORE, "wc", G640x480x256, argc, argv); initialize(); GSinterface(); } /* initialize() */ void initialize() { int x, y, wd, ht; GScharfunc(CHAR_FUNC); next_number=MIN_NUMBER; num_checks = 0; cur_item = NO_ITEM; GSsclistsetup(LIST_WINDOW, LIST_DA, /* window, field names */ NUM_COLUMNS, /* number of columns */ LIST_FLD, /* picklist field */ 0, 0, /* row, column gaps */ JUST_LEFT, /* label justification */ label_func, /* list functions */ text_func, in_func, out_func, click_func, SCROLLBAR_DA, /* scroll bar dragarea name */ GSconvertcolor("sclistcol"), /* colors */ GSconvertcolor("sclisttl"), GSconvertcolor("sclistbr"), num_checks, 0, /* number of items, slot # of top item */ NULL, /* scroll notification */ LIST_UP_BTN, LIST_DOWN_BTN, /* button names */ &list_handle, &sclist_handle); /* list handles */ GSgetdragareaspecs(LIST_WINDOW, LIST_DA, &x, &y, &wd, &ht, NULL, NULL); GSsetcurrentnamedwindow(LIST_WINDOW); GSsetcolor(GSconvertcolor("black")); GSwdrawline(x-1, y-1, x-1, y+ht-1); GSwdrawline(x-1, y-1, x+wd-1, y-1); GSsetcolor(GSconvertcolor("dgray")); GSwdrawline(x+wd, y, x+wd, y+ht); GSwdrawline(x, y+ht, x+wd, y+ht); GSdrawsclist(sclist_handle); } /* redraw_func() : called when the GIL window needs to be redrawn */ bool redraw_func() { int x, y, wd, ht; GSredrawnamedwindow("root"); GSredrawnamedwindow(LIST_WINDOW); /* redraw list */ GSgetdragareaspecs(LIST_WINDOW, LIST_DA, &x, &y, &wd, &ht, NULL, NULL); GSsetcurrentnamedwindow(LIST_WINDOW); GSsetcolor(GSconvertcolor("black")); GSwdrawline(x-1, y-1, x-1, y+ht-1); GSwdrawline(x-1, y-1, x+wd-1, y-1); GSsetcolor(GSconvertcolor("dgray")); GSwdrawline(x+wd, y, x+wd, y+ht); GSwdrawline(x, y+ht, x+wd, y+ht); GSdrawsclist(sclist_handle); 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() { if (cur_item == NO_ITEM) { /* shouldn't get here, but better safe than sorry... */ GSdisablebutton("root", EDIT_BTN, TRUE); GSelog(0, "Error - edit button not disabled!\n"); return; } edit_check.number = check[cur_item]->number; edit_check.amount = check[cur_item]->amount; strcpy(edit_check.payee, check[cur_item]->payee); wind_state = EDIT_STATE; init_data_window(); return TRUE; } /* delete_check() : called when the "delete" button is pressed Removes current item from list. */ bool delete_check() { int i; if (cur_item == NO_ITEM) { /* shouldn't get here, but better safe than sorry... */ GSdisablebutton("root", DELETE_BTN, TRUE); GSelog(0, "Error - delete button not disabled!\n"); return; } free(check[cur_item]); for (i=cur_item; i < num_checks; i++) check[i] = check[i+1]; num_checks--; cur_item = NO_ITEM; GSdisablebutton("root", EDIT_BTN, TRUE); GSdisablebutton("root", DELETE_BTN, TRUE); GSsetcurrentnamedwindow(LIST_WINDOW); GSsetsclistnumitems(sclist_handle, num_checks*3, 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); if (wind_state == ADD_STATE) { CheckType *new_check = (CheckType *) malloc(sizeof(CheckType)); int i; if (new_check == NULL) GSelog(-1, "Out of memory for check %s\n", edit_check.payee); new_check->number = edit_check.number; new_check->amount = edit_check.amount; strcpy(new_check->payee, edit_check.payee); if (cur_item == NO_ITEM) /* add check to end of list */ check[num_checks] = new_check; else { /* insert new check after current item */ for (i=num_checks-1; i > cur_item; i--) check[i+1] = check[i]; cur_item++; check[cur_item] = new_check; } num_checks++; GSsetsclistnumitems(sclist_handle, num_checks*3, TRUE); if (num_checks == MAX_CHECKS) GSdisablebutton("root", ADD_BTN, TRUE); } else if (wind_state == EDIT_STATE) { check[cur_item]->number = edit_check.number; check[cur_item]->amount = edit_check.amount; strcpy(check[cur_item]->payee, edit_check.payee); GSdrawsclist(sclist_handle); } 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_dec() : 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; } /* text_func(GSlistHandle list, int slot) : sets up color for item */ void text_func(GSlistHandle list, int slot) { int check_num = slot / NUM_COLUMNS; if (check_num == cur_item) GSsetcolor(GSconvertcolor("curitem")); else GSsetcolor(GSconvertcolor("black")); } /* label_func(int slot) : returns character string for list element */ char *label_func(int slot) { static BigString label; int check_num = slot / NUM_COLUMNS; switch (slot % NUM_COLUMNS) { case 0: /* check number */ sprintf(label, "%d", check[check_num]->number); break; case 1: /* check payee */ sprintf(label, "%s", check[check_num]->payee); break; case 2: /* check amount */ sprintf(label, "%d.%02d", check[check_num]->amount/100, check[check_num]->amount%100); break; } return label; } /* click_func(int slot) : called when user clicks an item */ void click_func(int slot) { int i, old_item = cur_item; /* Since there is a selected item, enable "Edit" and "Delete". */ GSenablebutton("root", EDIT_BTN, TRUE); GSenablebutton("root", DELETE_BTN, TRUE); cur_item = slot / NUM_COLUMNS; GSsetcurrentnamedwindow(LIST_WINDOW); /* draw old and new list items to reflect selection change */ if (old_item != NO_ITEM) for (i=0; i < NUM_COLUMNS; i++) GSdrawlistitem(list_handle, New, old_item*NUM_COLUMNS + i); for (i=0; i < NUM_COLUMNS; i++) GSdrawlistitem(list_handle, New, cur_item*NUM_COLUMNS + i); } /* list() : list dragarea callback */ bool list(int x, int y, DragStatusType status) { GShandlelist(list_handle, x, y, status); return TRUE; } /* scroll_bar() : scroll bar dragarea callback */ bool scroll_bar(int x, int y, DragStatusType status) { GShandlesclist(sclist_handle, x, y, status); return TRUE; } /* list_up() : up button function */ bool list_up() { GShandleupbutton(sclist_handle); return TRUE; } /* list_down() : up button function */ bool list_down() { GShandledownbutton(sclist_handle); return TRUE; } IntrFunction FuncNames[] = { {"redraw_func", redraw_func}, {"quit", quit}, {"add", add}, {"edit", edit}, {"delete", delete_check}, {"list", list}, {"list_up", list_up}, {"list_down", list_down}, {"scroll_bar", scroll_bar}, {"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);