/********************************************************/ /* OTS_GUI.c - OpenTaxSolver Graphical User Interface. */ /* Based on OpenToolKit (OTK). */ /* */ /* The OTS_GUI is designed to read-in standard OTS data */ /* files, and present the tax information on your */ /* screen. It allows entering the values, saving */ /* return data, editing previously saved return sheets, */ /* and running the OTS tax-solver to compute your */ /* taxes. */ /* */ /* The OTS tax-solver is a text program which can be */ /* used by itself. This GUI front-end simplifies using */ /* OTS. It walks you through the steps and invokes the */ /* regular OTS solver when you are ready. */ /* */ /* OTS data files, for example "tax_xx.dat", contain */ /* the line numbers (or names) of the entries for a */ /* given tax form, as well as any previously entered */ /* values for each line. Additional comments may */ /* follow on any line. */ /* A few example lines follow: */ /* */ /* L15 ; { Rental income } */ /* L17 234.00 ; { Savings interest } */ /* L18 { Dividends } */ /* 23.00 { Bank1 } */ /* 14.50 ; { Work loan } */ /* */ /* OTS_GUI reads these lines and places a label for */ /* each line number/name, a text-box for filling in */ /* the value(s), and addtional labels for the comments. */ /* At the bottom are placed buttons to save and */ /* calculate-taxes. */ /* */ /* To compile this graphical program, you will need to */ /* grab the Open graphics Tool-Kit (Otk). */ /* Download Otk from: */ /* https://sourceforge.net/projects/otk/ */ /* It unpacks to a subdirectory called otk_lib. */ /* */ /* Compile: */ /* cc -I/usr/X11R6/include -L/usr/X11R6/lib ots_gui.c \ -lGLU -lGL -lXmu -lXext -lX11 -lm -o ots_gui */ /* */ /* */ /********************************************************/ float version=0.51; #include "otk_lib/otk_lib.c" /* Include the graphics library. */ int verbose=0; FILE *infile; int ots_column=0, ots_line=0; /* Input file position. */ #define MaxFname 900 char directory_bin[MaxFname]=".", wildcards_bin[MaxFname]="", filename_exe[MaxFname]=""; char directory_dat[MaxFname]=".", wildcards_dat[MaxFname]="*.dat", filename_dat[MaxFname]=""; char title_line[900], *working_file=0, *invocation_path; OtkWidget title_panel, title_label, main_panel, warningpopup=0, popup, commentbox; OtkTabbedPanel *TabbedPanel; void open_taxfile(); void save_taxfile(); #define VKIND_FLOAT 0 #define VKIND_INT 1 #define VKIND_TEXT 2 #define VKIND_COMMENT 3 #define VKIND_COLON 4 #define VALUE_LABEL 0 #define COMMENT 1 #define SEMICOLON 2 #define NOTHING 10 struct value_list { int kind; /* 0=float, 1=integer, 2=text, 3=comment. */ float value; char *comment, *text; int column, linenum; struct taxline_record *parent; OtkWidget box; struct value_list *nxt; }; struct taxline_record { char *linename; int linenum, format_offset; struct value_list *values_hd, *values_tl; /* Head and tail list pointers for a tax-line-entry. */ struct taxline_record *nxt; } *taxlines_hd=0, *taxlines_tl=0; /* Head and tail list pointers for tax-form. */ struct taxline_record * new_taxline( char *linename, int linenum ) { struct taxline_record *tmppt; tmppt = (struct taxline_record *)malloc(sizeof(struct taxline_record)); tmppt->linename = strdup(linename); tmppt->linenum = linenum; tmppt->format_offset = 0; tmppt->values_hd = 0; tmppt->values_tl = 0; tmppt->nxt = 0; if (taxlines_hd==0) taxlines_hd = tmppt; else taxlines_tl->nxt = tmppt; taxlines_tl = tmppt; return tmppt; } struct value_list * new_list_item_value( int kind, struct taxline_record *txline, void *x, int column, int linenum ) { struct value_list *tmppt; tmppt = (struct value_list *)malloc(sizeof(struct value_list)); tmppt->kind = kind; tmppt->text = 0; tmppt->comment = 0; tmppt->column = column; tmppt->linenum = linenum; tmppt->box = 0; switch (kind) { case VKIND_FLOAT: tmppt->value = *(float *)x; break; case VKIND_INT: tmppt->value = *(int *)x; break; case VKIND_TEXT: tmppt->text = strdup( (char *)x ); break; case VKIND_COMMENT: tmppt->comment = strdup( (char *)x ); break; } tmppt->parent = txline; tmppt->nxt = 0; if (txline==0) {printf("ERROR1: called add_value %d before any line.\n",kind); return tmppt;} if (txline->values_hd==0) txline->values_hd = tmppt; else txline->values_tl->nxt = tmppt; txline->values_tl = tmppt; return tmppt; } /*--------------------------------------------------------------*/ /* Get_Next_Entry - Reads next item from input file. */ /* Returns 0=VALUE_LABEL if reads data value or line-label. */ /* Returns 1=COMMENT if reads comment. */ /* Returns 2=SEMICOLON if reads ';' entry-end character. */ /* */ /* Passes back the column and line number where the current */ /* entry begins on the line in the input file. */ /*--------------------------------------------------------------*/ int get_next_entry( char *word, int maxn, int *column, int *linenum, FILE *infile ) { int k=0; /* Get up to the next non-white-space character. */ do { word[k] = getc(infile); if (word[k] == '\n') { ots_column = 0; ots_line++; } else ots_column++; } while ((!feof(infile)) && ((word[k]==' ') || (word[k]==' ') || (word[k]=='\n') || (word[k]==13))); *column = ots_column; *linenum = ots_line; if (feof(infile)) {word[0] = '\0'; return NOTHING;} if (word[k]=='{') { /*get_comment*/ do { word[k++] = getc(infile); if (word[k-1] == '\n') { ots_column = 0; ots_line++; } else ots_column++; } while ((!feof(infile)) && (word[k-1]!='}') && (k=maxn) {printf("Error: Character buffer overflow detected.\n"); exit(0);} return COMMENT; } /*get_comment*/ else { /*get_value_or_linelabel*/ k++; while ((!feof(infile)) && (word[k-1]!=' ') && (word[k-1]!=' ') && (word[k-1]!='\n') && (word[k-1]!=13) && (word[k-1]!=';') && (k=maxn) {printf("Error: Character buffer overflow detected.\n"); exit(0);} if (word[k-1]==';') { if (k==1) word[1] = '\0'; else { ungetc(word[k-1], infile); word[k-1] = '\0'; } return SEMICOLON; } else { word[k-1] = '\0'; return VALUE_LABEL; } } /*get_value_or_linelabel*/ } void DisplayTaxInfo(); void Update_box_info() /* Capture entries from form-boxes. */ { struct taxline_record *txline; struct value_list *tmppt; char text[100]; txline = taxlines_hd; while (txline!=0) { tmppt = txline->values_hd; while (tmppt!=0) { if (tmppt->box != 0) { Otk_Get_Text( tmppt->box, text, 100 ); tmppt->kind = VKIND_TEXT; tmppt->text = strdup( text ); } tmppt = tmppt->nxt; } txline = txline->nxt; } } void refresh() { int pannum; /* Determine the current panel. */ pannum = 0; while ((pannum < TabbedPanel->num) && (TabbedPanel->selection != TabbedPanel->selects[pannum].selection )) pannum++; /* Remove and recreate the page-panels with the new line item. */ Otk_RemoveObject( main_panel ); main_panel = OtkMakePanel( OtkOuterWindow, Otk_Raised, Otk_LightGray, 1, 7.5, 98, 87 ); /* Main Panel. */ Otk_SetBorderThickness( main_panel, 0.25 ); DisplayTaxInfo(); /* Set to display the original page. */ Otk_tabbed_panel_select( &(TabbedPanel->selects[pannum]) ); } /*--------------------------------------------------------------*/ /* Add_New_Boxes - Callback for "+" button on form-boxes. */ /* Adds new form-box(s) to the line item. */ /*--------------------------------------------------------------*/ void add_new_boxes( void *data, int num ) { struct taxline_record *txline; struct value_list *item, *lineitem, *newitem1, *newitem2, *oldtail; Update_box_info(); item = (struct value_list *)data; oldtail = item->parent->values_tl; newitem1 = new_list_item_value( VKIND_TEXT, item->parent, "", 0, item->linenum + 1 ); if (num>1) { new_list_item_value( VKIND_TEXT, item->parent, "", 0, item->linenum + 1 ); new_list_item_value( VKIND_TEXT, item->parent, "", 0, item->linenum + 2 ); newitem2 = new_list_item_value( VKIND_TEXT, item->parent, "", 0, item->linenum + 2 ); } else newitem2 = newitem1; lineitem = item; /* Skip the items on the original line. */ while ((lineitem->nxt!=newitem1) && (lineitem->nxt->linenum == item->linenum)) lineitem = lineitem->nxt; /* Insert in list and remove from tail, if not on end of list. */ if (lineitem->nxt != newitem1) { newitem2->nxt = lineitem->nxt; lineitem->nxt = newitem1; oldtail->nxt = 0; item->parent->values_tl = oldtail; } /* Increment the effective file-line-number of all subsequent line entries. */ lineitem = newitem2->nxt; while (lineitem!=0) /* Now do remaining lines of this item. */ { lineitem->linenum = lineitem->linenum + num; lineitem = lineitem->nxt; } txline = item->parent->nxt; /* Next do remaining line items. */ while (txline!=0) { txline->linenum = txline->linenum + num; lineitem = txline->values_hd; while (lineitem!=0) { lineitem->linenum = lineitem->linenum + num; lineitem = lineitem->nxt; } txline = txline->nxt; } refresh(); } /*-------------------------------------------------------------------------*/ /* Add_new_capgain_boxes - Callback for "+" button on cap-gain form-boxes. */ /* Adds a new form-boxes to the line item. */ /*-------------------------------------------------------------------------*/ void add_new_capgain_boxes( void *data ) { add_new_boxes( data, 2 ); } void add_new_box_item( void *data ) { add_new_boxes( data, 1 ); } void cancelpopup() { Otk_RemoveObject(popup); } void acceptcomment( void *data ) { char comment[500]; struct value_list *tmppt; tmppt = (struct value_list *)data; Otk_Get_Text( commentbox, comment, 500 ); tmppt->comment = strdup(comment); cancelpopup(); refresh(); } void acceptcomment2( char *s, void *x ) { acceptcomment( x ); } void edit_line_comment( void *data ) { char comment[1000]; struct value_list *tmppt; tmppt = (struct value_list *)data; strcpy(comment,tmppt->comment); popup = OtkMakeWindow( Otk_Raised, Otk_Blue, OtkSetColor(0.8,0.8,0.8), 10.0, 10.0, 80.0, 25.0 ); OtkMakeTextLabel( popup, "Edit Line Comment", Otk_Black, /*scale=*/ 1.5, /*weight=*/ 1, /*x=*/ 5, /*y=*/ 10 ); commentbox = OtkMakeTextFormBox( popup, comment, 60, 8, 35, 90, 22, acceptcomment2, tmppt ); OtkMakeButton( popup, 15, 75.0, 10, 14, " Ok ", acceptcomment, tmppt ); OtkMakeButton( popup, 80, 75.0, 10, 14, "Cancel", cancelpopup, 0 ); } /* Check if entry looks like a date. */ /* If so, return 1, else return 0. */ int datecheck( char *word ) { int j, k=0; j = strlen(word) - 1; while (j>0) { if ((word[j]=='-') || (word[j]=='/')) k++; else if (word[j]>'9') return 0; j--; } if (k==2) return 1; else return 0; } #if (PLATFORM_KIND!=Posix_Platform) char slashchr='\\'; #else char slashchr='/'; #endif /***********************/ /* Read Tax Data File. */ /***********************/ void Read_Tax_File( char *fname ) { int j, k, kind, state=0, column=0, linenum=0, linecnt=0, lastline=0, newentry=0; char word[10000], *tmpstr, tmpstr2[100], tmpstr3[100]; struct taxline_record *txline=0; struct value_list *tmppt, *newitem, *oldtail; /* Read the Tax Data Form File. */ working_file = strdup(fname); taxlines_hd = 0; /* Accept the form's Title line. (Must be first line!) */ fgets(word, 200, infile); strcpy(title_line, word); j = strlen(word); if (j>0) word[j-1] = '\0'; // printf("Title: '%s'\n", word); if (strstr(word,"Title:")==word) tmpstr = &(word[6]); else tmpstr = &(word[0]); k = strlen(tmpstr); /* Pad to center if title is too short. */ if (k<20) { for (j=0; j<(20-k)/2; j++) tmpstr2[k]=' '; tmpstr2[(20-k)/2] = '\0'; strcpy(tmpstr3,tmpstr2); strcat(tmpstr3,tmpstr); strcpy(tmpstr,tmpstr3); strcat(tmpstr,tmpstr2); } Otk_Modify_Text( title_label, tmpstr ); Otk_FitTextInPanel( title_label ); kind = get_next_entry( word, 10000, &column, &linenum, infile ); if (linenum > lastline) { lastline = linenum; if (newentry) linecnt++; newentry = 0; } while (!feof(infile)) { if (column==1) state = 0; if (verbose) printf("%d: state=%d: col=%d: lnum=%d: '%s'\n", kind, state, column, linenum, word); switch (kind) { case VALUE_LABEL: if (state==0) { if (verbose) printf(" LineLabel: %s\n", word); state = 1; txline = new_taxline( word, linecnt ); } else { if (verbose) printf(" Value: %s\n", word); if (strcasecmp(txline->linename, "Status")==0) { new_list_item_value( VKIND_TEXT, txline, word, column, linecnt ); state = 0; } else // if (datecheck(word)) { new_list_item_value( VKIND_TEXT, txline, word, column, linecnt ); } // else // { // if (sscanf(word, "%f",&x)!=1) printf("Error: reading '%s'\n",word); // new_list_item_value( VKIND_FLOAT, txline, &x, column, linecnt ); // } } newentry++; break; case COMMENT: if (verbose) printf(" Comment: %s\n", word); if (txline==0) txline = new_taxline("", linecnt); new_list_item_value( VKIND_COMMENT, txline, word, column, linecnt ); newentry++; break; case SEMICOLON: if (verbose) printf(" End: %s\n", word); state = 0; new_list_item_value( VKIND_COLON, txline, word, column, linecnt ); break; } column = column + strlen(word); kind = get_next_entry( word, 10000, &column, &linenum, infile ); if (linenum > lastline) { lastline = linenum; if (newentry) linecnt++; newentry = 0; } } fclose(infile); /* Check for missing entries. */ txline = taxlines_hd; while (txline!=0) { tmppt = txline->values_hd; state = 0; while (tmppt!=0) { if ((tmppt->kind==VKIND_FLOAT) || (tmppt->kind==VKIND_TEXT) || (tmppt->kind==VKIND_INT)) state = 1; tmppt = tmppt->nxt; } if ((state==0) && (strlen(txline->linename)>0)) /* Place empty formbox on any line having no entries. */ { oldtail = txline->values_tl; newitem = new_list_item_value( VKIND_TEXT, txline, "", 0, txline->linenum ); if (newitem!=txline->values_hd) { newitem->nxt = txline->values_hd; txline->values_hd = newitem; txline->values_tl = oldtail; oldtail->nxt = 0; } } txline = txline->nxt; } DisplayTaxInfo(); } void advance_panel( void *x ) { int pannum=0, direction; /* Determine the current panel. */ while ((pannum < TabbedPanel->num) && (TabbedPanel->selection != TabbedPanel->selects[pannum].selection )) pannum++; direction = (long)x; pannum = pannum + direction; if (pannum >= TabbedPanel->num) return; if (pannum < 0) return; /* Set to display the original page. */ Otk_tabbed_panel_select( &(TabbedPanel->selects[pannum]) ); } void check_comments() /* Make sure every line has a comment field. */ { struct taxline_record *txline; struct value_list *tmppt, *npt, *tail; int ncomments; txline = taxlines_hd; while (txline!=0) { ncomments = 0; tmppt = txline->values_hd; while (tmppt!=0) { if (tmppt->kind==VKIND_COMMENT) ncomments++; if ((tmppt->nxt==0) || (tmppt->linenum != tmppt->nxt->linenum)) { if (ncomments==0) { new_list_item_value( VKIND_COMMENT, txline, "", 50, tmppt->linenum); if (tmppt->nxt != txline->values_tl) { npt = txline->values_tl; tail = tmppt->nxt; while (tail->nxt != npt) tail = tail->nxt; tail->nxt = 0; txline->values_tl = tail; npt->nxt = tmppt->nxt; tmppt->nxt = npt; } } ncomments = 0; } tmppt = tmppt->nxt; } txline = txline->nxt; } } void status_choice_S( void *x ) { struct value_list *tmppt=(struct value_list *)x; Otk_Modify_Text( tmppt->box, "Single" ); } void status_choice_MJ( void *x ) { struct value_list *tmppt=(struct value_list *)x; Otk_Modify_Text( tmppt->box, "Married/Joint" ); } void status_choice_MS( void *x ) { struct value_list *tmppt=(struct value_list *)x; Otk_Modify_Text( tmppt->box, "Married/Sep" ); } void status_choice_HH( void *x ) { struct value_list *tmppt=(struct value_list *)x; Otk_Modify_Text( tmppt->box, "Head_of_Household" ); } void status_choice_W( void *x ) { struct value_list *tmppt=(struct value_list *)x; Otk_Modify_Text( tmppt->box, "Widow(er)" ); } #define lines_per_page 10 /*************************************************************************/ /* Display the Tax Info - This routine constructs, lays-out and poulates */ /* the panels. Called after initial read-in and on updates. */ /*************************************************************************/ void DisplayTaxInfo() { struct taxline_record *txline; struct value_list *tmppt; char **panelnames; OtkWidget pagept, label, button, cbutton; OtkTabbedPanel *Panels; char messg[500]; int j, nlines=1, npanels, page, linecnt=0, nchars=14, linenum, pagenum; int lastline, olinecnt, olinenum, offset=0, tchars, capgtoggle; float pos_x, pos_y, twidth, theight, x, leftmargin=0.0; float box_x=11.0, box_width=18.0, box_height=5.0; check_comments(); /* First count the number of lines to display. */ txline = taxlines_hd; while (txline!=0) { if (linecnt < txline->linenum + offset) linecnt = txline->linenum + offset; linenum = linecnt % lines_per_page; olinecnt = linecnt; tmppt = txline->values_hd; while (tmppt!=0) { if (linecnt < tmppt->linenum + offset) linecnt = tmppt->linenum + offset; tmppt = tmppt->nxt; } /* Don't start a new multi-line entry at bottom of a page. */ if ((linenum==lines_per_page-1) && (linecnt > olinecnt)) { txline->format_offset = 1; offset++; linecnt++; } else txline->format_offset = 0; txline = txline->nxt; } nlines = linecnt; /* Now create enough tabbed-panels to hold all the lines. */ npanels = nlines / lines_per_page + 1; panelnames = (char **)malloc( (npanels+1) * sizeof(char *)); for (j=0; jpanels[0]; offset = 0; OtkMakeTextLabel( pagept, panelnames[page], Otk_Black, 1.0, 1.0, 45.0, 2.0 ); txline = taxlines_hd; while (txline!=0) { offset = offset + txline->format_offset; pagenum = (txline->linenum + offset) / lines_per_page; linenum = (txline->linenum + offset) % lines_per_page; if (page < pagenum) /* Check to turn page. */ { page++; if (page>=npanels) {printf("Too many pages!\n"); exit(0);} pagept = Panels->panels[page]; OtkMakeTextLabel( pagept, panelnames[page], Otk_Black, 1.0, 1.0, 45.0, 2.0 ); } /* Place the line label. */ pos_x = 2.0; pos_y = (float)linenum * 9.0 + 8.0; olinenum = linenum; // printf("%d: Label %s\n", linenum, txline->linename ); label = OtkMakeTextLabel( pagept, txline->linename, Otk_Black, 1.0, 1.0, pos_x, pos_y ); if (strlen(txline->linename)>8) /* Squeeze size if too long. */ { x = 7.8 / (float)strlen(txline->linename); Otk_Modify_Text_Aspect( label, x*sqrt(x) ); Otk_Modify_Text_Scale( label, sqrt(sqrt(x)) ); } tmppt = txline->values_hd; lastline = -1; button = 0; capgtoggle = 0; while (tmppt!=0) { pagenum = (tmppt->linenum + offset) / lines_per_page; linenum = (tmppt->linenum + offset) % lines_per_page; if (page < pagenum) /* Check to turn page. */ { page++; if (page>=npanels) {printf("Too many pages!\n"); exit(0);} pagept = Panels->panels[page]; OtkMakeTextLabel( pagept, panelnames[page], Otk_Black, 1.0, 1.0, 45.0, 2.0 ); } if (lastline != linenum) leftmargin = box_x; switch (tmppt->kind) { case VKIND_FLOAT: sprintf(messg, "%12.2f", tmppt->value ); // printf("Formbox: '%s'\n", messg); pos_x = leftmargin; leftmargin = leftmargin + box_width + 1.5; pos_y = (float)linenum * 9.0 + 6.5; tmppt->box = OtkMakeTextFormBox( pagept, messg, nchars, pos_x, pos_y, box_width, box_height, 0, 0 ); button = OtkMakeButton( pagept, pos_x+box_width, pos_y+4.0, 1.5, 1.5, "+", add_new_box_item, tmppt ); /* Add another box - button */ Otk_Modify_Text_Scale( button->children, 0.8 ); lastline = linenum; break; case VKIND_INT: // printf(">>>Int: %d ", (int)(tmppt->value) ); break; case VKIND_TEXT: // printf(">>>Text: '%s'\n", tmppt->text ); pos_x = leftmargin; pos_y = (float)linenum * 9.0 + 6.5; twidth = box_width; tchars = nchars; if (lastline == linenum) { /* Cap-gains. */ twidth = 0.75 * box_width; tchars = 8; pos_x = pos_x + 1.0; if (button!=0) Otk_RemoveObject(button); button = 0; if (!capgtoggle) OtkMakeTextLabel( pagept, "Date Bought", Otk_Black, 0.75, 1.0, pos_x+1.0, pos_y-1.9 ); else OtkMakeTextLabel( pagept, "Date Sold", Otk_Black, 0.75, 1.0, pos_x+2.0, pos_y-1.9 ); capgtoggle = !capgtoggle; } leftmargin = leftmargin + twidth + 1.5; tmppt->box = OtkMakeTextFormBox( pagept, tmppt->text, tchars, pos_x, pos_y, twidth, box_height, 0, 0 ); if (capgtoggle==0) { if (strcmp(txline->linename,"Status")!=0) { if (lastline == linenum) button = OtkMakeButton( pagept, pos_x+twidth, pos_y+4.0, 1.5, 1.5, "+", add_new_capgain_boxes, tmppt ); /* Add another box - button */ else button = OtkMakeButton( pagept, pos_x+twidth, pos_y+4.0, 1.5, 1.5, "+", add_new_box_item, tmppt ); /* Add another box - button */ Otk_Modify_Text_Scale( button->children, 0.8 ); } else { button = Otk_Make_Menu( pagept, pos_x+box_width, pos_y+4.0, 2.0, 1.5, "??" ); Otk_Add_Menu_Item( button, "Single", status_choice_S, tmppt); Otk_Add_Menu_Item( button, "Married/Joint", status_choice_MJ, tmppt); Otk_Add_Menu_Item( button, "Married/Sep", status_choice_MS, tmppt); Otk_Add_Menu_Item( button, "Head_of_Household", status_choice_HH, tmppt); Otk_Add_Menu_Item( button, "Widow(er)", status_choice_W, tmppt); } } lastline = linenum; break; case VKIND_COMMENT: // printf("%d: Comment {%s}\n", linenum, tmppt->comment ); pos_x = leftmargin; pos_y = (float)linenum * 9.0 + 8.0; label = OtkMakeTextLabel( pagept, tmppt->comment, Otk_Black, 1.0, 1.0, pos_x, pos_y ); Otk_Get_Text_Size( label, &twidth, &theight ); if (twidth > (100.0-leftmargin-3.5)) /* Shrink width to fit on page if too long. */ { x = (100.0-leftmargin-3.5)/twidth; Otk_Modify_Text_Aspect( label, x * x ); } /* Add edit_line_comment button */ cbutton = OtkMakeButton( pagept, 97.0, (float)linenum * 9.0 + 10.5, 1.4, 1.4, "*", edit_line_comment, tmppt ); Otk_Modify_Text_Scale( cbutton->children, 0.9 ); break; } tmppt = tmppt->nxt; } txline = txline->nxt; } /* Add the 'advance' and go-back' paging buttons to bottom of each page. */ for (page=0; pagepanels[page]; if (page>0) { button = OtkMakeButton( pagept, 1.5, 96.0, 2.5, 2.5, "<", advance_panel, (void *)-1 ); Otk_Modify_Text_Scale( button->children, 1.1 ); } if (page", advance_panel, (void *)1 ); Otk_Modify_Text_Scale( button->children, 1.1 ); } } } void dump_taxinfo() { struct taxline_record *txline; struct value_list *tmppt; printf("\n======================================\n"); txline = taxlines_hd; while (txline!=0) { printf("\n%d: %s\n", txline->linenum, txline->linename ); tmppt = txline->values_hd; while (tmppt!=0) { switch (tmppt->kind) { case VKIND_FLOAT: printf("%d,F: %6.2f\n", tmppt->linenum, tmppt->value ); break; case VKIND_INT: printf("%d,I: %d\n", tmppt->linenum, (int)(tmppt->value) ); break; case VKIND_TEXT: printf("%d,T: %s\n", tmppt->linenum, tmppt->text ); break; case VKIND_COMMENT: printf("%d,C: {%s}\n", tmppt->linenum, tmppt->comment ); break; } tmppt = tmppt->nxt; } txline = txline->nxt; } printf("\n"); } void Save_Tax_File( char *filename ) { struct taxline_record *txline; struct value_list *tmppt; int lastline=-1, semicolon; FILE *outfile; /* Update the data structure(s) by getting the form fields. */ Update_box_info(); working_file = strdup(filename); outfile = fopen(filename,"w"); if (outfile==0) { printf("ERROR: Output file '%s' could not be opened for writing.\n", filename); save_taxfile(); return; } working_file = strdup(filename); fprintf(outfile,"%s\n", title_line); txline = taxlines_hd; while (txline!=0) { fprintf(outfile,"\n%s", txline->linename ); semicolon = 0; lastline = txline->linenum; tmppt = txline->values_hd; while (tmppt!=0) { if (tmppt->linenum != lastline) { fprintf(outfile,"\n"); lastline = tmppt->linenum; } switch (tmppt->kind) { case VKIND_FLOAT: fprintf(outfile," %6.2f ", tmppt->value ); break; case VKIND_INT: fprintf(outfile," %d ", (int)(tmppt->value) ); break; case VKIND_TEXT: fprintf(outfile," %s ", tmppt->text ); break; case VKIND_COMMENT: if (strlen(tmppt->comment)>0) fprintf(outfile," {%s}", tmppt->comment ); break; case VKIND_COLON: semicolon = 1; break; } tmppt = tmppt->nxt; } if (semicolon) fprintf(outfile,"\n ;"); txline = txline->nxt; } fclose(outfile); printf("\nWrote form-data to file %s\n.", filename); } void read_file( char *filename ) { infile = fopen(filename,"r"); if (infile==0) { printf("ERROR: Input file '%s' could not be opened.\n", filename); open_taxfile(); } else Read_Tax_File(filename); } void open_taxfile() { Otk_Browse_Files( "File to Open:", MaxFname, directory_dat, wildcards_dat, filename_dat, read_file ); } void save_taxfile() { Otk_Browse_Files( "File to Save:", MaxFname, directory_dat, wildcards_dat, filename_dat, Save_Tax_File ); } void predict_output_filename(char *indatafile, char *outfname) { int j; /* Base name of output file on input file. */ strcpy(outfname,indatafile); j = strlen(outfname)-1; while ((j>=0) && (outfname[j]!='.')) j--; if (j<0) strcat(outfname,".out"); else strcpy(&(outfname[j]),".out"); } void taxsolve(); char *taxsolvecmd=0, taxsolvestrng[MaxFname]=""; void settxslvcmd( char *filename ) { strcpy(taxsolvestrng,filename); taxsolve(); } void findtscmd() { Otk_RemoveObject(warningpopup); Otk_Browse_Files( "Select TaxSolver:", MaxFname, directory_bin, wildcards_bin, taxsolvestrng, settxslvcmd); } void canceltxslvr() { Otk_RemoveObject(warningpopup); } void taxsolve() { char cmd[MaxFname], outfname[MaxFname]; if (working_file==0) { printf("No tax file opened.\n"); warningpopup = OtkMakeWindow( Otk_Raised, Otk_Blue, OtkSetColor(0.8,0.8,0.8), 10.0, 10.0, 80.0, 30.0 ); OtkMakeTextLabel( warningpopup, "No tax file selected.", Otk_Red, /*scale=*/ 1.8, /*weight=*/ 2, /*x=*/ 3, /*y=*/ 10 ); OtkMakeTextLabel( warningpopup, "First select a tax file.", Otk_Red, /*scale=*/ 1.8, /*weight=*/ 2, /*x=*/ 10, /*y=*/ 25 ); OtkMakeButton( warningpopup, 20, 48.0, 60, 15, "Select Tax File Now", open_taxfile, 0 ); OtkMakeButton( warningpopup, 42.5, 75.0, 15, 15, " Cancel ", canceltxslvr, 0 ); return; } if (strlen(taxsolvestrng)>0) taxsolvecmd = taxsolvestrng; if (taxsolvecmd==0) taxsolvecmd = getenv("taxsolvecmd"); if (taxsolvecmd==0) { printf("The 'taxsolvecmd' environment variable is not set.\n"); warningpopup = OtkMakeWindow( Otk_Raised, Otk_Blue, OtkSetColor(0.8,0.8,0.8), 10.0, 10.0, 80.0, 30.0 ); OtkMakeTextLabel( warningpopup, "The 'taxsolvecmd' environment", Otk_Red, /*scale=*/ 1.8, /*weight=*/ 2, /*x=*/ 3, /*y=*/ 10 ); OtkMakeTextLabel( warningpopup, "variable is not set.", Otk_Red, /*scale=*/ 1.8, /*weight=*/ 2, /*x=*/ 10, /*y=*/ 25 ); OtkMakeButton( warningpopup, 20, 48.0, 60, 15, "Select TaxSolver Now", findtscmd, 0 ); OtkMakeButton( warningpopup, 42.5, 75.0, 15, 15, " Cancel ", canceltxslvr, 0 ); return; } if (PLATFORM_KIND==Posix_Platform) sprintf(cmd,"%s %s &", taxsolvecmd, working_file ); else sprintf(cmd,"%s %s", taxsolvecmd, working_file ); printf("Invoking '%s'\n", cmd ); system(cmd); /* Invoke the TaxSolver. */ /* Make a popup message telling where the results are. */ predict_output_filename(working_file, outfname); warningpopup = OtkMakeWindow( Otk_Raised, Otk_Blue, OtkSetColor(0.8,0.8,0.6), 10.0, 10.0, 80.0, 30.0 ); OtkMakeTextLabel( warningpopup, "Results written to file:", Otk_Black, /*scale=*/ 1.8, /*weight=*/ 2, /*x=*/ 3, /*y=*/ 10 ); OtkMakeTextLabel( warningpopup, outfname, Otk_Blue, /*scale=*/ 1.2, /*weight=*/ 1.2, /*x=*/ 5, /*y=*/ 35 ); OtkMakeButton( warningpopup, 42.5, 75.0, 15, 15, " Dismiss ", canceltxslvr, 0 ); } OtkWidget printpopup=0, printerformbox, printresultstog; char printer_command[MaxFname], wrkingfname[MaxFname]; #if (PLATFORM_KIND==POSIX_PLATFORM) char base_printer_command[]="lpr "; #else char base_printer_command[]="print "; #endif void cancelprintpopup0() { printpopup = 0; } void cancelprintpopup() { Otk_RemoveObject(printpopup); printpopup = 0; } void togprntcmd_in(void *x) { sprintf(printer_command,"%s %s", base_printer_command, wrkingfname); Otk_Modify_Text( printerformbox, printer_command ); } void togprntcmd_out(void *x) { char tmpstr[MaxFname]; int k; predict_output_filename(wrkingfname,tmpstr); sprintf(printer_command,"%s %s", base_printer_command, tmpstr); Otk_Modify_Text( printerformbox, printer_command ); } void acceptprinter_command( void *data ) { Otk_Get_Text( printerformbox, printer_command, MaxFname ); printf("Issuing: %s\n", printer_command); system(printer_command); cancelprintpopup(); refresh(); } void acceptprinter_command2( char *s, void *x ) { acceptcomment( x ); } void printout( void *data ) { if (printpopup!=0) return; printpopup = OtkMakeWindow( Otk_Raised, Otk_Blue, OtkSetColor(0.8,0.8,0.8), 10.0, 10.0, 80.0, 35.0 ); OtkMakeTextLabel( printpopup, "Print Return Data:", Otk_Black, /*scale=*/ 1.9, /*weight=*/ 1, /*x=*/ 2, /*y=*/ 3 ); OtkMakeTextLabel( printpopup, "Print Input Data", Otk_Black, /*scale=*/ 1.5, /*weight=*/ 1, /*x=*/ 20, /*y=*/ 20.0 ); printresultstog = OtkMakeRadioButton( printpopup, 53.0, 20.0, 10.0, 6.0, togprntcmd_in, 0 ); OtkMakeTextLabel( printpopup, "Print Output Results", Otk_Black, /*scale=*/ 1.5, /*weight=*/ 1, /*x=*/ 20, /*y=*/ 35.0 ); OtkMakeRadioButton( printresultstog, 53.0, 35.0, 10.0, 6.0, togprntcmd_out, 0 ); Otk_Add_BoundingBox( printpopup, Otk_Blue, 1.0, 18.0, 16.0, 63.0, 47.0 ); if (working_file==0) strcpy(wrkingfname,filename_dat); else strcpy(wrkingfname,working_file); sprintf(printer_command,"%s %s", base_printer_command, wrkingfname); OtkMakeTextLabel( printpopup, "Print Command:", Otk_Black, /*scale=*/ 1.5, /*weight=*/ 1, /*x=*/ 4, /*y=*/ 57 ); printerformbox = OtkMakeTextFormBox( printpopup, printer_command, 60, 28.5, 55, 68, 18, acceptprinter_command2, 0 ); OtkMakeButton( printpopup, 10, 80.0, 22, 12, " Print It", acceptprinter_command, 0 ); OtkMakeButton( printpopup, 80, 81.0, 14, 11, " Cancel ", cancelprintpopup, 0 ); Otk_RegisterWindowKillEventFunction( printpopup, cancelprintpopup0, 0 ); } void slcttxprog( void *data ) { char *strg=(char *)data, tmpstr[MaxFname]; int k; printf("Selected '%s'\n", strg); if (strcmp(strg,"Other")==0) { Otk_Browse_Files( "Select TaxSolver:", MaxFname, directory_bin, wildcards_bin, taxsolvestrng, settxslvcmd); return; } else { snprintf(tmpstr, sizeof(tmpstr), "%s%s", invocation_path, strg); printf("Setting Tax Program to be: '%s'\n", tmpstr); taxsolvecmd = strdup(tmpstr); strcpy(taxsolvestrng,tmpstr); strcpy(tmpstr,invocation_path); k = strlen(tmpstr)-1; while ((k>0) && (tmpstr[k]!=slashchr)) k--; if (k>0) k--; while ((k>0) && (tmpstr[k]!=slashchr)) k--; if (tmpstr[k]==slashchr) tmpstr[k+1] = '\0'; else {snprintf(tmpstr, sizeof(tmpstr), ".%c", slashchr);} snprintf(directory_dat, sizeof(directory_dat), "%sexamples_and_templates%c", "%%PREFIX%%/share/ots/", slashchr); /* CA_540 MA_1 NC_400 NJ_1040 NY_IT201 OH_1040 PA_40 US_1040 US_1040_Sched_C VA_760 */ if (strstr(strg,"CA_540")) strcat(directory_dat,"CA_540"); else if (strstr(strg,"MA_1")) strcat(directory_dat,"MA_1"); else if (strstr(strg,"NC_D400")) strcat(directory_dat,"NC_400"); else if (strstr(strg,"NJ_1040")) strcat(directory_dat,"NJ_1040"); else if (strstr(strg,"NY_IT201")) strcat(directory_dat,"NY_IT201"); else if (strstr(strg,"OH_IT1040")) strcat(directory_dat,"OH_1040"); else if (strstr(strg,"PA_40")) strcat(directory_dat,"PA_40"); else if (strstr(strg,"US_1040_Sched_C")) strcat(directory_dat,"US_1040_Sched_C"); else if (strstr(strg,"US_1040")) strcat(directory_dat,"US_1040"); else if (strstr(strg,"VA_760")) strcat(directory_dat,"VA_760"); printf("Setting Tax Data Directory to be: '%s'\n", directory_dat); } } void Ok2Quit() { printf("OTS Exiting.\n"); exit(0); } void QuitCallback( void *x ) { popup = OtkMakeWindow( Otk_Raised, Otk_Blue, OtkSetColor(0.8,0.8,0.8), 10.0, 10.0, 80.0, 25.0 ); OtkMakeTextLabel( popup, "Ok to QUIT ?", Otk_Red, /*scale=*/ 3.0, /*weight=*/ 2, /*x=*/ 20, /*y=*/ 20 ); OtkMakeButton( popup, 15, 70.0, 15, 18, " Ok Quit ", Ok2Quit, 0); OtkMakeButton( popup, 75, 70.0, 15, 18, "Cancel", cancelpopup, 0 ); } /*----------------------------------------------------------------------------*/ /* Main - */ /*----------------------------------------------------------------------------*/ int main(int argc, char *argv[] ) { int argn, k; char vrsnmssg[50], tmpstr[MaxFname]; OtkWidget subpanel, txprogstog; float x, y, dy, fontsz; FILE *testfile; /* Decode any command-line arguments. */ argn = 1; k=1; while (argn < argc) { if (strcmp(argv[argn],"-verbose")==0) { verbose = 1; argv[argn][0] = '\0'; } else if (k==1) { working_file = strdup(argv[argn]); infile = fopen(working_file,"r"); if (infile==0) {printf("ERROR: Parameter file '%s' could not be opened.\n", argv[argn]); exit(1);} k = 2; } else {printf("Unknown command-line parameter '%s'\n", argv[argn]); /* exit(1); */ } argn = argn + 1; } sprintf(vrsnmssg,"OTS GUI v%1.2f", version); printf("%s\n\n",vrsnmssg); invocation_path = strdup(argv[0]); k = strlen(invocation_path)-1; while ((k>0) && (invocation_path[k]!=slashchr)) k--; if (invocation_path[k]==slashchr) k++; invocation_path[k] = '\0'; printf("Invocation path = '%s'\n", invocation_path); strcpy(directory_bin,invocation_path); OtkInitWindow( 650, 740, argc, argv ); /* Open a window. */ title_panel = OtkMakePanel( OtkOuterWindow, Otk_Raised, Otk_LightGray, 1, 0.75, 98, 6 ); /* Title Panel. */ Otk_SetBorderThickness( title_panel, 0.7 ); title_label = OtkMakeTextLabel( title_panel, "Open-Tax-Solver", Otk_Blue, /*scale=*/ 3, /*weight=*/ 2, /*x=*/ 27, /*y=*/ 10 ); main_panel = OtkMakePanel( OtkOuterWindow, Otk_Raised, Otk_LightGray, 1, 7.5, 98, 87 ); /* Main Panel. */ Otk_SetBorderThickness( main_panel, 0.25 ); snprintf(tmpstr, sizeof(tmpstr), "%%PREFIX%%/share/ots/otslogo.ppm"); subpanel = OtkMakePanel( main_panel, Otk_Raised, Otk_LightGray, 20, 2, 60, 20 ); testfile = fopen(tmpstr,"r"); if (testfile!=0) { /* Only attempt to show image if image-file is where we expect to find it. */ fclose(testfile); OtkMakeImagePanel( subpanel, tmpstr, 1.5, 5.0, 96, 88 ); /* Logo Image. */ } taxsolvecmd = getenv("taxsolvecmd"); if (taxsolvecmd==0) { OtkMakeTextLabel( main_panel, "Select Tax Program:", Otk_Black, /*scale=*/ 2, /*weight=*/ 1, /*x=*/ 3, /*y=*/ 27 ); x = 8.0; y = 33.5; dy = 5.5; fontsz = 1.4; txprogstog = OtkMakeRadioButton( main_panel, x, y, 6.0, 3.0, slcttxprog, "taxsolve_US_1040_2006" ); OtkMakeTextLabel( main_panel, "US 1040 (w/Scheds A,B,D)", Otk_Black, /*scale=*/ fontsz, /*weight=*/ 1, x+7.0, y+0.6 ); slcttxprog("taxsolve_US_1040_2006"); /* Set as default solver. */ y = y + dy; OtkMakeRadioButton( txprogstog, x, y, 6.0, 3.0, slcttxprog, "taxsolve_US_1040_Sched_C_2006" ); OtkMakeTextLabel( main_panel, "US 1040 Sched C", Otk_Black, /*scale=*/ fontsz, /*weight=*/ 1, /*x=*/ x+7.0, y+0.6 ); y = y + dy; // OtkMakeRadioButton( txprogstog, x, y, 6.0, 3.0, slcttxprog, "taxsolve_CA_540_2006" ); OtkMakePanel( main_panel, Otk_Recessed, Otk_LightGray, x+1.0, y+0.7, 3.0, 2.0 ); OtkMakeTextLabel( main_panel, "CA State 540", Otk_Gray, /*scale=*/ fontsz, /*weight=*/ 1, /*x=*/ x+7.0, y+0.6 ); y = y + dy; // OtkMakeRadioButton( txprogstog, x, y, 6.0, 3.0, slcttxprog, "taxsolve_MA_1_2006" ); OtkMakePanel( main_panel, Otk_Recessed, Otk_LightGray, x+1.0, y+0.7, 3.0, 2.0 ); OtkMakeTextLabel( main_panel, "MA State 1", Otk_Gray, /*scale=*/ fontsz, /*weight=*/ 1, /*x=*/ x+7.0, y+0.6 ); y = y + dy; // OtkMakeRadioButton( txprogstog, x, y, 6.0, 3.0, slcttxprog, "taxsolve_NC_D400_2006" ); OtkMakePanel( main_panel, Otk_Recessed, Otk_LightGray, x+1.0, y+0.7, 3.0, 2.0 ); OtkMakeTextLabel( main_panel, "NC State DC400", Otk_Gray, /*scale=*/ fontsz, /*weight=*/ 1, /*x=*/ x+7.0, y+0.6 ); y = y + dy; // OtkMakeRadioButton( txprogstog, x, y, 6.0, 3.0, slcttxprog, "taxsolve_NJ_1040_2006.c" ); OtkMakePanel( main_panel, Otk_Recessed, Otk_LightGray, x+1.0, y+0.7, 3.0, 2.0 ); OtkMakeTextLabel( main_panel, "NJ State 1040", Otk_Gray, /*scale=*/ fontsz, /*weight=*/ 1, /*x=*/ x+7.0, y+0.6 ); x = 60.0; y = 33.5; // OtkMakeRadioButton( txprogstog, x, y, 6.0, 3.0, slcttxprog, "taxsolve_NY_IT201_2006" ); OtkMakePanel( main_panel, Otk_Recessed, Otk_LightGray, x+1.0, y+0.7, 3.0, 2.0 ); OtkMakeTextLabel( main_panel, "NY State IT201", Otk_Gray, /*scale=*/ fontsz, /*weight=*/ 1, /*x=*/ x+7.0, y+0.6 ); y = y + dy; // OtkMakeRadioButton( txprogstog, x, y, 6.0, 3.0, slcttxprog, "taxsolve_OH_IT1040_2006" ); OtkMakePanel( main_panel, Otk_Recessed, Otk_LightGray, x+1.0, y+0.7, 3.0, 2.0 ); OtkMakeTextLabel( main_panel, "OH State IT1040", Otk_Gray, /*scale=*/ fontsz, /*weight=*/ 1, /*x=*/ x+7.0, y+0.6 ); y = y + dy; // OtkMakeRadioButton( txprogstog, x, y, 6.0, 3.0, slcttxprog, "taxsolve_PA_40_2006" ); OtkMakePanel( main_panel, Otk_Recessed, Otk_LightGray, x+1.0, y+0.7, 3.0, 2.0 ); OtkMakeTextLabel( main_panel, "PA STATE 40", Otk_Gray, /*scale=*/ fontsz, /*weight=*/ 1, /*x=*/ x+7.0, y+0.6 ); y = y + dy; // OtkMakeRadioButton( txprogstog, x, y, 6.0, 3.0, slcttxprog, "taxsolve_VA_760_2006" ); OtkMakePanel( main_panel, Otk_Recessed, Otk_LightGray, x+1.0, y+0.7, 3.0, 2.0 ); OtkMakeTextLabel( main_panel, "VA State 760", Otk_Gray, /*scale=*/ fontsz, /*weight=*/ 1, /*x=*/ x+7.0, y+0.6 ); y = y + dy; OtkMakeRadioButton( txprogstog, x, y, 6.0, 3.0, slcttxprog, "Other" ); OtkMakeTextLabel( main_panel, "Other", Otk_Gray, /*scale=*/ fontsz, /*weight=*/ 1, /*x=*/ x+7.0, y+0.6 ); Otk_Add_BoundingBox( main_panel, Otk_Blue, 1.0, 6.0, 32.0, 95.0, 67.0 ); } OtkMakeButton( OtkOuterWindow, 6, 95.3, 15, 4, "Save ", save_taxfile, 0 ); /* Save Button. */ OtkMakeButton( OtkOuterWindow, 27, 95.3, 21, 4, "Compute Tax ", taxsolve, 0 ); /* TaxSolve Button. */ OtkMakeButton( OtkOuterWindow, 55, 95.3, 15, 4, "Print", printout, 0 ); /* Print Button. */ OtkMakeButton( OtkOuterWindow, 82, 95.3, 15, 4, "Exit", QuitCallback, 0 ); /* Exit Button. */ if (infile==0) { OtkMakeButton( main_panel, 10, 75, 80, 10, "Open a Tax File (or Template)", open_taxfile, 0 ); OtkMakeTextLabel( main_panel, vrsnmssg, Otk_Black, /*scale=*/ 1, /*weight=*/ 1, /*x=*/ 42, /*y=*/ 95 ); } else Read_Tax_File(working_file); OtkMainLoop(); return 0; }