FxLibcTest/src/widgets/fbar.c

188 lines
4.8 KiB
C

#include <ft/widgets/fbar.h>
#include <justui/jwidget-api.h>
#include <gint/std/stdlib.h>
#include <gint/std/string.h>
/* Type identifier for fbar */
static int fbar_type_id = -1;
fbar *fbar_create(void *parent)
{
if(fbar_type_id < 0) return NULL;
fbar *b = malloc(sizeof *b);
if(!b) return NULL;
jwidget_init(&b->widget, fbar_type_id, parent);
b->tests = NULL;
b->lists = NULL;
jwidget_set_margin(b, 0, 8, 2, 8);
return b;
}
void fbar_set_tests(fbar *b, ft_test **tests)
{
b->tests = tests;
b->lists = NULL;
b->widget.update = 1;
}
void fbar_set_lists(fbar *b, ft_list *lists)
{
b->tests = NULL;
b->lists = lists;
b->widget.update = 1;
}
//---
// Counting statistics
//---
struct stats {
/* Number of tests done, pending and empty (proportion of full bar) */
int16_t done;
int16_t pending;
int16_t empty;
/* Number of assertions (proportion of the done section of the bar) */
int16_t passed;
int16_t skipped;
int16_t failed;
};
static void stats_init(struct stats *st)
{
memset(st, 0, sizeof *st);
}
static void stats_add_test(struct stats *st, ft_test *t)
{
st->passed += t->passed;
st->skipped += t->skipped;
st->failed += t->failed;
if(!t->function) st->empty++;
else if(t->passed + t->skipped + t->failed == 0) st->pending++;
else st->done++;
}
static void stats_add_list(struct stats *st, ft_list *l)
{
if(!l->children) return;
for(int i = 0; l->children[i]; i++)
stats_add_test(st, l->children[i]);
}
//---
// Polymorphic widget operations
//---
static void fbar_poly_csize(void *b0)
{
fbar *b = b0;
b->widget.w = 120;
b->widget.h = 13;
}
static void fbar_poly_render(void *b0, int x, int y)
{
fbar *b = b0;
int w = jwidget_content_width(b);
int h = jwidget_content_height(b);
struct stats st, px;
stats_init(&st);
stats_init(&px);
if(b->tests) for(int i = 0; b->tests[i]; i++) {
stats_add_test(&st, b->tests[i]);
}
else if(b->lists) for(int i = 0; b->lists[i].name; i++) {
stats_add_list(&st, &b->lists[i]);
}
/* Width of bar for each of the 3 main sections */
int main = st.done + st.pending + st.empty;
if(main == 0) {
drect_border(x, y, x+w-1, y+h-1, C_WHITE, 1, C_BLACK);
return;
}
/* Try go guarantee at least 10 pixels per section */
int guaranteeable_min = 10 * (!!st.done + !!st.pending + !!st.empty);
bool guaranteed = (w > guaranteeable_min);
if(guaranteed) w -= guaranteeable_min;
px.done = (st.done * w) / main;
px.pending = (st.pending * w) / main;
px.empty = w - px.done - px.pending;
if(guaranteed) {
if(st.done) px.done += 10;
if(st.pending) px.pending += 10;
if(st.empty) px.empty += 10;
w += guaranteeable_min;
}
/* Width of bar for each of the subsections of done */
int assertions = st.passed + st.skipped + st.failed;
if(assertions == 0) assertions = 1;
guaranteeable_min = 10 * (!!st.passed + !!st.skipped + !!st.failed);
guaranteed = (px.done > guaranteeable_min);
if(guaranteed) px.done -= guaranteeable_min;
px.passed = (st.passed * px.done) / assertions;
px.skipped = (st.skipped * px.done) / assertions;
px.failed = px.done - px.passed - px.skipped;
if(guaranteed) {
if(st.passed) px.passed += 10;
if(st.skipped) px.skipped += 10;
if(st.failed) px.failed += 10;
px.done += guaranteeable_min;
}
/* Draw */
#define block(px, val, fg) if(px) { \
drect(rx, y, rx+px-1, y+h-1, fg); \
dprint_opt(rx+px/2, y+2, C_BLACK, C_NONE, DTEXT_CENTER, DTEXT_TOP, \
"%d", val); \
rx += px; \
}
int rx = x;
block(px.passed, st.passed, FT_TEST_PASSED);
block(px.skipped, st.skipped, FT_TEST_SKIPPED);
block(px.failed, st.failed, FT_TEST_FAILED);
block(px.pending, st.pending, FT_TEST_PENDING);
block(px.empty, st.empty, FT_TEST_EMPTY);
#undef block
/* Darken the border for a cool effect */
for(int dx = 0; dx < w; dx++) {
int i1 = 396 * (y) + (x + dx);
int i2 = 396 * (y + h - 1) + (x + dx);
gint_vram[i1] = (gint_vram[i1] & 0xf7de) >> 1;
gint_vram[i2] = (gint_vram[i2] & 0xf7de) >> 1;
}
for(int dy = 1; dy < h-1; dy++) {
int i1 = 396 * (y + dy) + (x);
int i2 = 396 * (y + dy) + (x + w - 1);
gint_vram[i1] = (gint_vram[i1] & 0xf7de) >> 1;
gint_vram[i2] = (gint_vram[i2] & 0xf7de) >> 1;
}
}
/* fbar type definition */
static jwidget_poly type_fbar = {
.name = "fbar",
.csize = fbar_poly_csize,
.render = fbar_poly_render,
};
/* Type registration */
__attribute__((constructor(2000)))
static void j_register_fbar(void)
{
fbar_type_id = j_register_widget(&type_fbar, "jwidget");
}