diff options
| author | gonzo <gonzo@toniatuh.com> | 2023-06-09 21:46:26 +0200 |
|---|---|---|
| committer | gonzo <gonzo@toniatuh.com> | 2023-06-09 21:46:26 +0200 |
| commit | 1fb2975906401893eb46f98d2d1a3837dcb2e8d8 (patch) | |
| tree | 5b79a3274e69fbae924bb90b7fc868e6e4487a62 /main.c | |
| parent | 2c380f8df666fcebd979511f33e7d72291b389cd (diff) | |
| download | loan_calc-1fb2975906401893eb46f98d2d1a3837dcb2e8d8.tar.gz | |
rough ncurses main
Diffstat (limited to 'main.c')
| -rw-r--r-- | main.c | 197 |
1 files changed, 197 insertions, 0 deletions
@@ -0,0 +1,197 @@ +#include <ncurses.h> +#include <form.h> +#include <signal.h> +#include "contract.h" +#include "loans.h" + +static int WIDTH, HEIGHT; +static int padscroll, duration; +static WINDOW *pad; +_Noreturn static void finish(int sig); +void display_custom_form(FORM *); +void print_contract(WINDOW *w, int x, int y, contract *c); +void run_sim(FORM *); + +int main() { + int ch, i; + + /* setup ncurses */ + signal(SIGINT, finish); /* arrange interrupts to terminate */ + initscr(); /* initialize the curses library */ + cbreak(); /* take input chars one at a time don't wait for CR */ + noecho(); /* echo input */ + nonl(); /* do not LF->CR-LF on output */ + intrflush(stdscr, FALSE); /* do not flush on interrupts */ + keypad(stdscr, TRUE); /* enable keyboard mapping */ + getmaxyx(stdscr, HEIGHT, WIDTH); + + /* create the form */ + FIELD *fields[8]; + FORM *form; + char *contract_types[] = { "loan", "savings", NULL }; + char *contract_subtypes[] = { "bullet", "sla", "mort", NULL }; + + /* initialize fields */ + fields[0] = new_field(1, 11, 4, 22, 0, 0); /* contract type */ + set_field_type(fields[0], TYPE_ENUM, contract_types, FALSE, TRUE); + fields[1] = new_field(1, 11, 5, 22, 0, 0); /* contract subtype */ + set_field_type(fields[1], TYPE_ENUM, contract_subtypes, FALSE, TRUE); + fields[2] = new_field(1, 11, 6, 22, 0, 0); /* contract duration */ + set_field_type(fields[2], TYPE_INTEGER, 1, 0, INT_MAX); + fields[3] = new_field(1, 11, 7, 22, 0, 0); /* yearly payments */ + set_field_type(fields[3], TYPE_INTEGER, 1, 0, INT_MAX); + fields[4] = new_field(1, 11, 8, 22, 0, 0); /* delay duration */ + set_field_type(fields[4], TYPE_INTEGER, 1, 0, INT_MAX); + fields[5] = new_field(1, 11, 9, 22, 0, 0); /* starting amount */ + set_field_type(fields[5], TYPE_NUMERIC, 2, 0.0, 0.0); + fields[6] = new_field(1, 11, 10, 22, 0, 0); /* rate */ + set_field_type(fields[6], TYPE_NUMERIC, 3, 0.0, 1.0); + fields[7] = NULL; + + /* configure fields */ + for (i = 0; fields[i]; i++) { + set_field_back(fields[i], A_UNDERLINE); /* Print a line for the option */ + field_opts_off(fields[i], O_AUTOSKIP); /* Don't go to next field when this */ + /* Field is filled up */ + } + + /* create form */ + form = new_form(fields); + display_custom_form(form); + refresh(); + + int formactive = TRUE; + /* mainloop */ + while ((ch = getch()) != KEY_EXIT) { + if (formactive) { + switch (ch) { + case KEY_DOWN: + /* Go to next field */ + form_driver(form, REQ_NEXT_FIELD); + /* Go to the end of the present buffer */ + /* Leaves nicely at the last character */ + form_driver(form, REQ_END_LINE); + break; + case KEY_UP: + form_driver(form, REQ_PREV_FIELD); + form_driver(form, REQ_END_LINE); + break; + case KEY_LEFT: + form_driver(form, REQ_PREV_CHOICE); + break; + case KEY_RIGHT: + form_driver(form, REQ_NEXT_CHOICE); + break; + case KEY_BACKSPACE: + form_driver(form, REQ_DEL_PREV); + break; + case '\r': + unpost_form(form); + formactive = FALSE; + curs_set(0); + refresh(); + box(stdscr, 0, 0); + run_sim(form); + padscroll = 0; + prefresh(pad, padscroll, 0, 4, 1, HEIGHT-2, WIDTH-1); + break; + default: + /* If this is a normal character, it gets */ + /* Printed */ + form_driver(form, ch); + } + } else { + switch (ch) { + case KEY_DOWN: + padscroll += (padscroll < duration) ? 1 : 0; + pnoutrefresh(pad, padscroll, 0, 4, 1, HEIGHT-2, WIDTH-1); + doupdate(); + break; + case KEY_UP: + padscroll -= (padscroll > 0) ? 1 : 0; + pnoutrefresh(pad, padscroll, 0, 4, 1, HEIGHT-2, WIDTH-1); + doupdate(); + break; + case 'q': + display_custom_form(form); + formactive = TRUE; + curs_set(1); + break; + } + } + } + + delwin(pad); + if (formactive) unpost_form(form); + free_form(form); + for (i = 0; fields[i]; i++) + free_field(fields[i]); + + finish(0); +} + +_Noreturn static void finish (int sig) { + endwin(); + + exit(sig); +} + +void display_custom_form(FORM *form) { + post_form(form); + mvprintw(2, 5, "Initialization Parameters"); + mvprintw(4, 2, "Contract type:"); + mvprintw(5, 2, "Contract subtype:"); + mvprintw(6, 2, "Contract Duration:"); + mvprintw(7, 2, "Yearly payments:"); + mvprintw(8, 2, "Delay Duration:"); + mvprintw(9, 2, "Starting Amount:"); + mvprintw(10, 2, "Rate:"); + form_driver(form, REQ_FIRST_FIELD); +} + +void print_contract(WINDOW* w, int x, int y, contract *c) { + mvwprintw(w, x, y, + "%4d/%-4d | %12.2f | %10.2f | %10.2f | %10.2f\n", + c->k, c->n, + (double)c->P, (double)c->I, + (double)c->D, (double)c->A); +} + +void run_sim(FORM *form) { + /* loan_type type; */ + int n, d, yp; + double r, p; + + FIELD **fields = form_fields(form); + n = atoi(field_buffer(fields[2], 0)); + yp = atoi(field_buffer(fields[3], 0)); + d = atoi(field_buffer(fields[4], 0)); + p = atof(field_buffer(fields[5], 0)); + r = atof(field_buffer(fields[6], 0)); + + //adapt wrt yearly payments + if (yp > 1) { + n = n*yp; + d = d*yp; + r = r/(double)yp; + } + + /* setup pad */ + pad = newpad(n+1, WIDTH-2); + mvwprintw(stdscr, 1, 2, "Reinbursement Table"); + mvwprintw(stdscr, 3, 3, + "%4s/%-4s | %12s | %10s | %10s | %10s\n", + "cur", "tot", + "principal", + "interest", + "part", + "annuity"); + + /* run simulation */ + loan l = loan_init(MORTGAGE, n, d, r, p); + for (int i = 0; i <= n; i++) { + print_contract(pad, i, 2, l.c); + loan_update(l); + } + duration = n - HEIGHT + 6; +} |
