237 lines
6.0 KiB
C
237 lines
6.0 KiB
C
#include <ft/widgets/fbar.h>
|
|
#include <justui/jwidget-api.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.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, _(1,0), _(4,8), _(0,2), _(4,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 && !t->run) st->pending++;
|
|
else if(t->passed + t->skipped + t->failed) st->done++;
|
|
else st->empty++;
|
|
}
|
|
|
|
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 = _(75,120);
|
|
b->widget.h = _(5,13);
|
|
}
|
|
|
|
#ifdef FX9860G
|
|
static int block(int rx, int y, GUNUSED int h, int px, int val, int fg)
|
|
{
|
|
if(!px) return 0;
|
|
|
|
extern bopti_image_t img_status;
|
|
dsubimage(rx, y, &img_status, 6*(fg-1), 0, 5, 5, DIMAGE_NONE);
|
|
|
|
font_t const *old_font = dfont(&font_mini);
|
|
|
|
int w;
|
|
char str[16];
|
|
sprintf(str, "%d", val);
|
|
dsize(str, NULL, &w, NULL);
|
|
dtext(rx+6, y, C_BLACK, str);
|
|
dfont(old_font);
|
|
return w + 11;
|
|
}
|
|
#else
|
|
static int block(int rx, int y, int h, int px, int val, int fg)
|
|
{
|
|
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);
|
|
return px;
|
|
}
|
|
#endif
|
|
|
|
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 = (st.empty * w) / main;
|
|
int rest = w - px.done - px.pending - px.empty;
|
|
if(rest > 0) {
|
|
if(st.done) px.done += rest;
|
|
else if(st.pending) px.pending += rest;
|
|
else if(st.empty) px.empty += rest;
|
|
}
|
|
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;
|
|
|
|
/* Try to guarantee each section the size of its text, +2 pixels */
|
|
int min_passed=0, min_skipped=0, min_failed=0;
|
|
char str[10];
|
|
if(st.passed) {
|
|
sprintf(str, "%d", st.passed);
|
|
dsize(str, NULL, &min_passed, NULL);
|
|
min_passed += 2;
|
|
}
|
|
if(st.skipped) {
|
|
sprintf(str, "%d", st.skipped);
|
|
dsize(str, NULL, &min_skipped, NULL);
|
|
min_skipped += 2;
|
|
}
|
|
if(st.failed) {
|
|
sprintf(str, "%d", st.failed);
|
|
dsize(str, NULL, &min_failed, NULL);
|
|
min_failed += 2;
|
|
}
|
|
|
|
guaranteeable_min = min_passed + min_skipped + min_failed;
|
|
guaranteed = (px.done > guaranteeable_min);
|
|
|
|
if(guaranteed) px.done -= guaranteeable_min;
|
|
px.skipped = (st.skipped * px.done) / assertions;
|
|
px.failed = (st.failed * px.done) / assertions;
|
|
px.passed = px.done - px.skipped - px.failed;
|
|
if(guaranteed) {
|
|
px.passed += min_passed;
|
|
px.skipped += min_skipped;
|
|
px.failed += min_failed;
|
|
px.done += guaranteeable_min;
|
|
}
|
|
|
|
/* Draw */
|
|
int rx = x;
|
|
rx += block(rx, y, h, px.passed, st.passed, FT_TEST_PASSED);
|
|
rx += block(rx, y, h, px.skipped, st.skipped, FT_TEST_SKIPPED);
|
|
rx += block(rx, y, h, px.failed, st.failed, FT_TEST_FAILED);
|
|
rx += block(rx, y, h, px.pending, st.pending, FT_TEST_PENDING);
|
|
rx += block(rx, y, h, px.empty, st.empty, FT_TEST_EMPTY);
|
|
|
|
#ifdef FXCG50
|
|
/* 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;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/* 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");
|
|
}
|