diff options
Diffstat (limited to 'ttt.jai')
| -rw-r--r-- | ttt.jai | 241 |
1 files changed, 125 insertions, 116 deletions
@@ -33,17 +33,6 @@ TUI :: #import "TUI"; stdscr: *void; // TODO DAM A_BOLD: s32 = 0; // TODO DAM COLOR_PAIR :: (a: s32) -> s32 { return 0; } // TODO DAM -KEY_RESIZE :: 410; // TODO DAM -KEY_F2 :: 266; // TODO DAM -KEY_F5 :: 269; // TODO DAM -KEY_HOME :: 262; // TODO DAM -KEY_UP :: 259; // TODO DAM -KEY_DOWN :: 258; // TODO DAM -KEY_NPAGE :: 338; // TODO DAM -KEY_PPAGE :: 339; // TODO DAM -KEY_END :: 360; // TODO DAM -KEY_BACKSPACE :: 263; // TODO DAM -KEY_DC :: 330; // TODO DAM WINDOW :: struct { } // TODO DAM @@ -90,10 +79,10 @@ app_directory : string; db_file_path : string; ar_file_path : string; -size_x : s32; -size_y : s32; -pos_x : s32; -pos_y : s32; +size_x : int; +size_y : int; +pos_x : int; +pos_y : int; Styles :: enum s16 { SELECTED :: 1; @@ -118,8 +107,8 @@ print_error :: (format :string, args : .. Any) { } else { CHAR_SPACE :: #char " "; - w_size_x: s32 = ifx size_x > 120 then 120 else size_x - 2; - w_size_y: s32 = 4; + w_size_x: int = ifx size_x > 120 then 120 else size_x - 2; + w_size_y: int = 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); TODO DAM //wattron(error_window, COLOR_PAIR(xx Styles.ERROR)); TODO DAM @@ -1175,23 +1164,27 @@ free_memory :: () { //reset_temporary_storage(); } -read_input_string_padded :: (row: int, column: int, style: s32, length: int, padding: int) -> string { - str := talloc_string(length); - memset(str.data, 0, str.count); - // attron(style | A_UNDERLINE); TODO DAM - // mvprintw(xx row, xx column, "%*s", padding, ""); TODO DAM - //echo(); TODO DAM - //curs_set(1); TODO DAM - //mvgetnstr(xx row, xx column, str.data, xx length); TODO DAM - truncate_string(str, length); - //noecho(); TODO DAM - //curs_set(0); TODO DAM - //attrset(A_NORMAL); TODO DAM - return str; -} +read_input_string :: (row: int, column: int, style: s32, input_limit: int, padding: int = 0) -> value: string, success: bool { + + // TODO We still need to apply the style. + + // TODO Draw padding (at end of inputbox)... padding was renamed to input_width... is this the best name? + // TODO Maybe add another optional arg with the placeholder text (to be preset on the input)? + + // TODO WIPWIPWIP + + column += 1; // TODO FIX THE NCURSES INDEXING CHAOS + + TUI.set_cursor_position(row, column + input_limit); + write_string(TUI.Commands.DrawingMode); + for 1..padding { + write_string(TUI.Drawings.Checkerboard); + } + write_string(TUI.Commands.TextMode); + TUI.set_cursor_position(row, column); + value, key := TUI.read_input_line(input_limit); + return value, key == TUI.Keys.Enter; -read_input_string :: (row: int, column: int, style: s32, length: int) -> string { - return read_input_string_padded(row, column, style, length, length); } // Returns success. @@ -1203,41 +1196,67 @@ read_input_int :: (row: int, style: s32, message: string) -> value: int, success //attrset(A_NORMAL); TODO DAM // Get line number. - input_pos_x := 0;//getcurx(stdscr); TODO DAM - input_width := size_x - input_pos_x - 1; + input_pos_x := 1;//getcurx(stdscr); TODO DAM + input_width := size_x - input_pos_x; str := read_input_string(row, input_pos_x, style, input_width); value, success := parse_int(*str); return value, success; } -// Retuns true if user presses enter, false otherwise. -read_input_char :: (row: int, style: int, message: string) -> s32 { - assert(message.data != null, ASSERT_NOT_NULL, "message"); // TODO Improve this check? - - // attron(xx style); TODO DAM - //move(xx row, 1); TODO DAM +// Shows message to user and waits for user key press. +prompt_user :: (row: int, style: int, message: string) -> TUI.Key { +/* + assert(message.data != null, ASSERT_NOT_NULL, "message"); + attron(xx style); + move(xx row, 1); for 0..size_x-3 { - //for (int idx = 0; idx < size_x - 2; idx++) { // TODO check what's going on here. - //addch(ACS_CKBOARD); TODO DAM + // for (int idx = 0; idx < size_x - 2; idx++) { + addch(ACS_CKBOARD); } - //mvaddstr(xx row, 2, message.data); TODO DAM - //attrset(A_NORMAL); TODO DAM + mvaddstr(xx row, 2, message.data); + attrset(A_NORMAL); - //return getch(); TODO DAM - return 0; -} + return getch(); +*/ -// Retuns true if user presses enter, false otherwise. -read_enter_confirmation :: inline (row: int, style: int, message: string) -> bool { - return read_input_char(row, style, message) == #char "\n"; + // TODO We still need to apply the style. + + TUI.set_cursor_position(row, 2); + write_string(TUI.Commands.DrawingMode); + for 0..size_x-2 { + print(TUI.Drawings.Checkerboard); + } + write_string(TUI.Commands.TextMode); + + TUI.set_cursor_position(row, 3); + write_strings(" ", message, " "); + return TUI.get_key(); } main :: () { // -- -- -- Testing TUI -- START - if 1 { + perform_test := false; + + assert_result :: (result: bool, error_message: string) { + if result == true { + print("- success\n", to_standard_error = true); + } + else { + TUI.stop(); + print("- ERROR: %", error_message, to_standard_error = true); + exit(1); + } + } + + next_line :: inline () { + r, c := TUI.get_cursor_position(); + TUI.set_cursor_position(r+1, 1); + } + + if perform_test && 1 { print("TEST : set and get cursor position\n", to_standard_error = true); TUI.start(); ROW :: 3; @@ -1245,21 +1264,19 @@ main :: () { TUI.set_cursor_position(ROW, COLUMN); row, column := TUI.get_cursor_position(); TUI.stop(); - assert(row == ROW && column == COLUMN, "# Failed set/get cursor position.\n"); - print("- success\n", to_standard_error = true); + assert_result(row == ROW && column == COLUMN, "Failed set/get cursor position.\n"); } - if 0 { + if perform_test && 1 { print("TEST : test key input\n", to_standard_error = true); auto_release_temp(); TUI.start(); TUI.clear_terminal(); TUI.set_cursor_position(1, 1); write_string("Press q to exit, other key to print it to screen, wait 1s to see animation."); - TUI.set_cursor_position(2, 1); + next_line(); key: TUI.Key; while(key != #char "q") { - __mark := get_temporary_storage_mark(); key = TUI.get_key(1000); if key == TUI.Keys.None { write_string("-"); @@ -1271,13 +1288,12 @@ main :: () { // else if key >= 32 && key <= 128 then print_character(cast,force(u8)key) write_string(TUI.to_string(key)); } - set_temporary_storage_mark(__mark); } TUI.stop(); print("- success\n", to_standard_error = true); } - if 0 { + if perform_test && 1 { print("TEST : draw box\n", to_standard_error = true); auto_release_temp(); TUI.start(); // TODO Should start() call flush_input internally? @@ -1288,11 +1304,10 @@ main :: () { print("Can you see the box below? (y/n)"); key := TUI.get_key(); TUI.stop(); - assert(key == #char "y", "# Failed to draw box.\n"); - print("- success\n", to_standard_error = true); + assert_result(key == #char "y", "Failed to draw box.\n"); } - if 0 { + if perform_test && 1 { print("TEST : get terminal size\n", to_standard_error = true); auto_release_temp(); TUI.start(); @@ -1305,11 +1320,10 @@ main :: () { key = TUI.get_key(); } TUI.stop(); - assert(key == #char "y", "# Failed to get terminal size.\n"); - print("- success\n", to_standard_error = true); + assert_result(key == #char "y", "Failed to get terminal size.\n"); } - if 0 { + if perform_test && 1 { print("TEST : set terminal title\n", to_standard_error = true); TUI.start(); title := "BAZINGA"; @@ -1321,12 +1335,12 @@ main :: () { key = TUI.get_key(); } TUI.stop(); - assert(key == #char "y", "# Failed to set terminal title.\n"); - print("- success\n", to_standard_error = true); + assert_result(key == #char "y", "Failed to set terminal title.\n"); } - if 0 { + if perform_test && 1 { print("TEST : print keys and set terminal title\n", to_standard_error = true); + auto_release_temp(); TUI.start(); TUI.set_terminal_title("bazinga"); key: TUI.Key = #char "d"; @@ -1338,7 +1352,6 @@ main :: () { drop_down := 0; while(key != #char "q") { - __mark := get_temporary_storage_mark(); if key == { case TUI.Keys.None; { @@ -1383,83 +1396,80 @@ main :: () { TUI.set_cursor_position(x, y); print("size(CxR): %x%\n", size_c, size_r); key = TUI.get_key(1000); - - set_temporary_storage_mark(__mark); + + // __mark := get_temporary_storage_mark(); + // set_temporary_storage_mark(__mark); } + print("- success"); TUI.stop(); } - if 1 { + if perform_test && 1 { print("TEST : user input\n", to_standard_error = true); auto_release_temp(); TUI.start(); TUI.clear_terminal(); TUI.set_cursor_position(1, 1); print("Enter some text (use Enter to finish, Esc to cancel, or resize to abort):"); - r, c := TUI.get_cursor_position(); - TUI.set_cursor_position(r+1, 1); + next_line(); str, key := TUI.read_input_line(15); TUI.set_cursor_position(3, 1); + error_message: string; if key == { case TUI.Keys.Escape; { print("Have you pressed Esc? (y/n)"); - assert(TUI.get_key() == #char "y", "Failed to read line on Esc."); - print("- success\n", to_standard_error = true); + error_message = "Failed to read line on Esc."; } case TUI.Keys.Resize; { print("Have you resized the terminal? (y/n)"); - assert(TUI.get_key() == #char "y", "Failed to read line on resize."); - print("- success\n", to_standard_error = true); + error_message = "Failed to read line on resize."; + } case; { print("Have you entered '%'? (y/n)", str); - assert(TUI.get_key() == #char "y", "Failed to read line."); - print("- success\n", to_standard_error = true); + error_message = "Failed to read line."; } } + answer := TUI.get_key(); TUI.stop(); + assert_result(answer == #char "y", error_message); } - if 1 { + if perform_test && 1 { print("TEST : hidden user input\n", to_standard_error = true); auto_release_temp(); TUI.start(); TUI.clear_terminal(); TUI.set_cursor_position(1, 1); print("Enter some secret (use Enter to finish, Esc to cancel, or resize to abort):"); - r, c := TUI.get_cursor_position(); - TUI.set_cursor_position(r+1, 1); + next_line(); str, key := TUI.read_input_line(15, false); TUI.set_cursor_position(3, 1); + error_message: string; if key == { case TUI.Keys.Escape; { print("Have you pressed Esc? (y/n)"); - assert(TUI.get_key() == #char "y", "Failed to read line on Esc."); - print("- success\n", to_standard_error = true); + error_message = "Failed to read line on Esc."; } case TUI.Keys.Resize; { print("Have you resized the terminal? (y/n)"); - assert(TUI.get_key() == #char "y", "Failed to read line on resize."); - print("- success\n", to_standard_error = true); + error_message = "Failed to read line on resize."; } case; { print("Have you entered '%'? (y/n)", str); - assert(TUI.get_key() == #char "y", "Failed to read line."); - print("- success\n", to_standard_error = true); + error_message = "Failed to read line."; } } + answer := TUI.get_key(); TUI.stop(); + assert_result(answer == #char "y", error_message); } - write_string("DONE\n"); - exit(0); // -- -- -- Testing TUI -- STOP - // TODO Implement signal handling and see modules/Debug.jai for examples. - defer report_memory_leaks(); // TODO Remove after final debug sessions. defer free_memory(); @@ -1674,9 +1684,9 @@ main :: () { ifx selected_idx == active_idx && selected_idx != -1 then Styles.ACTIVE else Styles.SELECTED_INVERTED); error_style = A_BOLD | COLOR_PAIR(xx Styles.ERROR); - selected_task_row = ifx is_terminal_too_small then 0 + selected_task_row = ifx is_terminal_too_small then 0 else ifx (selected_idx < 0) then 1 - else (selected_idx % layout_tasks_rows) + NUM_HEADER_ROWS; + else (selected_idx % layout_tasks_rows) + NUM_HEADER_ROWS + 1; } if key == { @@ -1697,10 +1707,7 @@ main :: () { // When terminal is resized. case TUI.Keys.Resize; TUI.clear_terminal(); - _y, _x := TUI.get_terminal_size(); - // TODO FIX ME - size_y = xx _y; - size_x = xx _x; + size_y, size_x = TUI.get_terminal_size(); is_terminal_too_small = size_x < 60 || size_y < 3; update_layout(); layout = *layouts[ifx size_x > 100 then Layouts.NORMAL else Layouts.COMPACT]; @@ -1723,7 +1730,7 @@ main :: () { case #char "n"; #through; case #char "N"; if is_database_full(db) { - read_enter_confirmation(selected_task_row, error_style, " Unable to create task: database is full. "); + prompt_user(selected_task_row, error_style, "Unable to create task: database is full."); continue; } @@ -1743,29 +1750,31 @@ main :: () { //flushinp(); TODO DAM //ungetch(KEY_F(2)); TODO DAM - case KEY_F2; + case TUI.Keys.F2; if (selected_task == null) continue; - + // Change task name. - input := read_input_string_padded(selected_task_row, 1, action_style, Task.name.count, size_x - 2); + // TODO WIPWIPWIP + input := read_input_string(selected_task_row, 1, action_style, Task.name.count, size_x - 2 - Task.name.count); if is_empty_string(input) == false { - replace_chars(input, "\t\x0B\x0C\r", #char " "); + replace_chars(input, "\t\x0B\x0C\r", #char " "); // Replace weird spaces with space. + memset(selected_task.name.data, 0, Task.name.count); memcpy(selected_task.name.data, input.data, min(Task.name.count, input.count)); trigger_autosave(); } - case KEY_BACKSPACE; + case TUI.Keys.Backspace; if (selected_task == null) continue; - if (read_enter_confirmation(selected_task_row, action_style, " Press enter to reset task. ") == true) { + if (prompt_user(selected_task_row, action_style, "Press enter to reset task.") == TUI.Keys.Enter) { reset_task_times(db, db.selected_idx); trigger_autosave(); } - case KEY_DC; // Delete + case TUI.Keys.Delete; if (selected_task == null || selected_task == active_task) continue; - if (read_enter_confirmation(selected_task_row, action_style, " Press enter to delete task. ") == true) { + if (prompt_user(selected_task_row, action_style, "Press enter to delete task.") == TUI.Keys.Enter) { delete_task(db, db.selected_idx); trigger_autosave(); } @@ -1851,7 +1860,7 @@ main :: () { if selected_task == null continue; if is_database_full(db) { - read_enter_confirmation(selected_task_row, error_style, " Unable to duplicate task: database is full. "); + prompt_user(selected_task_row, error_style, "Unable to duplicate task: database is full."); continue; } @@ -1861,7 +1870,7 @@ main :: () { } trigger_autosave(); - case KEY_F5; + case TUI.Keys.F5; update_total_times(db); trigger_autosave(); @@ -1912,7 +1921,7 @@ main :: () { if (db != *archive || selected_task == null) continue; if is_database_full(*database) { - read_enter_confirmation(selected_task_row, error_style, " Unable to restore task: database is full. "); + prompt_user(selected_task_row, error_style, "Unable to restore task: database is full."); continue; } @@ -1927,7 +1936,7 @@ main :: () { case #char "s"; #through; case #char "S"; // TODO The initial part should only decide what's the sorting procedure... then we would would all in a single place. - sort_by := read_input_char(selected_task_row, action_style, " Sort by (n) name, (1..7) day, or (t) total time. "); + sort_by := prompt_user(selected_task_row, action_style, "Sort by (n) name, (1..7) day, or (t) total time."); show_processing(); sort_procedure: (a: Task, b: Task) -> s64; @@ -1975,7 +1984,7 @@ main :: () { case #char "w"; #through; case #char "W"; if (db != *database || db.tasks.count <= 0) continue; - if (read_enter_confirmation(selected_task_row, action_style, " Press enter to archive duplicates and reset all. ") == false) continue; + if (prompt_user(selected_task_row, action_style, "Press enter to archive duplicates and reset all.") != TUI.Keys.Enter) continue; show_processing(); for db.tasks { @@ -1990,7 +1999,7 @@ main :: () { case #char "c"; #through; case #char "C"; if (db.tasks.count <= 0) continue; - if (read_enter_confirmation(selected_task_row, action_style, " Press enter to coalesce similar tasks. ") == false) continue; + if (prompt_user(selected_task_row, action_style, "Press enter to coalesce similar tasks.") != TUI.Keys.Enter) continue; show_processing(); head_idx := 0; @@ -2009,7 +2018,7 @@ main :: () { } trigger_autosave(); - case KEY_HOME; + case TUI.Keys.Home; select_task(db, 0); case TUI.Keys.Up; @@ -2018,7 +2027,7 @@ main :: () { case TUI.Keys.PgUp; select_task_by_delta(db, -layout_tasks_rows); - case KEY_END; + case TUI.Keys.End; select_task(db, db.tasks.count-1); case TUI.Keys.Down; |
