diff options
| -rw-r--r-- | main.c | 168 | ||||
| -rw-r--r-- | readme.md | 8 |
2 files changed, 80 insertions, 96 deletions
@@ -629,19 +629,18 @@ int size_x, size_y, pos_x, pos_y; #define NUM_OF_COLUMNS 9 typedef struct { - int timers_offset; - char *table_headers[NUM_OF_COLUMNS]; - int column_widths[NUM_OF_COLUMNS]; - char alignments[NUM_OF_COLUMNS]; - int alignment_offsets[NUM_OF_COLUMNS]; -} layout_t; + char *header; + int width; + char alignment; + int alignment_offset; +} column_st; -layout_t *layouts = NULL; +typedef struct { + column_st columns[NUM_OF_COLUMNS]; + char *archive_title; +} layout_st; -// typedef enum { -// L_NORMAL, -// L_COMPACT, -// } layout_type; +layout_st layouts[2]; #define L_NORMAL 0 #define L_COMPACT 1 @@ -660,61 +659,57 @@ layout_t *layouts = NULL; void initialize_tui() { - layouts = calloc(2, sizeof(layout_t)); - // Normal layout. - layouts[L_NORMAL] = (layout_t) { - .column_widths = { -1, 7, 7, 7, 7, 7, 7, 7, 9 }, - .alignments = { 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C' }, - .table_headers = { - " Task Time Tracker v1 ", - " Sun ", - " Mon ", - " Tue ", - " Wed ", - " Thu ", - " Fri ", - " Sat ", - " Total ", - }, + layouts[L_NORMAL] = (layout_st) { + .archive_title = " Archive ", + .columns = { + { .header = " Task Time Tracker v1 ", .width = -1, .alignment = 'L' }, + { .header = " Sun ", .width = 7, .alignment = 'C' }, + { .header = " Mon ", .width = 7, .alignment = 'C' }, + { .header = " Tue ", .width = 7, .alignment = 'C' }, + { .header = " Wed ", .width = 7, .alignment = 'C' }, + { .header = " Thu ", .width = 7, .alignment = 'C' }, + { .header = " Fri ", .width = 7, .alignment = 'C' }, + { .header = " Sat ", .width = 7, .alignment = 'C' }, + { .header = " Total ", .width = 9, .alignment = 'C' }, + } }; - + // Compact layout. - layouts[L_COMPACT] = (layout_t){ - .column_widths = { -1, 5, 5, 5, 5, 5, 5, 5, 5 }, - .alignments = { 'L', 'C', 'C', 'C', 'C', 'C', 'C', 'C', 'C' }, - .table_headers = { - " TTT v1 ", - " S ", - " M ", - " T ", - " W ", - " T ", - " F ", - " S ", - " # ", - }, + layouts[L_COMPACT] = (layout_st) { + .archive_title = " Archive ", + .columns = { + { .header = " TTT v1 ", .width = -1, .alignment = 'L' }, + { .header = " S ", .width = 5, .alignment = 'C' }, + { .header = " M ", .width = 5, .alignment = 'C' }, + { .header = " T ", .width = 5, .alignment = 'C' }, + { .header = " W ", .width = 5, .alignment = 'C' }, + { .header = " T ", .width = 5, .alignment = 'C' }, + { .header = " F ", .width = 5, .alignment = 'C' }, + { .header = " S ", .width = 5, .alignment = 'C' }, + { .header = " # ", .width = 5, .alignment = 'C' }, + } }; // Calculate alignment_offsets. - for(layout_t *layout = layouts; layout <= layouts + 1; layout++) { - for (int idx = 0; idx < NUM_OF_COLUMNS; idx++) { + for(layout_st *layout = layouts; layout <= layouts + 1; layout++) { + for (column_st *col = layout->columns; col <= layout->columns + NUM_OF_COLUMNS; col++) { int offset; - switch(layout->alignments[idx]) { + switch(col->alignment) { default: case 'L': offset = 0; break; case 'C': - offset = ((layout->column_widths[idx] - strlen(layout->table_headers[idx])) / 2); + offset = ((col->width - strlen(col->header)) / 2); break; case 'R': - offset = (layout->column_widths[idx] - strlen(layout->table_headers[idx])); + offset = (col->width - strlen(col->header)); break; } - layout->alignment_offsets[idx] = offset; + col->alignment_offset = offset; } } @@ -733,7 +728,7 @@ void initialize_tui() { init_pair(THEME_E, COLOR_BLUE, COLOR_BLACK); } -void draw_tui(database_t *db, layout_t *layout) { +void draw_tui(database_t *db, layout_st *layout) { const static int adjust_first_day_of_week[] = { (0 + FIRST_DAY_OF_WEEK) % WEEK_DAYS, @@ -746,6 +741,7 @@ void draw_tui(database_t *db, layout_t *layout) { }; int x, y; + column_st *col; // Get context information. task_t *active_task = get_active_task(db); @@ -754,9 +750,9 @@ void draw_tui(database_t *db, layout_t *layout) { int now_week_day = localtime(&now_utc)->tm_wday; // The first column expands to fill the remaining space dynamically. - layout->column_widths[0] = size_x - (NUM_OF_COLUMNS - 1) - 2; + layout->columns[0].width = size_x - (NUM_OF_COLUMNS - 1) - 2; for (int idx = 1; idx < NUM_OF_COLUMNS; idx++) { - layout->column_widths[0] -= layout->column_widths[idx]; + layout->columns[0].width -= layout->columns[idx].width; } // Reset theme and clear screen. @@ -770,7 +766,7 @@ void draw_tui(database_t *db, layout_t *layout) { y = 0; x = 0; for (int idx = 0; idx < NUM_OF_COLUMNS - 1; idx++) { - x += 1 + layout->column_widths[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); @@ -778,13 +774,6 @@ void draw_tui(database_t *db, layout_t *layout) { mvaddch(size_y - 1, x, ACS_BTEE); } - // Draw diamond symbol on top left corner when in archive mode. - if (db == &archive) { - attron(COLOR_PAIR(THEME_D)); // Apply theme - mvaddch(0, 0, ACS_DIAMOND); - attrset(A_NORMAL); // Reset theme. - } - /////////////////////////////////////////////////////////////////////////// // Draw headers. @@ -793,8 +782,9 @@ void draw_tui(database_t *db, layout_t *layout) { // Headers : title x++; - mvaddstr(y, x + layout->alignment_offsets[L_TITLE_IDX], layout->table_headers[L_TITLE_IDX]); - x += layout->column_widths[L_TITLE_IDX]; + col = &layout->columns[L_TITLE_IDX]; + mvaddstr(y, x + col->alignment_offset, (db == &archive ? layout->archive_title : col->header)); + x += col->width; // Headers : days for (int raw_idx = 0; raw_idx < WEEK_DAYS; raw_idx++) { @@ -809,8 +799,9 @@ void draw_tui(database_t *db, layout_t *layout) { attron(COLOR_PAIR(THEME_D) | A_BOLD); } - mvaddstr(y, x + layout->alignment_offsets[idx + L_DAYS_IDX], layout->table_headers[idx + L_DAYS_IDX]); - x += layout->column_widths[idx + L_DAYS_IDX]; + col = &layout->columns[L_DAYS_IDX + idx]; + mvaddstr(y, x + col->alignment_offset, col->header); + x += col->width; // Reset theme. attrset(A_NORMAL); @@ -818,8 +809,8 @@ void draw_tui(database_t *db, layout_t *layout) { // Headers : total x++; - mvaddstr(y, x + layout->alignment_offsets[L_TOTAL_IDX], layout->table_headers[L_TOTAL_IDX]); - x += layout->column_widths[L_TOTAL_IDX]; // Not needed. + col = &layout->columns[L_TOTAL_IDX]; + mvaddstr(y, x + col->alignment_offset, col->header); /////////////////////////////////////////////////////////////////////////// @@ -853,7 +844,7 @@ void draw_tui(database_t *db, layout_t *layout) { // Task title. x++; - column_width = layout->column_widths[L_TITLE_IDX]; + column_width = layout->columns[L_TITLE_IDX].width; sprintf(string_buffer, "%*s", column_width, ""); mvaddnstr(y, x, string_buffer, column_width); mvaddnstr(y, x, task->name, column_width); @@ -866,7 +857,7 @@ void draw_tui(database_t *db, layout_t *layout) { int day_idx = (idx + FIRST_DAY_OF_WEEK) % WEEK_DAYS; - int column_width = layout->column_widths[L_DAYS_IDX + day_idx]; + column_width = layout->columns[L_DAYS_IDX + day_idx].width; int64_t task_time = task->times[day_idx]; total_time = add_time(total_time, task_time); format_time(string_buffer, task_time, column_width); @@ -876,8 +867,7 @@ void draw_tui(database_t *db, layout_t *layout) { // Task total. x++; - column_width = layout->column_widths[L_TOTAL_IDX]; // TODO - format_time(string_buffer, total_time, column_width); + format_time(string_buffer, total_time, layout->columns[L_TOTAL_IDX].width); mvaddstr(y, x, string_buffer); // Reset theme. @@ -888,7 +878,7 @@ void draw_tui(database_t *db, layout_t *layout) { /////////////////////////////////////////////////////////////////////////// // Draw selected/total tasks. sprintf(string_buffer, " %td/%zd ", db->selected_task+1, db->count); - if (strlen(string_buffer) > layout->column_widths[L_TITLE_IDX]) { + if (strlen(string_buffer) > layout->columns[L_TITLE_IDX].width) { sprintf(string_buffer, "%td", db->selected_task+1); } mvaddstr(size_y-1, 1, string_buffer); @@ -896,23 +886,21 @@ void draw_tui(database_t *db, layout_t *layout) { /////////////////////////////////////////////////////////////////////////// // Draw daily totals. y = size_y-1; - x = 0 + 1 + layout->column_widths[L_TITLE_IDX]; + x = 0 + 1 + layout->columns[L_TITLE_IDX].width; total_time = 0; for (int idx = 0; idx < WEEK_DAYS; idx++) { x++; int day_idx = (idx + FIRST_DAY_OF_WEEK) % WEEK_DAYS; int64_t daily_total = db->total_times[day_idx]; - column_width = layout->column_widths[day_idx + L_DAYS_IDX]; + column_width = layout->columns[day_idx + L_DAYS_IDX].width; total_time = add_time(total_time, daily_total); format_time(string_buffer, daily_total, column_width); mvaddstr(y, x, string_buffer); x += column_width; } x++; - column_width = layout->column_widths[L_TOTAL_IDX]; - format_time(string_buffer, total_time, column_width); + format_time(string_buffer, total_time, layout->columns[L_TOTAL_IDX].width); mvaddstr(y, x, string_buffer); - x += column_width; } @@ -922,9 +910,6 @@ void free_memory() { free(string_buffer); string_buffer = NULL; - - free(layouts); - layouts = NULL; } #define INPUT_TIMEOUT_MS 1000 @@ -1011,18 +996,17 @@ int main(int argc, char *argv[]) { store_database(&database, DB_BIN_PATH_NAME); } - // TODO - // When this is active, it cancels selecting text with the mouse, and breaks the creation of a new task. - // Fortunatelly, this only happens when we write on the line being selected. If we only update the places that changes, this problem goes away. - - int ch = KEY_RESIZE; - do { + int ch; + ungetch(KEY_RESIZE); + while((ch = getch()) != 'q') { + + timeout(INPUT_AWAIT_INF); task_t *active_task = get_active_task(db); task_t *selected_task = get_selected_task(db); update_timers(&database); - switch(ch) - { + switch(ch) { + // When getch() times out. case ERR: break; @@ -1031,12 +1015,12 @@ int main(int argc, char *argv[]) { case KEY_RESIZE: clear(); getmaxyx(stdscr, size_y, size_x); - string_buffer = realloc(string_buffer, 511 | MAX_TASK_NAME | size_x); + string_buffer = realloc(string_buffer, 511 | MAX_TASK_NAME | size_x); // TODO This realloc sucks. break; case KEY_F(1): { - timeout(INPUT_AWAIT_INF); + task_t *new_task; if (create_task(db, &new_task) == false) { // ERROR @@ -1069,7 +1053,6 @@ int main(int argc, char *argv[]) { case KEY_F(2): { - timeout(INPUT_AWAIT_INF); if (selected_task == NULL) { break; } @@ -1188,15 +1171,16 @@ int main(int argc, char *argv[]) { break; } - if (size_x >= 60 && size_y > 2) { + if (size_x >= 60 && size_y >= 3) { draw_tui(db, &layouts[size_x > 100 ? L_NORMAL : L_COMPACT]); } else { const char *INVALID_WINDOW_MESSAGE = "Please expand window."; mvaddstr(size_y / 2, (size_x - strlen(INVALID_WINDOW_MESSAGE)) / 2, INVALID_WINDOW_MESSAGE); } - timeout(INPUT_TIMEOUT_MS); // Make getch() timeout. - } while((ch = getch()) != 'q'); + + timeout(INPUT_TIMEOUT_MS); + } update_timers(&database); store_database(&database, DB_BIN_PATH_NAME); @@ -29,11 +29,11 @@ Task Time Tracker - [x] Review code: char !uint8_t; - [x] Make sure that only one task is running at each time; - [x] Mouse selection is broken due to entire TUI update: No, it was fixed by using `erase()` on the `draw_tui` instead of `clear()`; -- [ ] I bet the headers are no longer being used all on a single cycle. Let's separate them and include "header_title_archive"; -- [ ] rename layout members: title_header, archive_header, total_header, days_headers, column_widths, column_alignments, headers_paddings. -- [ ] using the archive header, we can remove the top-left-corner diamond on the archive. +- [x] I bet the headers are no longer being used all on a single cycle. Let's separate them and include "header_title_archive"; +- [x] rename layout members: title_header, archive_header, total_header, days_headers, column_widths, column_alignments, headers_paddings. +- [x] using the archive header, we can remove the top-left-corner diamond on the archive. +- [x] Allow to cancel a rename_task operation: you can do it by leaving it blank. - [ ] MAYBE... IS THIS REALLY NEEDED? add helper func: get_selected_screen_row(db*, out int selected_row); It seems to be used in KEY_F(1) and KEY_F(2) cases of input management. -- [ ] Allow to cancel a rename_task operation. - [ ] Improve total_times: - Create function to recalculate them. Shouldn't take so long, right? - Decide when this will run. |
