From 98a21ce9edcd22bf7a9dde62f317f143e289ecf5 Mon Sep 17 00:00:00 2001 From: dam Date: Tue, 4 Apr 2023 17:45:05 +0100 Subject: WIP Making ncurses work a bit. --- ttt.jai | 213 ++++++++++++++++++++++++++++++++-------------------------------- 1 file changed, 106 insertions(+), 107 deletions(-) (limited to 'ttt.jai') diff --git a/ttt.jai b/ttt.jai index 96a5fdb..b5fb59d 100644 --- a/ttt.jai +++ b/ttt.jai @@ -74,20 +74,23 @@ Database :: struct { database : Database; archive : Database; is_autosave_enabled := true; -// int countdown_to_autosave = -1; +countdown_to_autosave := -1; app_directory : string; db_file_path : string; ar_file_path : string; // char *string_buffer = NULL; // A temporary buffer for localized actions. Please avoid data leaks and out-of-bounds errors. // size_t string_buffer_size = 0; -// int size_x, size_y, pos_x, pos_y; +size_x : s32; +size_y : s32; +pos_x : s32; +pos_y : s32; Styles :: enum s16 { STYLE_SELECTED :: 1; - STYLE_SELECTED_INVERTED; + SELECTED_INVERTED; STYLE_ACTIVE; STYLE_ACTIVE_SELECTED; - STYLE_ERROR; + ERROR; } Layouts :: enum u8 { @@ -109,7 +112,7 @@ print_error :: (format :string, args : .. Any) { // int w_size_y = 4; // if (error_window == NULL) { // error_window = newwin(w_size_y, w_size_x, (size_y - w_size_y) / 2, (size_x - w_size_x) / 2); -// wattron(error_window, COLOR_PAIR(STYLE_ERROR)); +// wattron(error_window, COLOR_PAIR(ERROR)); // wborder(error_window, ' ', ' ', 0, 0, ACS_HLINE, ACS_HLINE, ACS_HLINE, ACS_HLINE); // mvwprintw(error_window, 0, 1, " Error "); // wmove(error_window, 1, 0); @@ -152,18 +155,15 @@ draw_error_window :: () { */ } -/* -void trigger_autosave() { +trigger_autosave :: () { countdown_to_autosave = 13375; // ms } -void show_processing() { +show_processing :: () { mvaddch(0, 0, ACS_DIAMOND); refresh(); } -*/ - // Returns true if string to_compare is equal to any of the other passed strings, false otherwise. is_equal_to_any :: (to_compare :string, test_a :string, test_b :string) -> bool { return to_compare == test_a || to_compare == test_b; @@ -299,29 +299,24 @@ sub_int64 :: (x :s64, y :s64) -> s64 { x - y; } -/* // Returns active task or NULL if none applies. -task_st *get_active_task(database_st *db) { - assert(db != NULL); - - task_st *task = NULL; - if (db->active_task >= 0) { - task = db->tasks + db->active_task; +get_active_task :: inline (db: Database) -> *Task { + task: *Task = null; + if (db.active_idx >= 0) { + task = *db.tasks[db.active_idx]; } return task; } // Returns selected task or NULL if none applies. -task_st *get_selected_task(database_st *db) { - assert(db != NULL); - - task_st *task = NULL; - if (db->selected_task >= 0) { - task = db->tasks + db->selected_task; +get_selected_task :: inline (db: Database) -> *Task { + task: *Task = null; + if (db.selected_idx >= 0) { + task = *db.tasks[db.selected_idx]; } return task; } -*/ + // Adds a task to the database. // If necessary, expands database capacity. // Returns success. @@ -528,11 +523,12 @@ void move_task_to_index(database_st *db, task_st *task, ptrdiff_t index) { } db->selected_task = target_index; } - +*/ // Updates the times on the active task (and adjusts database totals). -void update_times(database_st *db) { - assert(db != NULL); - +update_times :: (db: *Database) { + assert(db != null); + return; + /* // Get current UTC time. time_t stop_time = time(NULL); @@ -566,8 +562,9 @@ void update_times(database_st *db) { start_time = next_start; } + */ } - +/* // Recalculates database totals. void update_total_times(database_st *db) { assert(db != NULL); @@ -642,8 +639,7 @@ reset_database :: (db: *Database) { // Stores data from database into binary file. // Returns success. -store_database :: (db: *Database, path: string) -> success: bool { - assert(db != null, "Parameter 'db' is null."); +store_database :: (db: Database, path: string) -> success: bool { assert(xx path, "Parameter 'path' is empty."); // Open file. @@ -655,7 +651,7 @@ store_database :: (db: *Database, path: string) -> success: bool { defer file_close(*file); file_write(*file, DB_FILE_SIGN_STR); - file_write(*file, db, size_of(Database)); + file_write(*file, *db, size_of(Database)); file_write(*file, db.tasks.data, size_of(Task) * db.tasks.count); return true; @@ -710,8 +706,7 @@ load_database :: (db: *Database, path: string) -> success: bool { // Exports data into CSV file. // Returns success. -export_to_csv :: (db: *Database, path: string) -> success: bool { - assert(db != null, "Parameter 'db' is null."); +export_to_csv :: (db: Database, path: string) -> success: bool { assert(xx path, "Parameter 'path' is empty."); // TODO Make sure (IN ALL PROCEDURES) we're not receiving an empty path. @@ -1013,7 +1008,7 @@ initialize_tui :: () { // TODO //setlocale(LC_ALL, "C.UTF-8"); // Sets locale for C library functions; Allows usage of UTF-8. - stdscr = initscr(); // Start curses mode. + stdscr = initscr(); // Start curses mode. cbreak(); // Line buffering disabled; pass on everty thing to me. keypad(stdscr, true); // I need those nifty F1..F12. curs_set(0); // Set cursor invisible. @@ -1023,29 +1018,28 @@ initialize_tui :: () { start_color(); use_default_colors(); // Using default (-1) instead of COLOR_BLACK. init_pair(xx Styles.STYLE_SELECTED, COLOR_BLACK, COLOR_CYAN); - init_pair(xx Styles.STYLE_SELECTED_INVERTED, COLOR_CYAN, -1); + init_pair(xx Styles.SELECTED_INVERTED, COLOR_CYAN, -1); init_pair(xx Styles.STYLE_ACTIVE, COLOR_BLUE, -1); init_pair(xx Styles.STYLE_ACTIVE_SELECTED, COLOR_WHITE, COLOR_BLUE); - init_pair(xx Styles.STYLE_ERROR, COLOR_RED, -1); + init_pair(xx Styles.ERROR, COLOR_RED, -1); } -/* -void update_layout() { +update_layout :: () { // Calculate number of available rows to display tasks. layout_tasks_rows = (size_y - NUM_HEADER_ROWS - NUM_FOOTER_ROWS); // Calculate first column width: expands to fill the remaining space dynamically. - for (layout_st *layout = layouts; layout <= &layouts[NUM_LAYOUTS - 1]; layout++) { - layout->columns[0].width = size_x - (NUM_COLUMNS - 1) - 2; - for (int idx = 1; idx < NUM_COLUMNS; idx++) { - layout->columns[0].width -= layout->columns[idx].width; + for * layout: layouts { + layout.columns[0].width = size_x - (NUM_COLUMNS - 1) - 2; + for 1..layout.columns.count-1 { + layout.columns[0].width -= layout.columns[it].width; } } } -void draw_tui(database_st *db, layout_st *layout) { - - const static int adjust_first_day_of_week[] = { +draw_tui :: (db: *Database, layout: *Layout) { + + adjust_first_day_of_week := int.[ (0 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS, (1 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS, (2 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS, @@ -1053,36 +1047,37 @@ void draw_tui(database_st *db, layout_st *layout) { (4 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS, (5 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS, (6 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS, - }; - - int x, y; - column_st *col; + ]; + x: int; + y: int; + col: *Column; + // Get context information. - task_st *active_task = get_active_task(db); - task_st *selected_task = get_selected_task(db); - time_t now_utc = time(NULL); - int now_week_day = localtime(&now_utc)->tm_wday; + active_task := get_active_task(db); + selected_task := get_selected_task(db); + now_utc := current_time_consensus(); + now_week_day := to_calendar(now_utc).day_of_week_starting_at_0; // Reset theme and clear screen. attrset(A_NORMAL); erase(); - + // Draw outer border. box(stdscr, 0, 0); - + // Draw table grids. y = 0; x = 0; - for (int idx = 0; idx < NUM_COLUMNS - 1; idx++) { - x += 1 + layout->columns[idx].width; - mvaddch(y, x, ACS_TTEE); - for (y = 1; y < size_y - 1; y++) { - mvaddch(y, x, ACS_VLINE); + for layout.columns { + x += 1 + it.width; + mvaddch(xx y, xx x, ACS_TTEE); + for row: 1..size_y-1 { + mvaddch(xx row, xx x, ACS_VLINE); } - mvaddch(size_y - 1, x, ACS_BTEE); + mvaddch(size_y-1, xx x, ACS_BTEE); } - +return; /* /////////////////////////////////////////////////////////////////////////// // Draw headers. @@ -1105,7 +1100,7 @@ void draw_tui(database_st *db, layout_st *layout) { attron(COLOR_PAIR(STYLE_ACTIVE) | A_BOLD); } else if (idx == now_week_day) { - attron(COLOR_PAIR(STYLE_SELECTED_INVERTED) | A_BOLD); + attron(COLOR_PAIR(SELECTED_INVERTED) | A_BOLD); } col = &layout->columns[L_DAYS_IDX + idx]; @@ -1203,7 +1198,7 @@ void draw_tui(database_st *db, layout_st *layout) { attron(COLOR_PAIR(STYLE_ACTIVE) | A_BOLD); } else if (idx == now_week_day) { - attron(COLOR_PAIR(STYLE_SELECTED_INVERTED) | A_BOLD); + attron(COLOR_PAIR(SELECTED_INVERTED) | A_BOLD); } column_width = layout->columns[L_DAYS_IDX + idx].width; @@ -1216,8 +1211,9 @@ void draw_tui(database_st *db, layout_st *layout) { } x++; mvprintw_time(y, x, total_time, layout->columns[L_TOTAL_IDX].width); + */ } - +/* void *mem_alloc(size_t mem_size, const char *error_tag) { void *mem_pointer = malloc(mem_size); if (mem_pointer == NULL && mem_size > 0) { @@ -1335,14 +1331,14 @@ main :: () { { // Initialize database and archive files if needed. if (file_exists(db_file_path) == false) { - if (store_database(*database, db_file_path) == false) { + if (store_database(database, db_file_path) == false) { print_error("Failed to initialize database."); exit(1); } } if (file_exists(ar_file_path) == false) { - if (export_to_csv(*archive, ar_file_path) == false) { + if (export_to_csv(archive, ar_file_path) == false) { print_error("Failed to initialize archive."); exit(1); } @@ -1474,67 +1470,69 @@ main :: () { } initialize_tui(); - /* + // TODO Remove this?! //signal(SIGTERM, exit_gracefully); //signal(SIGINT, exit_gracefully); //signal(SIGQUIT, exit_gracefully); //signal(SIGHUP, exit_gracefully); + layout := *layouts[Layouts.COMPACT]; + db := *database; + flushinp(); ungetch(KEY_RESIZE); - for (int key; ((key = getch()) != 'q') && (key != 'Q'); ) { + while (true) { + key := getch(); + if key == #char "q" || key == #char "Q" break; - static layout_st *layout = &layouts[L_COMPACT]; - task_st *active_task = get_active_task(db); - task_st *selected_task = get_selected_task(db); - int action_style = A_BOLD | COLOR_PAIR(selected_task == active_task && selected_task != NULL ? STYLE_ACTIVE : STYLE_SELECTED_INVERTED); - int error_style = A_BOLD | COLOR_PAIR(STYLE_ERROR); - int selected_task_row = is_terminal_too_small ? 0 - : (db->selected_task < 0) ? 1 - : (db->selected_task % layout_tasks_rows) + NUM_HEADER_ROWS; + active_task := get_active_task(db); + selected_task := get_selected_task(db); + action_style := A_BOLD | COLOR_PAIR(xx ifx selected_task == active_task && selected_task != null + then Styles.STYLE_ACTIVE + else Styles.SELECTED_INVERTED); + error_style := A_BOLD | COLOR_PAIR(xx Styles.ERROR); + selected_task_row : int = ifx is_terminal_too_small then 0 + else ifx (db.selected_idx < 0) then 1 + else (db.selected_idx % layout_tasks_rows) + NUM_HEADER_ROWS; timeout(INPUT_AWAIT_INF); - update_times(&database); + update_times(*database); - switch(key) { + if key == { // When getch() times out. - case ERR: { + case ERR; if (is_autosave_enabled && countdown_to_autosave > 0) { countdown_to_autosave -= INPUT_TIMEOUT_MS; if (countdown_to_autosave <= 0) { show_processing(); - if (db == &archive) { - export_to_csv(&archive, ar_file_path); + if (db == *archive) { + export_to_csv(*archive, ar_file_path); } - store_database(&database, db_file_path); + store_database(database, db_file_path); } } - break; - } // When terminal is resized. - case KEY_RESIZE: { + case KEY_RESIZE; // BUG KEY_RESIZE is not happening. clear(); - getmaxyx(stdscr, size_y, size_x); + getmaxyx(stdscr, *size_y, *size_x); is_terminal_too_small = size_x < 60 || size_y < 3; - size_t new_size = 2047 | TASK_NAME_BYTES | (size_x + 1); - if (string_buffer_size < new_size) { - string_buffer_size = new_size; - string_buffer = realloc(string_buffer, string_buffer_size); - if (string_buffer == NULL && string_buffer_size > 0) { - print_error("Failed to allocate memory for string buffer: %s.", strerror(errno)); - flushinp(); - ungetch('q'); - break; - } - } + new_size := 2047 | TASK_NAME_BYTES | (size_x + 1); + //if (string_buffer_size < new_size) { + //string_buffer_size = new_size; + //string_buffer = realloc(string_buffer, string_buffer_size); + //if (string_buffer == NULL && string_buffer_size > 0) { + //print_error("Failed to allocate memory for string buffer: %s.", strerror(errno)); + //flushinp(); + //ungetch(#char "q"); + //break; + //} + //} update_layout(); - layout = &layouts[size_x > 100 ? L_NORMAL : L_COMPACT]; - break; - } - + layout = *layouts[ifx size_x > 100 then Layouts.NORMAL else Layouts.COMPACT]; +/* case 'n': case 'N':{ if (is_database_full(db)) { @@ -1849,12 +1847,12 @@ main :: () { select_task_by_delta(db, layout_tasks_rows); break; } +*/ } if (is_terminal_too_small) { - const char *INVALID_WINDOW_MESSAGE = "Terminal is too small: minimum 60x3."; - const int INVALID_WINDOW_MESSAGE_LENGTH = strlen(INVALID_WINDOW_MESSAGE); - mvaddstr(size_y / 2, (size_x - INVALID_WINDOW_MESSAGE_LENGTH) / 2, INVALID_WINDOW_MESSAGE); + INVALID_WINDOW_MESSAGE :: "Terminal is too small: minimum 60x3."; + mvaddstr(size_y / 2, (size_x - xx INVALID_WINDOW_MESSAGE.count) / 2, INVALID_WINDOW_MESSAGE); } else { draw_tui(db, layout); @@ -1862,8 +1860,9 @@ main :: () { } timeout(INPUT_TIMEOUT_MS); + } - */ + // Save any unsaved changes. // show_processing(); error_saving := false; -- cgit v1.2.3