aboutsummaryrefslogtreecommitdiff
path: root/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'main.c')
-rw-r--r--main.c209
1 files changed, 152 insertions, 57 deletions
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;