aboutsummaryrefslogtreecommitdiff
path: root/ttt.jai
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-04-04 17:45:05 +0100
committerdam <dam@gudinoff>2023-04-04 17:45:05 +0100
commit98a21ce9edcd22bf7a9dde62f317f143e289ecf5 (patch)
tree14613e8506a6fe481b2072fae7aad826809b1b19 /ttt.jai
parentee5fa34d14288a4ce79d77a0d3a89cc14b16a6b1 (diff)
downloadtask-time-tracker-98a21ce9edcd22bf7a9dde62f317f143e289ecf5.tar.zst
task-time-tracker-98a21ce9edcd22bf7a9dde62f317f143e289ecf5.zip
WIP Making ncurses work a bit.
Diffstat (limited to 'ttt.jai')
-rw-r--r--ttt.jai213
1 files changed, 106 insertions, 107 deletions
diff --git a/ttt.jai b/ttt.jai
index 96a5fdb..b5fb59d 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -74,20 +74,23 @@ Database :: struct {
database : Database;
archive : Database;
is_autosave_enabled := true;
-// int countdown_to_autosave = -1;
+countdown_to_autosave := -1;
app_directory : string;
db_file_path : string;
ar_file_path : string;
// char *string_buffer = NULL; // A temporary buffer for localized actions. Please avoid data leaks and out-of-bounds errors.
// size_t string_buffer_size = 0;
-// int size_x, size_y, pos_x, pos_y;
+size_x : s32;
+size_y : s32;
+pos_x : s32;
+pos_y : s32;
Styles :: enum s16 {
STYLE_SELECTED :: 1;
- STYLE_SELECTED_INVERTED;
+ SELECTED_INVERTED;
STYLE_ACTIVE;
STYLE_ACTIVE_SELECTED;
- STYLE_ERROR;
+ ERROR;
}
Layouts :: enum u8 {
@@ -109,7 +112,7 @@ print_error :: (format :string, args : .. Any) {
// int w_size_y = 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);
-// wattron(error_window, COLOR_PAIR(STYLE_ERROR));
+// wattron(error_window, COLOR_PAIR(ERROR));
// wborder(error_window, ' ', ' ', 0, 0, ACS_HLINE, ACS_HLINE, ACS_HLINE, ACS_HLINE);
// mvwprintw(error_window, 0, 1, " Error ");
// wmove(error_window, 1, 0);
@@ -152,18 +155,15 @@ draw_error_window :: () {
*/
}
-/*
-void trigger_autosave() {
+trigger_autosave :: () {
countdown_to_autosave = 13375; // ms
}
-void show_processing() {
+show_processing :: () {
mvaddch(0, 0, ACS_DIAMOND);
refresh();
}
-*/
-
// Returns true if string to_compare is equal to any of the other passed strings, false otherwise.
is_equal_to_any :: (to_compare :string, test_a :string, test_b :string) -> bool {
return to_compare == test_a || to_compare == test_b;
@@ -299,29 +299,24 @@ sub_int64 :: (x :s64, y :s64) -> s64 {
x - y;
}
-/*
// Returns active task or NULL if none applies.
-task_st *get_active_task(database_st *db) {
- assert(db != NULL);
-
- task_st *task = NULL;
- if (db->active_task >= 0) {
- task = db->tasks + db->active_task;
+get_active_task :: inline (db: Database) -> *Task {
+ task: *Task = null;
+ if (db.active_idx >= 0) {
+ task = *db.tasks[db.active_idx];
}
return task;
}
// Returns selected task or NULL if none applies.
-task_st *get_selected_task(database_st *db) {
- assert(db != NULL);
-
- task_st *task = NULL;
- if (db->selected_task >= 0) {
- task = db->tasks + db->selected_task;
+get_selected_task :: inline (db: Database) -> *Task {
+ task: *Task = null;
+ if (db.selected_idx >= 0) {
+ task = *db.tasks[db.selected_idx];
}
return task;
}
-*/
+
// Adds a task to the database.
// If necessary, expands database capacity.
// Returns success.
@@ -528,11 +523,12 @@ void move_task_to_index(database_st *db, task_st *task, ptrdiff_t index) {
}
db->selected_task = target_index;
}
-
+*/
// Updates the times on the active task (and adjusts database totals).
-void update_times(database_st *db) {
- assert(db != NULL);
-
+update_times :: (db: *Database) {
+ assert(db != null);
+ return;
+ /*
// Get current UTC time.
time_t stop_time = time(NULL);
@@ -566,8 +562,9 @@ void update_times(database_st *db) {
start_time = next_start;
}
+ */
}
-
+/*
// Recalculates database totals.
void update_total_times(database_st *db) {
assert(db != NULL);
@@ -642,8 +639,7 @@ reset_database :: (db: *Database) {
// Stores data from database into binary file.
// Returns success.
-store_database :: (db: *Database, path: string) -> success: bool {
- assert(db != null, "Parameter 'db' is null.");
+store_database :: (db: Database, path: string) -> success: bool {
assert(xx path, "Parameter 'path' is empty.");
// Open file.
@@ -655,7 +651,7 @@ store_database :: (db: *Database, path: string) -> success: bool {
defer file_close(*file);
file_write(*file, DB_FILE_SIGN_STR);
- file_write(*file, db, size_of(Database));
+ file_write(*file, *db, size_of(Database));
file_write(*file, db.tasks.data, size_of(Task) * db.tasks.count);
return true;
@@ -710,8 +706,7 @@ load_database :: (db: *Database, path: string) -> success: bool {
// Exports data into CSV file.
// Returns success.
-export_to_csv :: (db: *Database, path: string) -> success: bool {
- assert(db != null, "Parameter 'db' is null.");
+export_to_csv :: (db: Database, path: string) -> success: bool {
assert(xx path, "Parameter 'path' is empty.");
// TODO Make sure (IN ALL PROCEDURES) we're not receiving an empty path.
@@ -1013,7 +1008,7 @@ initialize_tui :: () {
// TODO
//setlocale(LC_ALL, "C.UTF-8"); // Sets locale for C library functions; Allows usage of UTF-8.
- stdscr = initscr(); // Start curses mode.
+ stdscr = initscr(); // Start curses mode.
cbreak(); // Line buffering disabled; pass on everty thing to me.
keypad(stdscr, true); // I need those nifty F1..F12.
curs_set(0); // Set cursor invisible.
@@ -1023,29 +1018,28 @@ initialize_tui :: () {
start_color();
use_default_colors(); // Using default (-1) instead of COLOR_BLACK.
init_pair(xx Styles.STYLE_SELECTED, COLOR_BLACK, COLOR_CYAN);
- init_pair(xx Styles.STYLE_SELECTED_INVERTED, COLOR_CYAN, -1);
+ init_pair(xx Styles.SELECTED_INVERTED, COLOR_CYAN, -1);
init_pair(xx Styles.STYLE_ACTIVE, COLOR_BLUE, -1);
init_pair(xx Styles.STYLE_ACTIVE_SELECTED, COLOR_WHITE, COLOR_BLUE);
- init_pair(xx Styles.STYLE_ERROR, COLOR_RED, -1);
+ init_pair(xx Styles.ERROR, COLOR_RED, -1);
}
-/*
-void update_layout() {
+update_layout :: () {
// Calculate number of available rows to display tasks.
layout_tasks_rows = (size_y - NUM_HEADER_ROWS - NUM_FOOTER_ROWS);
// Calculate first column width: expands to fill the remaining space dynamically.
- for (layout_st *layout = layouts; layout <= &layouts[NUM_LAYOUTS - 1]; layout++) {
- layout->columns[0].width = size_x - (NUM_COLUMNS - 1) - 2;
- for (int idx = 1; idx < NUM_COLUMNS; idx++) {
- layout->columns[0].width -= layout->columns[idx].width;
+ for * layout: layouts {
+ layout.columns[0].width = size_x - (NUM_COLUMNS - 1) - 2;
+ for 1..layout.columns.count-1 {
+ layout.columns[0].width -= layout.columns[it].width;
}
}
}
-void draw_tui(database_st *db, layout_st *layout) {
-
- const static int adjust_first_day_of_week[] = {
+draw_tui :: (db: *Database, layout: *Layout) {
+
+ adjust_first_day_of_week := int.[
(0 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS,
(1 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS,
(2 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS,
@@ -1053,36 +1047,37 @@ void draw_tui(database_st *db, layout_st *layout) {
(4 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS,
(5 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS,
(6 + FIRST_DAY_OF_WEEK) % NUM_WEEK_DAYS,
- };
-
- int x, y;
- column_st *col;
+ ];
+ x: int;
+ y: int;
+ col: *Column;
+
// Get context information.
- task_st *active_task = get_active_task(db);
- task_st *selected_task = get_selected_task(db);
- time_t now_utc = time(NULL);
- int now_week_day = localtime(&now_utc)->tm_wday;
+ active_task := get_active_task(db);
+ selected_task := get_selected_task(db);
+ now_utc := current_time_consensus();
+ now_week_day := to_calendar(now_utc).day_of_week_starting_at_0;
// Reset theme and clear screen.
attrset(A_NORMAL);
erase();
-
+
// Draw outer border.
box(stdscr, 0, 0);
-
+
// Draw table grids.
y = 0;
x = 0;
- for (int idx = 0; idx < NUM_COLUMNS - 1; 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);
+ for layout.columns {
+ x += 1 + it.width;
+ mvaddch(xx y, xx x, ACS_TTEE);
+ for row: 1..size_y-1 {
+ mvaddch(xx row, xx x, ACS_VLINE);
}
- mvaddch(size_y - 1, x, ACS_BTEE);
+ mvaddch(size_y-1, xx x, ACS_BTEE);
}
-
+return; /*
///////////////////////////////////////////////////////////////////////////
// Draw headers.
@@ -1105,7 +1100,7 @@ void draw_tui(database_st *db, layout_st *layout) {
attron(COLOR_PAIR(STYLE_ACTIVE) | A_BOLD);
}
else if (idx == now_week_day) {
- attron(COLOR_PAIR(STYLE_SELECTED_INVERTED) | A_BOLD);
+ attron(COLOR_PAIR(SELECTED_INVERTED) | A_BOLD);
}
col = &layout->columns[L_DAYS_IDX + idx];
@@ -1203,7 +1198,7 @@ void draw_tui(database_st *db, layout_st *layout) {
attron(COLOR_PAIR(STYLE_ACTIVE) | A_BOLD);
}
else if (idx == now_week_day) {
- attron(COLOR_PAIR(STYLE_SELECTED_INVERTED) | A_BOLD);
+ attron(COLOR_PAIR(SELECTED_INVERTED) | A_BOLD);
}
column_width = layout->columns[L_DAYS_IDX + idx].width;
@@ -1216,8 +1211,9 @@ void draw_tui(database_st *db, layout_st *layout) {
}
x++;
mvprintw_time(y, x, total_time, layout->columns[L_TOTAL_IDX].width);
+ */
}
-
+/*
void *mem_alloc(size_t mem_size, const char *error_tag) {
void *mem_pointer = malloc(mem_size);
if (mem_pointer == NULL && mem_size > 0) {
@@ -1335,14 +1331,14 @@ main :: () {
{ // Initialize database and archive files if needed.
if (file_exists(db_file_path) == false) {
- if (store_database(*database, db_file_path) == false) {
+ if (store_database(database, db_file_path) == false) {
print_error("Failed to initialize database.");
exit(1);
}
}
if (file_exists(ar_file_path) == false) {
- if (export_to_csv(*archive, ar_file_path) == false) {
+ if (export_to_csv(archive, ar_file_path) == false) {
print_error("Failed to initialize archive.");
exit(1);
}
@@ -1474,67 +1470,69 @@ main :: () {
}
initialize_tui();
- /*
+
// TODO Remove this?!
//signal(SIGTERM, exit_gracefully);
//signal(SIGINT, exit_gracefully);
//signal(SIGQUIT, exit_gracefully);
//signal(SIGHUP, exit_gracefully);
+ layout := *layouts[Layouts.COMPACT];
+ db := *database;
+
flushinp();
ungetch(KEY_RESIZE);
- for (int key; ((key = getch()) != 'q') && (key != 'Q'); ) {
+ while (true) {
+ key := getch();
+ if key == #char "q" || key == #char "Q" break;
- static layout_st *layout = &layouts[L_COMPACT];
- task_st *active_task = get_active_task(db);
- task_st *selected_task = get_selected_task(db);
- int action_style = A_BOLD | COLOR_PAIR(selected_task == active_task && selected_task != NULL ? STYLE_ACTIVE : STYLE_SELECTED_INVERTED);
- int error_style = A_BOLD | COLOR_PAIR(STYLE_ERROR);
- int selected_task_row = is_terminal_too_small ? 0
- : (db->selected_task < 0) ? 1
- : (db->selected_task % layout_tasks_rows) + NUM_HEADER_ROWS;
+ active_task := get_active_task(db);
+ selected_task := get_selected_task(db);
+ action_style := A_BOLD | COLOR_PAIR(xx ifx selected_task == active_task && selected_task != null
+ then Styles.STYLE_ACTIVE
+ else Styles.SELECTED_INVERTED);
+ error_style := A_BOLD | COLOR_PAIR(xx Styles.ERROR);
+ selected_task_row : int = ifx is_terminal_too_small then 0
+ else ifx (db.selected_idx < 0) then 1
+ else (db.selected_idx % layout_tasks_rows) + NUM_HEADER_ROWS;
timeout(INPUT_AWAIT_INF);
- update_times(&database);
+ update_times(*database);
- switch(key) {
+ if key == {
// When getch() times out.
- case ERR: {
+ case ERR;
if (is_autosave_enabled && countdown_to_autosave > 0) {
countdown_to_autosave -= INPUT_TIMEOUT_MS;
if (countdown_to_autosave <= 0) {
show_processing();
- if (db == &archive) {
- export_to_csv(&archive, ar_file_path);
+ if (db == *archive) {
+ export_to_csv(*archive, ar_file_path);
}
- store_database(&database, db_file_path);
+ store_database(database, db_file_path);
}
}
- break;
- }
// When terminal is resized.
- case KEY_RESIZE: {
+ case KEY_RESIZE; // BUG KEY_RESIZE is not happening.
clear();
- getmaxyx(stdscr, size_y, size_x);
+ getmaxyx(stdscr, *size_y, *size_x);
is_terminal_too_small = size_x < 60 || size_y < 3;
- size_t new_size = 2047 | TASK_NAME_BYTES | (size_x + 1);
- if (string_buffer_size < new_size) {
- string_buffer_size = new_size;
- string_buffer = realloc(string_buffer, string_buffer_size);
- if (string_buffer == NULL && string_buffer_size > 0) {
- print_error("Failed to allocate memory for string buffer: %s.", strerror(errno));
- flushinp();
- ungetch('q');
- break;
- }
- }
+ new_size := 2047 | TASK_NAME_BYTES | (size_x + 1);
+ //if (string_buffer_size < new_size) {
+ //string_buffer_size = new_size;
+ //string_buffer = realloc(string_buffer, string_buffer_size);
+ //if (string_buffer == NULL && string_buffer_size > 0) {
+ //print_error("Failed to allocate memory for string buffer: %s.", strerror(errno));
+ //flushinp();
+ //ungetch(#char "q");
+ //break;
+ //}
+ //}
update_layout();
- layout = &layouts[size_x > 100 ? L_NORMAL : L_COMPACT];
- break;
- }
-
+ layout = *layouts[ifx size_x > 100 then Layouts.NORMAL else Layouts.COMPACT];
+/*
case 'n':
case 'N':{
if (is_database_full(db)) {
@@ -1849,12 +1847,12 @@ main :: () {
select_task_by_delta(db, layout_tasks_rows);
break;
}
+*/
}
if (is_terminal_too_small) {
- const char *INVALID_WINDOW_MESSAGE = "Terminal is too small: minimum 60x3.";
- const int INVALID_WINDOW_MESSAGE_LENGTH = strlen(INVALID_WINDOW_MESSAGE);
- mvaddstr(size_y / 2, (size_x - INVALID_WINDOW_MESSAGE_LENGTH) / 2, INVALID_WINDOW_MESSAGE);
+ INVALID_WINDOW_MESSAGE :: "Terminal is too small: minimum 60x3.";
+ mvaddstr(size_y / 2, (size_x - xx INVALID_WINDOW_MESSAGE.count) / 2, INVALID_WINDOW_MESSAGE);
}
else {
draw_tui(db, layout);
@@ -1862,8 +1860,9 @@ main :: () {
}
timeout(INPUT_TIMEOUT_MS);
+
}
- */
+
// Save any unsaved changes.
// show_processing();
error_saving := false;