diff options
| -rw-r--r-- | main.c | 160 |
1 files changed, 72 insertions, 88 deletions
@@ -970,10 +970,10 @@ void draw_tui(database_st *db, layout_st *layout) { uint64_t total_time = 0; int column_width; - // TODO This is some sort of pagination to allow scrolling through the tasks. - // TODO Review this code. y = 0; + // Pagination based on currently selected task (show page where selected task is). size_t idx_start = (db->selected_task / layout_tasks_rows) * layout_tasks_rows; + // Display up to rows allowed by the layout, or less if reached end of database. size_t idx_stop = idx_start + (layout_tasks_rows > db->count - idx_start ? db->count - idx_start : layout_tasks_rows); for (size_t idx = idx_start; idx < idx_stop; idx++) { task_st *task = &db->tasks[idx]; @@ -1120,12 +1120,12 @@ void exit_gracefully(int signal) { ungetch('q'); } -void read_input_to_string_buffer_with_space(int row, int column, int length, int space) { +void read_input_to_string_buffer_with_space(int row, int column, int style, int length, int space) { assert(length < string_buffer_size); assert(space < string_buffer_size); snprintf(string_buffer, string_buffer_size, "%*s", space, ""); - attron(A_UNDERLINE); + attron(style | A_UNDERLINE); mvaddstr(row, column, string_buffer); echo(); curs_set(1); @@ -1133,11 +1133,50 @@ void read_input_to_string_buffer_with_space(int row, int column, int length, int truncate_string_utf8(string_buffer, length); noecho(); curs_set(0); - attroff(A_UNDERLINE); + attrset(A_NORMAL); +} + +void read_input_to_string_buffer(int row, int column, int style, int length) { + read_input_to_string_buffer_with_space(row, column, style, length, length); +} + +// Returns success. +bool read_input_to_int(int row, int style, const char *message, intmax_t *result) { + assert(message != NULL); + assert(result != NULL); + + attron(style); + move(row, 1); + addch(ACS_CKBOARD); + addstr(message); + attrset(A_NORMAL); + + // Get line number. + int input_pos_x = getcurx(stdscr); + int input_width = size_x - input_pos_x - 1; + read_input_to_string_buffer(row, input_pos_x, style, input_width); + + char *parser; + *result = strtoimax(string_buffer, &parser, 10); + + // TODO Add comment about this comparison... is checking what? - ALSO ADD THIS BELOW + // If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, strtol() stores the original value of nptr in *endptr (and returns 0). In particular, if *nptr is not '\0' but **endptr is '\0' on return, the entire string is valid. + return parser != string_buffer; } -void read_input_to_string_buffer(int row, int column, int length) { - read_input_to_string_buffer_with_space(row, column, length, length); +// Retuns true if user presses enter, false otherwise. +bool read_enter_confirmation(int row, int style, const char *message) { + assert(message != NULL); + + attron(style); + move(row, 1); + for (int idx = 0; idx < size_x - 2; idx++) { + addch(ACS_CKBOARD); + } + mvaddstr(row, 2, message); + attrset(A_NORMAL); + + return getch() == '\n'; } int main(int argc, char *argv[]) { @@ -1297,7 +1336,7 @@ int main(int argc, char *argv[]) { task_st *active_task = get_active_task(db); task_st *selected_task = get_selected_task(db); int selected_task_row = is_terminal_too_small ? 0 : (db->selected_task % layout_tasks_rows) + NUM_HEADER_ROWS; - int selected_task_theme = selected_task == active_task ? STYLE_ACTIVE : STYLE_SELECTED_INVERTED; + int action_style = A_BOLD | COLOR_PAIR(selected_task == active_task ? STYLE_ACTIVE : STYLE_SELECTED_INVERTED); timeout(INPUT_AWAIT_INF); update_times(&database); @@ -1370,9 +1409,7 @@ int main(int argc, char *argv[]) { break; } - attron(COLOR_PAIR(selected_task_theme) | A_BOLD); - read_input_to_string_buffer_with_space(selected_task_row, 1, TASK_NAME_LENGTH, size_x - 2); - attrset(A_NORMAL); + read_input_to_string_buffer_with_space(selected_task_row, 1, action_style, TASK_NAME_LENGTH, size_x - 2); if (is_empty_string(string_buffer) == false) { replace_char(string_buffer, '\t', ' '); @@ -1392,18 +1429,20 @@ int main(int argc, char *argv[]) { break; } - attron(COLOR_PAIR(selected_task_theme) | A_BOLD); - - move(selected_task_row, 1); - for (int idx = 0; idx < size_x - 2; idx++) { - addch(ACS_CKBOARD); + if (read_enter_confirmation(selected_task_row, action_style, " Press enter to reset task. ") == true) { + reset_task_times(db, selected_task); + trigger_autosave(); + } + break; + } + + case KEY_DC: { // Delete + if (selected_task == NULL || selected_task == active_task) { + break; } - mvaddstr(selected_task_row, 2, " Press enter to reset task. "); - - attrset(A_NORMAL); - if (getch() == '\n') { - reset_task_times(db, selected_task); + if (read_enter_confirmation(selected_task_row, action_style, " Press enter to delete task. ") == true) { + delete_task(db, selected_task); trigger_autosave(); } break; @@ -1430,20 +1469,19 @@ int main(int argc, char *argv[]) { input_pos_x++; // Get time delta. - attron(COLOR_PAIR(selected_task_theme) | A_BOLD); - read_input_to_string_buffer(selected_task_row, input_pos_x, input_width); - attrset(A_NORMAL); + read_input_to_string_buffer(selected_task_row, input_pos_x, action_style, input_width); - // TODO Check if parsed OK. For that, I need to read the manual to know what strtoX returns. - // TODO It seems that the float parsing may return INF or NAN. Take special care with those. - // TODO Once I know the parse was OK, I'll check the remaining of the string for multipliers: + // TODO Review code + /* Check if parsed OK. For that, I need to read the manual to know what strtoX returns. + // It seems that the float parsing may return INF or NAN. Take special care with those. + // Once I know the parse was OK, I'll check the remaining of the string for multipliers: // s/S - second (default if none is found) // m/M - minute // h/H - hour // d/D - day // y/Y - year + */ - // TODO Review code char *input = string_buffer; if (is_empty_string(input) == true) { @@ -1510,59 +1548,20 @@ int main(int argc, char *argv[]) { break; } - case KEY_DC: { // Delete - if (selected_task == NULL || selected_task == active_task) { - break; - } - - attron(COLOR_PAIR(selected_task_theme) | A_BOLD); - - move(selected_task_row, 1); - for (int idx = 0; idx < size_x - 2; idx++) { - addch(ACS_CKBOARD); - } - mvaddstr(selected_task_row, 2, " Press enter to delete task. "); - - attrset(A_NORMAL); - - if (getch() == '\n') { - delete_task(db, selected_task); - trigger_autosave(); - } - break; - } - case 'm': case 'M': { if (selected_task == NULL) { break; } - attron(COLOR_PAIR(selected_task_theme) | A_BOLD); - move(selected_task_row, 1); - addch(ACS_CKBOARD); - addstr(" Move to: "); - - // Get line number. - int input_pos_x = getcurx(stdscr); - int input_width = size_x - input_pos_x - 1; - read_input_to_string_buffer(selected_task_row, input_pos_x, input_width); - attrset(A_NORMAL); - - char *parser; // TODO Rename var. - intmax_t input = strtoimax(string_buffer, &parser, 10); - - // TODO Add comment about this comparison... is checking what? - ALSO ADD THIS BELOW - // If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, strtol() stores the original value of nptr in *endptr (and returns 0). In particular, if *nptr is not '\0' but **endptr is '\0' on return, the entire string is valid. - if (parser == string_buffer) { + intmax_t value; + if (read_input_to_int(selected_task_row, action_style, " Move to: ", &value) == false) { break; } - ptrdiff_t target_index = (input < 1 ? 1 : input > MAX_DATABASE_TASKS ? MAX_DATABASE_TASKS : input) - 1; + ptrdiff_t target_index = (value < 1 ? 1 : value > MAX_DATABASE_TASKS ? MAX_DATABASE_TASKS : value) - 1; move_task_to_index(db, selected_task, target_index); - trigger_autosave(); - break; } @@ -1572,27 +1571,12 @@ int main(int argc, char *argv[]) { break; } - attron(COLOR_PAIR(selected_task_theme) | A_BOLD); - move(selected_task_row, 1); - addch(ACS_CKBOARD); - addstr(" Go to: "); - - // Get line number. - int input_pos_x = getcurx(stdscr); - int input_width = size_x - input_pos_x - 1; - read_input_to_string_buffer(selected_task_row, input_pos_x, input_width); - attrset(A_NORMAL); - - char *parser; - intmax_t input = strtoimax(string_buffer, &parser, 10); - - // TODO Add comment about this comparison... is checking what? - ALSO ADD THIS BELOW - // If endptr is not NULL, strtol() stores the address of the first invalid character in *endptr. If there were no digits at all, strtol() stores the original value of nptr in *endptr (and returns 0). In particular, if *nptr is not '\0' but **endptr is '\0' on return, the entire string is valid. - if (parser == string_buffer) { + intmax_t value; + if (read_input_to_int(selected_task_row, action_style, " Go to: ", &value) == false) { break; } - ptrdiff_t target_index = (input < 1 ? 1 : input > MAX_DATABASE_TASKS ? MAX_DATABASE_TASKS : input) - 1; + ptrdiff_t target_index = (value < 1 ? 1 : value > MAX_DATABASE_TASKS ? MAX_DATABASE_TASKS : value) - 1; select_task_by_index(db, target_index); break; } |
