From 6804d3035ba9ca6f6b28dedf8002e81d3ae4cd43 Mon Sep 17 00:00:00 2001 From: dam Date: Tue, 30 Aug 2022 17:14:49 +0000 Subject: Completed add_task and remove_task functions. All screen is now refreshed, always. Added F1 and F2 to add and remove tasks as prototype. --- main.c | 209 +++++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 152 insertions(+), 57 deletions(-) (limited to 'main.c') diff --git a/main.c b/main.c index 69f26c1..5e3a1e5 100644 --- a/main.c +++ b/main.c @@ -45,13 +45,8 @@ const size_t SIZEOF_DATABASE_T = sizeof(database_t); const char* DAYS_OF_WEEK[] = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" }; const uint8_t DAYS_ON_WEEK = sizeof(DAYS_OF_WEEK)/sizeof(char*); -uint32_t selected_task = -1; -database_t database = { - .tasks = NULL, - .count = 0, - .capacity = 0, -}; - +uint32_t selected_task; +database_t database; // Given an UTF8 encoded string, truncate it to length without breaking any UTF8 character. // The string should have capacity for at least length number of items. @@ -95,8 +90,8 @@ void print_task(const task_t* task) { printf("t[6]: '%" PRIu32 "'\n", task->time[6]); } - -// TODO Maybe inline? +// Adds task to database. If necessary, expands database capacity. +// Returns success. bool add_task(database_t* db, const task_t* task) { assert(db != NULL); assert(task != NULL); @@ -108,18 +103,18 @@ bool add_task(database_t* db, const task_t* task) { // If necessary, expand database capacity. uint32_t current_capacity = db->capacity; - if(db->count + 1 > db->capacity) { + if((db->count + 1) > current_capacity) { uint32_t new_capacity = current_capacity == 0 ? 2 : current_capacity >= UINT32_MAX >> 2 ? UINT32_MAX : current_capacity << 1; - task_t* new_database_tasks = realloc(db->tasks, new_capacity * SIZEOF_TASK_T); - if (new_database_tasks == NULL) { + task_t* new_tasks = realloc(db->tasks, new_capacity * SIZEOF_TASK_T); + if (new_tasks == NULL) { fprintf(stderr, "Failed to expand database, discarding task '%s'.\n", task->name); return false; } db->capacity = new_capacity; - db->tasks = new_database_tasks; + db->tasks = new_tasks; } // Store new task. @@ -129,41 +124,40 @@ bool add_task(database_t* db, const task_t* task) { return true; } -// TODO Maybe inline? +// Removes task by index from database. If possible, shrinks database capacity. +// Returns success. bool remove_task(database_t* db, uint32_t index) { assert(db != NULL); assert(index < db->count); - /* - | ~ ~ 6 - 0 1 2 3 4 5 6 - 3 - 1 = 2 - - | ~ 6 - 0 1 2 3 4 5 6 - 4 - 1 = 1 + if (index >= db->count) { + fprintf(stderr, "Failed to remove out-of-bounds index '%" PRIu32 "'.", index); + return false; + } - | ~ 6 - 0 1 2 3 4 5 6 - 5 - 1 = 0 - */ + // Move tasks after the index position to their new positions. memmove(&db->tasks[index], &db->tasks[index+1], (db->count - index - 1) * SIZEOF_TASK_T); db->count--; - if (db->capacity > 16 && db->count < (db->capacity >> 2)) { - uint32_t new_tasks_capacity = db->capacity << 1; - task_t* new_tasks = realloc(db->tasks, new_tasks_capacity * SIZEOF_TASK_T); + // If possible, shrink database capacity. + uint32_t current_capacity = db->capacity; + if (db->count <= (current_capacity >> 2)) { + uint32_t new_capacity = current_capacity >> 1; + task_t* new_tasks = realloc(db->tasks, new_capacity * SIZEOF_TASK_T); if (new_tasks == NULL) { - fprintf(stderr, "Failed to shrink database memory.\n"); + fprintf(stderr, "Failed to shrink database.\n"); return false; } + db->capacity = new_capacity; db->tasks = new_tasks; } + return true; } void clear_database(database_t* db) { free(db->tasks); - db->tasks = NULL; - db->count = 0; - db->capacity = 0; + memset(db, 0, SIZEOF_TASK_T); } // Stores data from database into binary file. @@ -534,12 +528,12 @@ void initialize_layouts() { } void initialization() { - // Make sure architecture uses 8bits per char. - assert(CHAR_BIT == 8); - // TODO May use the memset or set the properties during instancing. - // Prepare memory. - memset(&database, 0, SIZEOF_DATABASE_T); + selected_task = 0; + + if (load_database(&database, DB_BIN_PATH_NAME) == false) { + memset(&database, 0, SIZEOF_DATABASE_T); + } } void free_memory() { @@ -586,14 +580,19 @@ void draw_header() { void draw_table() { task_t* task; + task_t* active_task; + task_t* selected_taskx; // TODO Improve naming. layout_t* layout = &layouts[selected_layout]; int table_size = layout->table_size; // char** table_headers = layout->table_headers; - // TODO Colors + // TODO Maybe move this to side function? start_color(); - init_pair(1, COLOR_BLACK, COLOR_CYAN); + init_pair(1, COLOR_BLUE, COLOR_BLACK); + init_pair(2, COLOR_BLACK, COLOR_CYAN); + init_pair(3, COLOR_WHITE, COLOR_BLUE); + int color_pair; int start_columns = size_x - 1 - 8*table_size - 2; @@ -610,16 +609,31 @@ void draw_table() { size_x-1, }; + // Draw rows with tasks. move(1, 0); + active_task = database.active_task; + selected_taskx = &database.tasks[selected_task]; for (uint32_t idx = 0; idx < database.count; idx++){ task = &database.tasks[idx]; // Enable highlight color on selected entry. - if (idx == selected_task) { - attron(COLOR_PAIR(1)); + color_pair = 0; + if (task == active_task) { + color_pair = 1; + } + if (task == selected_taskx) { + color_pair = 2; + } + if (task == active_task && task == selected_taskx) { + color_pair = 3; + } + if (color_pair > 0) { + attron(COLOR_PAIR(color_pair)); } + attron(COLOR_PAIR(color_pair)); + // Clear line_buffer and add string termination. memset(line_buffer, ' ', size_x * sizeof(char)); line_buffer[size_x-1] = '\0'; @@ -632,8 +646,8 @@ void draw_table() { addstr(line_buffer); // Disable highlight color on selected entry. - if (idx == selected_task) { - attroff(COLOR_PAIR(1)); + if (color_pair > 0) { + attroff(COLOR_PAIR(color_pair)); } // Print columns separators. @@ -646,6 +660,27 @@ void draw_table() { pos_y++; move(pos_y, 0); } + + // Draw empty rows. + // TODO Do this properly. + int dummy = 100; + while (dummy > 0) { + + // Clear current line. + move(pos_y, 0); + clrtoeol(); + + // Print columns separators. + pos_y = getcury(stdscr); + for (int c_idx = 0; c_idx < sizeof(columns)/sizeof(int); c_idx++) { + mvaddch(pos_y, columns[c_idx], ACS_VLINE); + } + + pos_y++; + move(pos_y, 0); + dummy--; + } + } void draw_footer() { @@ -667,14 +702,41 @@ void draw_footer() { printw(app_version); addch(' '); addch(ACS_LRCORNER); + + + + // TODO This code is now repeated accross the header, table and footer. Clean this up. + layout_t* layout = &layouts[selected_layout]; + int table_size = layout->table_size; + char** table_headers = layout->table_headers; + + int start_columns = size_x - 1 - 8*table_size - 2; + int columns[] = { + 0, + start_columns+(table_size*0), + start_columns+(table_size*1), + start_columns+(table_size*2), + start_columns+(table_size*3), + start_columns+(table_size*4), + start_columns+(table_size*5), + start_columns+(table_size*6), + start_columns+(table_size*7), + }; + + mvaddstr(row-1, columns[0]+2, table_headers[0]); + for (int idx = 1; idx < 9; idx++) { + mvaddch(row-1, columns[idx], ACS_BTEE); + } } WINDOW *create_newwin(int height, int width, int starty, int startx); void destroy_win(WINDOW *local_win); int main(int argc, char *argv[]) { - initialization(); + // Make sure architecture uses 8bits per char. + assert(CHAR_BIT == 8); + // TODO Parse commands using: https://stackoverflow.com/questions/9642732/parsing-command-line-arguments-in-c if (argc > 1) { @@ -741,7 +803,7 @@ int main(int argc, char *argv[]) { return EXIT_FAILURE; } - load_database(&database, DB_BIN_PATH_NAME); + initialization(); initialize_layouts(); @@ -749,24 +811,56 @@ int main(int argc, char *argv[]) { int startx, starty, width, height; int ch; - initscr(); /* Start curses mode */ - cbreak(); /* Line buffering disabled, Pass on - * everty thing to me */ - keypad(stdscr, TRUE); /* I need that nifty F1 */ - curs_set(0); // Set cursor invisible. + initscr(); // Start curses mode. + cbreak(); // Line buffering disabled, Pass on everty thing to me. + keypad(stdscr, TRUE); // I need that nifty F1 + curs_set(0); // Set cursor invisible. height = 3; width = 10; - starty = (LINES - height) / 2; /* Calculating for a center placement */ - startx = (COLS - width) / 2; /* of the window */ + starty = (LINES - height) / 2; // Calculating for a center placement of the window. + startx = (COLS - width) / 2; // printw("Press F1 to exit"); refresh(); my_win = create_newwin(height, width, starty, startx); ch = KEY_RESIZE; + ESCDELAY = 0; do { switch(ch) { + case KEY_F(1): + { + task_t new_task; + add_task(&database, &new_task); + move(database.count, 2); + curs_set(1); + getnstr(database.tasks[database.count-1].name, MAX_TASK_NAME-1); + curs_set(0); + break; + } + + case KEY_F(2): + remove_task(&database, selected_task); + break; + + case '\n': + case ' ': + if (true) { + task_t* current_task = database.active_task; + task_t* next_task = &database.tasks[selected_task]; + if (current_task != NULL) { + // TODO Add remaining time to task. + database.active_task = NULL; + } + if (current_task != next_task) { + database.active_task = next_task; + } + database.modified_on = time(NULL); + store_database(&database, DB_BIN_PATH_NAME); + } + break; + case KEY_RESIZE: erase(); if (line_buffer != NULL) { @@ -788,20 +882,15 @@ int main(int argc, char *argv[]) { case KEY_UP: selected_task = selected_task == 0 ? 0 : selected_task - 1; - destroy_win(my_win); - my_win = create_newwin(height, width, --starty,startx); break; case KEY_DOWN: selected_task = (selected_task+1) == database.count ? selected_task : selected_task + 1; - destroy_win(my_win); - my_win = create_newwin(height, width, ++starty,startx); break; } - selected_layout = size_x > 100 ? 0 : 1; - if (size_x >= 60 && size_y > 2) { + selected_layout = size_x > 100 ? 0 : 1; draw_header(); draw_table(); draw_footer(); @@ -810,9 +899,15 @@ int main(int argc, char *argv[]) { const char* INVALID_WINDOW_MESSAGE = "Please expand window."; mvaddstr(size_y / 2, (size_x - strlen(INVALID_WINDOW_MESSAGE)) / 2, INVALID_WINDOW_MESSAGE); } + + // TEST +// if (ch == KEY_F(1) || ch == KEY_F(2)) { +// mvprintw(1, 1, "db:'%u'/'%u'", database.count, database.capacity); +// } - } while((ch = getch()) != KEY_F(1)); + } while((ch = getch()) != 'q'); + store_database(&database, DB_BIN_PATH_NAME); free_memory(); endwin(); return EXIT_SUCCESS; -- cgit v1.2.3