changed some time formatting stuff to fix bugs

This commit is contained in:
Lexi Quinn 2021-10-05 02:18:25 +11:00
parent 24b576f59f
commit 67426fac09
7 changed files with 264 additions and 64 deletions

View File

@ -3,7 +3,7 @@ LIBS = -lm -luiohook
CC = gcc CC = gcc
CFLAGS = -g -Wall CFLAGS = -g -Wall
INSTALL_PATH = /usr/local INSTALL_PATH = /usr/local
VERSION = 0.5.0 VERSION = 0.5.1
.PHONY: default all clean .PHONY: default all clean

View File

@ -13,7 +13,7 @@ A speedrun timer for \*nix terminals
## Usage ## Usage
Copy `examples/sample.json` somewhere, replace the sample information with Copy `examples/sample.json` somewhere, replace the sample information with
the names of your game, catagories and splits. Changing split names/number of the names of your game, catagories and splits. Changing the number of
splits after the first use of the split file is currently unsupported. splits after the first use of the split file is currently unsupported.
### Default Keybinds ### Default Keybinds

View File

@ -1,11 +1,5 @@
#include "display.h" #include "display.h"
const char *millitime = "%8d.%d";
const char *secondstime = "%7d.%02d";
const char *minutestime = "%7d:%02d";
const char *hourstime = "%5d:%02d:%02d";
const char *fulltime = "%2d:%02d:%02d.%02d";
const char *sfulltime = "%4d:%02d.%02d";
#define MVCUR "\033[%d;%dH%s" #define MVCUR "\033[%d;%dH%s"
int maxrows = INT_MAX; int maxrows = INT_MAX;
int maxcols = INT_MAX; int maxcols = INT_MAX;
@ -100,14 +94,15 @@ void drawHLine(int row, int maxlen)
//Column 0 is the left justified column, all following columns columns count //Column 0 is the left justified column, all following columns columns count
//from the right hand side towards the left. //from the right hand side towards the left.
void drawColumn(char **data, int count, int column) void drawColumn(char **data, int count, int column, int end)
{ {
int x = maxcols - (column * 10) + 1; int x = maxcols - (column * 10) + 1;
int y = 6; int y = 6;
if (column == 0) if (column == 0)
x = 1; x = 1;
for (int i = 0; i < count; i++) { for (int i = 0; i < count; i++) {
printf(MVCUR, y + i, x, data[i]); if (i <= end)
printf(MVCUR, y + i, x, data[i]);
} }
} }
@ -122,12 +117,13 @@ void drawRow(char **data, int count, int row)
} }
} }
void drawCell(char *data, int column, int row) //In case you need colors, you gotta draw cell by cell
void drawCell(char *data, int column, int row, struct color col)
{ {
int x = maxcols - (column * 10); int x = maxcols - (column * 10) + 1;
if (column == 1) if (column == 1)
x = 1; x = 1;
printf(MVCUR, row, x, data); printf("\033[38;2;%d;%d;%dm\033[%d;%dH%s", col.r, col.g, col.b, row, x, data);
} }
void setMaxRows(int rows) void setMaxRows(int rows)

View File

@ -8,12 +8,6 @@
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
extern const char *millitime;
extern const char *secondstime;
extern const char *minutestime;
extern const char *hourstime;
extern const char *fulltime;
extern const char *sfulltime;
extern int maxrows; extern int maxrows;
extern int maxcols; extern int maxcols;
extern int colwidth; extern int colwidth;
@ -38,9 +32,9 @@ void cntrPrint(int row, int col, int maxlen, char *text);
void leftPrint(int row, int maxlen, char *text); void leftPrint(int row, int maxlen, char *text);
void rghtPrint(int row, int maxlem, char *text); void rghtPrint(int row, int maxlem, char *text);
void drawHLine(int row, int maxlen); void drawHLine(int row, int maxlen);
void drawColumn(char **data, int count, int column); void drawColumn(char **data, int count, int column, int end);
void drawRow(char **data, int count, int row); void drawRow(char **data, int count, int row);
void drawCell(char *data, int column, int row); void drawCell(char *data, int column, int row, struct color col);
void setMaxRows(int rows); void setMaxRows(int rows);
void setMaxCols(int cols); void setMaxCols(int cols);

View File

@ -35,9 +35,16 @@ void dispatch_proc(uiohook_event * const event) {
int handleInput() int handleInput()
{ {
ssize_t rd = read(pipefd[0], &buf, 1); //Non global hotkeys
char t; char t;
read(in, &t, 1); read(in, &t, 1);
if (t == 'c')
toggleCompact();
if (t == 'q')
return 1;
//Global hotkeys
ssize_t rd = read(pipefd[0], &buf, 1);
if ((!hotkeys_enabled && buf != K_HOTKS) || rd == -1) if ((!hotkeys_enabled && buf != K_HOTKS) || rd == -1)
return 0; return 0;
if (buf == K_SPLIT) if (buf == K_SPLIT)
@ -59,9 +66,5 @@ int handleInput()
unsplit(); unsplit();
if (buf == K_SKIP) if (buf == K_SKIP)
skip(); skip();
if (t == 'c')
toggleCompact();
if (t == 'q')
return 1;
return 0; return 0;
} }

View File

@ -1,13 +1,20 @@
#include "timer.h" #include "timer.h"
#define COLSTRLEN 11
//Timekeeping //Timekeeping
struct timespec timestart, finish, notif; struct timespec timestart, finish, notif;
int currentMS = 0; int currentMS = 0;
int timeSave = 0;
bool timerActive; bool timerActive;
//UI //UI
struct color bg = { 47, 53, 66}; struct color bg = { 47, 53, 66};
struct color fg = {247, 248, 242}; struct color fg = {247, 248, 242};
struct color fade = {210, 210, 210};
struct color gold = {249, 255, 79};
struct color good = { 79, 255, 85};
struct color bad = {255, 79, 79};
int h, w; int h, w;
bool compact = false; bool compact = false;
bool dirty = false; bool dirty = false;
@ -16,7 +23,7 @@ bool dirty = false;
const char *schemaver = "v1.0.1"; const char *schemaver = "v1.0.1";
const char *timersname = "quest"; const char *timersname = "quest";
const char *timerlname = "Quinn's Utterly Elegant Speedrun Timer"; const char *timerlname = "Quinn's Utterly Elegant Speedrun Timer";
const char *timerver = "v0.5.0"; const char *timerver = "v0.5.1";
const char *timerlink = "https://github.com/SilentFungus/quest"; const char *timerlink = "https://github.com/SilentFungus/quest";
//Run data //Run data
@ -55,6 +62,7 @@ void start()
clock_gettime(CLOCK_REALTIME, &timestart); clock_gettime(CLOCK_REALTIME, &timestart);
timerActive = true; timerActive = true;
//Reset state of timer //Reset state of timer
dirty = true;
for(int i = 0; i < segCount; i++) { for(int i = 0; i < segCount; i++) {
segments[i].ms = 0; segments[i].ms = 0;
segments[i].isSkipped = false; segments[i].isSkipped = false;
@ -130,33 +138,103 @@ void loadKeymap()
km.SKIP = VC_V; km.SKIP = VC_V;
} }
void ftime(char *timestr, bool withMS, int rms) void ftime(char *timestr, int rms, int decimals, bool sign)
{ {
if (decimals > 3 || decimals < 0)
decimals = 0;
int seconds = rms / 1000; int seconds = rms / 1000;
int minutes = seconds / 60; int minutes = seconds / 60;
int hours = minutes / 60; int hours = minutes / 60;
//A few better formatted variables for displaying these numbers //A few better formatted variables for displaying these numbers
int tms = (rms % 1000) / 10; int thr = rms % 1000;
int oms = tms / 10; int two = thr / 10;
int one = two / 10;
int s = seconds % 60; int s = seconds % 60;
int m = minutes % 60; int m = minutes % 60;
int h = hours; int h = hours;
int d = 0;
switch (decimals) {
case 1:
d = one;
break;
case 2:
d = two;
break;
case 3:
d = thr;
break;
}
char tformat[22];
int i = 0;
int decimalspace = decimals + (decimals != 0);
if (hours) {
tformat[i++] = '%';
if (sign)
tformat[i++] = '+';
tformat[i++] = (colwidth - 6 - decimalspace) + 48;
tformat[i++] = 'd';
tformat[i++] = ':';
}
if (minutes) {
tformat[i++] = '%';
if (sign && !hours)
tformat[i++] = '+';
if (hours) {
tformat[i++] = '0';
tformat[i++] = '2';
} else {
tformat[i++] = (colwidth - 3 - decimalspace) + 48;
}
tformat[i++] = 'd';
tformat[i++] = ':';
}
tformat[i++] = '%';
if (s != 0 && sign && !hours && !minutes)
tformat[i++] = '+';
if (minutes) {
tformat[i++] = '0';
tformat[i++] = '2';
} else {
//This value can push the resulting char out of the numbers
//section of the ascii table so we gotta clamp it
int n = colwidth - decimalspace + 48;
if (n >= 58)
n = 57;
tformat[i++] = n;
}
tformat[i++] = 'd';
if (decimals) {
tformat[i++] = '.';
tformat[i++] = '%';
tformat[i++] = '0';
tformat[i++] = decimals + 48;
tformat[i++] = 'd';
}
tformat[i] = 0;
if (hours) { if (hours) {
if (withMS) if (!decimals)
sprintf(timestr, fulltime, h, abs(h), abs(m), abs(s), abs(tms)); sprintf(timestr, tformat, h, abs(m), abs(s));
else else
sprintf(timestr, hourstime, h, abs(m), abs(s)); sprintf(timestr, tformat, h, abs(m), abs(s), abs(d));
} else if (minutes) { } else if (minutes) {
if (withMS) if (!decimals)
sprintf(timestr, sfulltime, m, abs(s), abs(tms)); sprintf(timestr, tformat, m, abs(s));
else else
sprintf(timestr, minutestime, m, abs(s)); sprintf(timestr, tformat, m, abs(s), abs(d));
} else { } else {
if (withMS) if (!decimals) {
sprintf(timestr, secondstime, s, abs(tms)); sprintf(timestr, tformat, s);
else } else {
sprintf(timestr, millitime, s, abs(oms)); sprintf(timestr, tformat, s, abs(d));
if (sign && s == 0 && d < 0)
timestr[COLSTRLEN - 4 - decimals] = '-';
if (sign && s == 0 && d >= 0)
timestr[COLSTRLEN - 4 - decimals] = '+';
}
} }
} }
@ -171,25 +249,56 @@ void drawSegmentNames()
for(int i = 0; i < segCount; i++) { for(int i = 0; i < segCount; i++) {
names[i] = segments[i].name; names[i] = segments[i].name;
} }
drawColumn(names, segCount, 0); drawColumn(names, segCount, 0, segCount);
}
//TODO: Fix up all this commented garbage
//Really the entire display system needs rethinking first but yea
void drawDeltaColumn(int column)
{
char *times[segCount];
for (int i = 0; i < segCount; i++) {
times[i] = calloc(1, COLSTRLEN);
int time = 0;
if (i == currSeg)
time = currentMS - pbrun[i].ms;
else if (i < currSeg)
time = segments[i].ms - pbrun[i].ms;
ftime(times[i], time, 1, true);
struct color col = {0};
if (time <= 0)
col = good;
else
col = bad;
if (i < currSeg)
drawCell(times[i], column, i + 6, col);
if (i == currSeg && time >= -5000)
drawCell(times[i], column, i + 6, col);
}
//drawColumn(times, segCount, column, currSeg);
//Use drawCell because we're doing colors.
//for (int i = 0; i < segCount; i++) {
// if (i <= currSeg)
// drawCell(times[i], column, i + 6, good);
//}
setFGColor(fg);
for (int i = 0; i < segCount; i++) {
free(times[i]);
}
} }
//TODO: try to clean the branching up //TODO: try to clean the branching up
void drawTimeColumn(int timeoption, int column) void drawTimeColumn(int timeoption, int column)
{ {
char *times[segCount]; char *times[segCount];
int drawEnd = currSeg;
for (int i = 0; i < segCount; i++) { for (int i = 0; i < segCount; i++) {
times[i] = calloc(1, 11); times[i] = calloc(1, COLSTRLEN);
int time = 0; int time = 0;
switch (timeoption) { switch (timeoption) {
case 0: case 0:
time = pbrun[i].ms; time = pbrun[i].ms;
break; drawEnd = segCount;
case 1:
if (i == currSeg)
time = currentMS - pbrun[i].ms;
else
time = segments[i].ms - pbrun[i].ms;
break; break;
case 2: case 2:
if (i > 0 && i < currSeg) if (i > 0 && i < currSeg)
@ -207,9 +316,9 @@ void drawTimeColumn(int timeoption, int column)
else else
time = segments[i].ms; time = segments[i].ms;
} }
ftime(times[i], false, time); ftime(times[i], time, 1, false);
} }
drawColumn(times, segCount, column); drawColumn(times, segCount, column, drawEnd);
for (int i = 0; i < segCount; i++) { for (int i = 0; i < segCount; i++) {
free(times[i]); free(times[i]);
} }
@ -250,6 +359,7 @@ void drawDisplay()
rghtPrint(2, w, atmpt); rghtPrint(2, w, atmpt);
cntrPrint(1, w / 2, w, gameTitle); cntrPrint(1, w / 2, w, gameTitle);
cntrPrint(2, w / 2, w, categoryTitle); cntrPrint(2, w / 2, w, categoryTitle);
setFGColor(fade);
drawHLine(5, w); drawHLine(5, w);
printf("\033[5;3H"); printf("\033[5;3H");
if (hotkeys_enabled || compact) if (hotkeys_enabled || compact)
@ -260,26 +370,34 @@ void drawDisplay()
printf("c"); printf("c");
if (hotkeys_enabled || compact) if (hotkeys_enabled || compact)
printf("]"); printf("]");
setFGColor(fg);
drawSegmentNames(); drawSegmentNames();
//TODO: The column names stuff has to be more dynamic, part of the //TODO: The column names stuff has to be more dynamic, part of the
//drawColumn function probably //drawColumn function probably
if (!compact) { if (!compact) {
char cols[41]; char cols[41];
sprintf(cols, "%10s%10s%10s%10s", "Delta", "Sgmt", "Time", "PB"); sprintf(cols, "%10s%10s%10s%10s", "Delta", "Sgmt", "Time", "PB");
setFGColor(fade);
rghtPrint(4, w, cols); rghtPrint(4, w, cols);
setFGColor(fg);
drawTimeColumn(0, 1); drawTimeColumn(0, 1);
drawTimeColumn(3, 2); drawTimeColumn(3, 2);
drawTimeColumn(2, 3); drawTimeColumn(2, 3);
drawTimeColumn(1, 4); drawDeltaColumn(4);
} else { } else {
char cols[21]; char cols[21];
sprintf(cols, "%10s%10s", "Delta", "Time/PB"); sprintf(cols, "%10s%10s", "Delta", "Time/PB");
setFGColor(fade);
rghtPrint(4, w, cols); rghtPrint(4, w, cols);
setFGColor(fg);
drawTimeColumn(0, 1);
drawTimeColumn(3, 1); drawTimeColumn(3, 1);
drawTimeColumn(1, 2); drawDeltaColumn(2);
} }
setFGColor(fade);
drawHLine(segCount + 6, w); drawHLine(segCount + 6, w);
ftime(currentTime, true, currentMS); setFGColor(fg);
ftime(currentTime, currentMS, 2, false);
rghtPrint(segCount + 7, w, currentTime); rghtPrint(segCount + 7, w, currentTime);
fflush(stdout); fflush(stdout);
} }
@ -435,9 +553,9 @@ void loadFile()
cJSON_ArrayForEach(iIterator, oIterator) { cJSON_ArrayForEach(iIterator, oIterator) {
struct pastseg t; struct pastseg t;
cJSON *rms = cJSON_GetItem(iIterator, "rms"); cJSON *rms = cJSON_GetItem(iIterator, "m");
cJSON *skp = cJSON_GetItem(iIterator, "skipped"); cJSON *skp = cJSON_GetItem(iIterator, "s");
cJSON *rst = cJSON_GetItem(iIterator, "reset"); cJSON *rst = cJSON_GetItem(iIterator, "r");
t.ms = rms->valueint; t.ms = rms->valueint;
if (cJSON_IsTrue(skp)) if (cJSON_IsTrue(skp))
@ -507,6 +625,95 @@ void importSplitsIO(cJSON *splitfile)
cJSON_Delete(splitfile); cJSON_Delete(splitfile);
} }
void exportSplitsIO()
{
//cJSON root node
cJSON *export = NULL;
//Schema version
cJSON *schema = NULL;
//Links
cJSON *links_root = NULL;
cJSON *speedruncom_id = NULL;
cJSON *splitsio_id = NULL;
//Timer
cJSON *timer_root = NULL;
cJSON *timer_shortname = NULL;
cJSON *timer_longname = NULL;
cJSON *timer_version = NULL;
cJSON *timer_website = NULL;
//Attempts
cJSON *attempts_root = NULL;
cJSON *attempts_total = NULL;
cJSON *histories = NULL;
cJSON *history_root = NULL;
cJSON *history_attmpt = NULL;
cJSON *history_dur = NULL;
cJSON *history_dur_rms = NULL;
cJSON *history_dur_gms = NULL;
//Supplementary data
cJSON *image_url = NULL;
cJSON *video_url = NULL;
//Time
cJSON *started_at = NULL;
cJSON *ended_at = NULL;
//Pauses
cJSON *pauses_root = NULL;
cJSON *pause_started = NULL;
cJSON *pause_ended = NULL;
//Game
cJSON *game_root = NULL;
cJSON *game_longname = NULL;
cJSON *game_shortname = NULL;
cJSON *game_links = NULL;
cJSON *game_srcom_id = NULL;
cJSON *game_splits_id = NULL;
//Catagory
cJSON *cate_root = NULL;
cJSON *cate_longname = NULL;
cJSON *cate_shortname = NULL;
cJSON *cate_links = NULL;
cJSON *cate_splits_id = NULL;
cJSON *cate_spdrun_id = NULL;
//Runners
cJSON *runner_root = NULL;
cJSON *runner_longname = NULL;
cJSON *runner_shrtname = NULL;
cJSON *runner_links = NULL;
cJSON *runner_twitch = NULL;
cJSON *runner_spltsio = NULL;
cJSON *runner_spdrun = NULL;
cJSON *runner_twitter = NULL;
//Segments
cJSON *seg_root = NULL;
cJSON *seg_name = NULL;
cJSON *seg_ended = NULL;
cJSON *seg_ended_rms = NULL;
cJSON *seg_ended_gms = NULL;
cJSON *seg_best = NULL;
cJSON *seg_best_rms = NULL;
cJSON *seg_best_gms = NULL;
cJSON *seg_is_skipped = NULL;
cJSON *seg_is_reset = NULL;
cJSON *seg_histories = NULL;
cJSON *seg_hst_attmp = NULL;
cJSON *seg_hst_end = NULL;
cJSON *seg_hst_end_rms = NULL;
cJSON *seg_hst_end_gms = NULL;
cJSON *seg_hst_skp = NULL;
cJSON *seg_hst_rst = NULL;
}
void saveFile() void saveFile()
{ {
if (timerActive) if (timerActive)
@ -550,9 +757,9 @@ void saveFile()
cJSON *skp = cJSON_CreateBool(t.isSkipped); cJSON *skp = cJSON_CreateBool(t.isSkipped);
cJSON *rst = cJSON_CreateBool(t.isReset); cJSON *rst = cJSON_CreateBool(t.isReset);
cJSON_AddItemToObject(seg, "rms", tim); cJSON_AddItemToObject(seg, "m", tim);
cJSON_AddItemToObject(seg, "skipped", skp); cJSON_AddItemToObject(seg, "s", skp);
cJSON_AddItemToObject(seg, "reset", rst); cJSON_AddItemToObject(seg, "r", rst);
cJSON_AddItemToArray(run, seg); cJSON_AddItemToArray(run, seg);
} }

View File

@ -45,7 +45,7 @@ void tpause();
void unsplit(); void unsplit();
void skip(); void skip();
void loadKeymap(); void loadKeymap();
void ftime(char *timestr, bool withMS, int ms); void ftime(char *timestr, int rms, int decimals, bool sign);
int timespecToMS(struct timespec t); int timespecToMS(struct timespec t);
void drawNotif(); void drawNotif();
void clearNotif(); void clearNotif();