From 02fe82d903ec1ba04eac66e2a95704ee7727d1e5 Mon Sep 17 00:00:00 2001 From: Lephenixnoir Date: Sat, 4 Dec 2021 21:20:37 +0100 Subject: [PATCH] basic fx-9860G support and some filesystem tests (WIP) --- CMakeLists.txt | 8 ++++ assets-fx/fbar_main.png | Bin 0 -> 2290 bytes assets-fx/font_mini.png | Bin 0 -> 16103 bytes assets-fx/fxconv-metadata.txt | 12 +++++ assets-fx/icon.png | Bin 0 -> 8103 bytes assets-fx/status.png | Bin 0 -> 210 bytes assets-fx/status2.png | Bin 0 -> 196 bytes include/ft/all-tests.h | 7 +++ include/ft/test.h | 11 +++-- include/ft/util.h | 21 ++++++++ src/fcntl/open.c | 49 +++++++++++++++++++ src/main.c | 42 ++++++++++------ src/string/memarray.c | 9 ++++ src/unistd/files.c | 87 ++++++++++++++++++++++++++++++++++ src/widgets/fbar.c | 53 +++++++++++++++------ src/widgets/fbrowser.c | 57 ++++++++++++++++------ src/widgets/flist.c | 2 + src/widgets/flog.c | 20 +++++--- src/widgets/gscreen.c | 2 +- 19 files changed, 323 insertions(+), 57 deletions(-) create mode 100644 assets-fx/fbar_main.png create mode 100644 assets-fx/font_mini.png create mode 100644 assets-fx/fxconv-metadata.txt create mode 100644 assets-fx/icon.png create mode 100644 assets-fx/status.png create mode 100644 assets-fx/status2.png create mode 100644 src/fcntl/open.c create mode 100644 src/unistd/files.c diff --git a/CMakeLists.txt b/CMakeLists.txt index cfc2286..bfdd61b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,9 +48,17 @@ set(SOURCES src/string/memarray.c src/string/misc.c src/string/naive.c + # unistd + src/unistd/files.c + # fcntl + src/fcntl/open.c ) # fx-9860G-only assets and fx-CG-50-only assets set(ASSETS_fx + assets-fx/status.png + assets-fx/status2.png + assets-fx/font_mini.png + assets-fx/fbar_main.png ) set(ASSETS_cg ) diff --git a/assets-fx/fbar_main.png b/assets-fx/fbar_main.png new file mode 100644 index 0000000000000000000000000000000000000000..185aea057bac931bd5c4d452486f5310a78e6297 GIT binary patch literal 2290 zcmV zaB^>EX>4U6ba`-PAZ2)IW&i+q+O3yuk|Ze(ME`S&Jwkv0iQ|9(v%SF{f1e_&t9xeJ z#%w<_IyM$sXYJtAzc%$_H}4$}E`X7DTIW*UjeC8s!DY{UJmvcA$DhUJdE}Di zxw+<@XTJHopPro*YdJ;vEX9kwVyRP9jfcPn!&^vSiiO zR$sbojWr$lc=hJp)y;>`w9A%VciVmIwmtSd`5>iJPdokSu`|xRNbSn4x7~jA+8uX( zv-Yx@{=nH^nfrUz@)v6mmR`;(5B*?`VbvcYa@a`=&S0$64C5LMAm|dDJ(g=N!CVT? zo>8cZR>-miIXeeqFj!A6?dEUpelqtL-V$~H-||*|WiADE{}1L;Q1=_={>s~LSli+6 z9(DL&Y*B^*>LZljS@)FMZA|hv?&V@(b?i3xJv(=idpmJP?zh*ySI@O)p99u#t9+iV z%FGHF(8cdbdqXhEg9Lh8`Ho`>l*galt+vme zs}d6k)~qCX=rqUsI4E%OS*Y2l(0pOdtBNBNkn+5-}3jfyshYE-!Z~FR_N)B1*W=sv0dfl zf!Uxz9!IZawKveG+Qeu)-!($o=OlwykvWY@(FT1Kt{s&3FvSsO-qiEEAvj;!LW^(4Ru_eO z7YicEG!}{L@nJ-!q9N8dG@V1@V;rRzp3XM%tD$oy=AbL2KJg7>cs_*^uE8N=9(>M!&9&fB(s6 z`rPOXb&dwO@py@vk=C(?Iu=@yeQQ1y8z>kNdRh|zg`;r+_-cnhv?0Q3_~2)L_+a#p z^D={sSNP4x2?INo_zTAZQn41zgU*Ki(WCK+cJuW@2wfK|*+n0_Kp@u*Th@ zvC$<_F((`>wIs!9Pst%%TkGS1bXm$H?@sUch2bK8jGxkMTDhT>Bm4J90%kPWMP3P? zafmP~A)}=EMHSneVXkF;`dNs=l&U9g4Z>)+>W7~t_teL0PKS8IZ{;M|;(WsFjGN#d zApxEy6HEwwt{y3ck6c#93=WQ`9B}wS(RacDb#KR!4r^choBF0UN#iY7Lf8c|(C{F?#NWP)Jhjf zbYRsu{ZQxh9JMV-AMx)5=yODG{Dc9Z4iS>O2CZ?h8*ixo)gX76eFaHYR~kbD0H_^_ zZpaB#P{+U+2L2sx)><6-3MX*H0Xmpq^i_0}{tdD9K|V@+(%Jw3010qNS#tmY3ljhU z3ljkVnw%H_000McNliruQ*3A|Lb;5A*)d`mKKX?Xu#1FXK$$}BuDZ&tde zBchz5w^d_p$roZ5*Z{FOExvRsg+;!j$<2{}?#~)SPa*TX*yp9*r2qf` M07*qoM6N<$g7V*JjQ{`u literal 0 HcmV?d00001 diff --git a/assets-fx/font_mini.png b/assets-fx/font_mini.png new file mode 100644 index 0000000000000000000000000000000000000000..15b05ff3bc7941437686285db958bf28b87942e1 GIT binary patch literal 16103 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 t;eR#f!d=iqjWB-T#_|x#NgjGf`2xqlZOv#^ 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 BnPC6` literal 0 HcmV?d00001 diff --git a/assets-fx/status.png b/assets-fx/status.png new file mode 100644 index 0000000000000000000000000000000000000000..719b73facc645b1594e2323f97e83ad5fb96691c GIT binary patch literal 210 zcmeAS@N?(olHy`uVBq!ia0vp^vOvtr!2~4DN($BiDb50q$YKTtJ!KGPtXOJa1{7p3 z@$_|Nf66T`YN)$X$K@ALNV3E=qQp5rH#aq}gu%HeHL)Z$MWH;iBtya7(>EZzkxv|` z$j8&gF+}2WYk(skg8~QF|NrUM8w}I3^9< BKu7=p literal 0 HcmV?d00001 diff --git a/assets-fx/status2.png b/assets-fx/status2.png new file mode 100644 index 0000000000000000000000000000000000000000..6265244ccb5e97838749ebe98ca9724b562cb47a GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^vOvtr!2~4DN($BiDb50q$YKTtJ!KGPtXOJa1{7p3 z@$_|Nf66T`YG@wfx3>W(Bw6AbQR1ARo12#K^EHH+w4MmtPh@lNdZ*{an^LB{Ts5KX*Pf literal 0 HcmV?d00001 diff --git a/include/ft/all-tests.h b/include/ft/all-tests.h index 18c6fb4..2e8bf78 100644 --- a/include/ft/all-tests.h +++ b/include/ft/all-tests.h @@ -49,4 +49,11 @@ extern ft_test ft_string_strlen; extern ft_test ft_string_naive; extern ft_test ft_string_strerror; +/* unistd */ +extern ft_test ft_unistd_simple_write; +extern ft_test ft_unistd_write_odd; + +/* fcntl */ +extern ft_test ft_fcntl_open; + #endif /* _FT_ALL_TESTS_H_ */ diff --git a/include/ft/test.h b/include/ft/test.h index 1467bda..4338843 100644 --- a/include/ft/test.h +++ b/include/ft/test.h @@ -7,6 +7,7 @@ #include #include +#include //--- // Test framework @@ -91,11 +92,11 @@ void ft_list_aggregate(ft_list *l); //--- /* Colors for each test category */ -#define FT_TEST_EMPTY C_RGB(20,20,20) -#define FT_TEST_PASSED C_RGB(6,25,8) -#define FT_TEST_SKIPPED C_RGB(31,20,9) -#define FT_TEST_PENDING C_RGB(15,23,27) -#define FT_TEST_FAILED C_RGB(31,10,7) +#define FT_TEST_EMPTY _(1, C_RGB(20,20,20)) +#define FT_TEST_PASSED _(2, C_RGB(6,25,8)) +#define FT_TEST_SKIPPED _(3, C_RGB(31,20,9)) +#define FT_TEST_PENDING _(4, C_RGB(15,23,27)) +#define FT_TEST_FAILED _(5, C_RGB(31,10,7)) /* ft_test_color(): Color for the summary of a test */ int ft_test_color(ft_test const *t); diff --git a/include/ft/util.h b/include/ft/util.h index 9422eb3..e88cfe0 100644 --- a/include/ft/util.h +++ b/include/ft/util.h @@ -5,12 +5,33 @@ #ifndef _FT_UTIL_H_ #define _FT_UTIL_H_ +#include +#include + #ifdef FX9860G #define _(fx,cg) (fx) +extern font_t font_mini; +extern bopti_image_t img_fbar_main; #endif #ifdef FXCG50 #define _(fx, cg) (cg) #endif +/* Macro to make a call, get the return value, and log it immediately. This + does *not* work well under context, keep calls simple. */ +#define DO(var, expr, t, fmt) { \ + var = expr; \ + ft_log(t, #expr " = " fmt "\n", var); \ +} +/* Macro to print errno when non-zero */ +#define SHOW_ERRNO(t) \ + if(errno != 0) ft_log(t, "errno %d: %s\n", errno, strerror(errno)) +/* Combination */ +#define DO_E(var, expr, t, fmt) { \ + var = expr; \ + ft_log(t, #expr " = " fmt "\n", var); \ + SHOW_ERRNO(t); \ +} + #endif /* _FT_UTIL_H_ */ diff --git a/src/fcntl/open.c b/src/fcntl/open.c new file mode 100644 index 0000000..dd955e9 --- /dev/null +++ b/src/fcntl/open.c @@ -0,0 +1,49 @@ +#include +#include +#include + +#include +#include +#include +#include + +static void _ft_fcntl_open_switch(ft_test *t) +{ + char const *filename = "ft_open.txt"; + int fd, rc; + errno = 0; + + fd = open(filename, O_RDONLY); + ft_log(t, "open(\"%s\", O_RDONLY) = %d\n", filename, fd); + if(fd == -1) + ft_log(t, "errno %d: %s\n", errno, strerror(errno)); + ft_assert(t, fd == -1 && errno == ENOENT); + if(fd != -1) + close(fd); + + fd = open(filename, O_RDWR | O_CREAT); + ft_log(t, "open(\"%s\", O_RDWR | O_CREAT) = %d\n", filename, fd); + if(fd == -1) + ft_log(t, "errno %d: %s\n", errno, strerror(errno)); + ft_assert(t, fd >= 0); + if(fd != -1) + close(fd); + + rc = unlink(filename); + ft_log(t, "unlink(\"%s\") = %d\n", filename, rc); + if(rc == -1) + ft_log(t, "errno %d: %s\n", errno, strerror(errno)); + ft_assert(t, rc == 0); +} + +static void _ft_fcntl_open(ft_test *t) +{ + gint_world_switch(GINT_CALL(_ft_fcntl_open_switch, (void *)t)); +} + +ft_test ft_fcntl_open = { + .name = "Opening files", + .function = _ft_fcntl_open, +}; + +// TODO: Truncation diff --git a/src/main.c b/src/main.c index cce8e57..10b2e79 100644 --- a/src/main.c +++ b/src/main.c @@ -18,34 +18,34 @@ #pragma GCC diagnostic ignored "-Wmissing-field-initializers" ft_list headers_libc[] = { - { "", (ft_test*[]){ + { _("ctype.h", ""), (ft_test*[]){ &ft_ctype_classes, &ft_ctype_conversion, NULL, }}, - { "", (ft_test*[]){ + { _("inttypes.h", ""), (ft_test*[]){ &ft_inttypes_sizes, &ft_inttypes_functions, NULL, }}, - { "", NULL }, - { "", (ft_test*[]){ + { _("locale.h", ""), NULL }, + { _("setjmp.h", ""), (ft_test*[]){ &ft_setjmp_simple, &ft_setjmp_massive, &ft_setjmp_interrupt, NULL, }}, - { "", (ft_test*[]){ + { _("signal.h", ""), (ft_test*[]){ &ft_signal_signal, NULL, }}, - { "", (ft_test*[]){ + { _("stdio.h", ""), (ft_test*[]){ &ft_stdio_printf_basics, &ft_stdio_printf_formats, &ft_stdio_printf_fp, NULL, }}, - { "", (ft_test*[]){ + { _("stdlib.h", ""), (ft_test*[]){ &ft_stdlib_arith, &ft_stdlib_sizes, &ft_stdlib_llconv, @@ -57,7 +57,7 @@ ft_list headers_libc[] = { &ft_stdlib_abort, NULL, }}, - { "", (ft_test*[]){ + { _("string.h", ""), (ft_test*[]){ &ft_string_memset, &ft_string_memcpy, &ft_string_memmove, @@ -68,14 +68,22 @@ ft_list headers_libc[] = { &ft_string_strerror, NULL, }}, - { "", NULL }, - { "", NULL }, - { "", NULL }, - { "", NULL }, + { _("time.h", ""), NULL }, + { _("uchar.h", ""), NULL }, + { _("wchar.h", ""), NULL }, + { _("wctype.h", ""), NULL }, { NULL } }; ft_list headers_posix[] = { - { "", NULL }, + { "", (ft_test*[]){ + &ft_fcntl_open, + NULL, + }}, + { "", (ft_test*[]){ + &ft_unistd_simple_write, + &ft_unistd_write_odd, + NULL, + }}, { NULL } }; @@ -98,22 +106,26 @@ int main(void) ft_list_init(&headers_posix[i]); // Create GUI - gscreen *scr = gscreen_create2("FxLibc tests", NULL, + gscreen *scr = gscreen_create2("FxLibc tests", &img_fbar_main, "FxLibc regression and performance tests", "/LIBC;/POSIX;;;;#RUN"); fbrowser *browser = fbrowser_create(NULL); int selected_set = 0; gscreen_add_tab(scr, browser, NULL); + gscreen_set_tab_title_visible(scr, 0, _(false, true)); fbrowser_set_headers(browser, headers_libc, false); jwidget *results = jwidget_create(NULL); jlayout_set_stack(results); gscreen_add_tab(scr, results, NULL); + gscreen_set_tab_title_visible(scr, 1, _(false, true)); gscreen_set_tab_fkeys_visible(scr, 1, false); flog *testlog = flog_create(NULL); - flog_set_line_spacing(testlog, 3); + flog_set_line_spacing(testlog, _(1,3)); + flog_set_font(testlog, _(&font_mini, dfont_default())); gscreen_add_tab(scr, testlog, testlog); + gscreen_set_tab_title_visible(scr, 2, _(false, true)); gscreen_set_tab_fkeys_visible(scr, 2, false); // Event handling diff --git a/src/string/memarray.c b/src/string/memarray.c index b8911e2..35e2ccc 100644 --- a/src/string/memarray.c +++ b/src/string/memarray.c @@ -186,8 +186,17 @@ static void paint_results(int x, int y, uint8_t *rc) int value = -1; if(row < 4*sizes) value = memarray_get(rc, 4*sizes * col + row); + +#ifdef FX9860G + if(value >= 0) { + for(int y = y1; y <= y1+10; y++) + for(int x = x1; x <= x1+19; x++) + dpixel(x, y, (x&1)^(y&1) ? C_BLACK : (value != 0)); + } +#else int fg = (value == -1) ? C_WHITE : (value == 0) ? C_GREEN : C_RED; drect_border(x1, y1, x1+19, y1+10, fg, 1, C_BLACK); +#endif } } diff --git a/src/unistd/files.c b/src/unistd/files.c new file mode 100644 index 0000000..2341c6f --- /dev/null +++ b/src/unistd/files.c @@ -0,0 +1,87 @@ +#include +#include +#include + +#include +#include +#include + +#include +#include + +static void _ft_unistd_simple_write_switch(ft_test *t) +{ + int fd, rc; + errno = 0; + + DO_E(fd, open("ft_write.txt", O_WRONLY | O_CREAT), t, "%d"); + ft_assert(t, fd >= 0); + + if(fd >= 0) { + DO_E(rc, write(fd, "write\n", 6), t, "%d"); + ft_assert(t, rc == 6); + DO_E(rc, write(fd, "line #2\n", 8), t, "%d"); + ft_assert(t, rc == 8); + DO_E(rc, write(fd, "line #3\n", 8), t, "%d"); + ft_assert(t, rc == 8); + } + + close(fd); +} + +static void _ft_unistd_simple_write(ft_test *t) +{ + gint_world_switch(GINT_CALL(_ft_unistd_simple_write_switch,(void *)t)); +} + +ft_test ft_unistd_simple_write = { + .name = "Write simple file", + .function = _ft_unistd_simple_write, +}; + +static void _ft_unistd_write_odd_switch_1(ft_test *t) +{ + int fd, rc; + errno = 0; + + DO_E(fd, open("ft_odd1.txt", O_WRONLY | O_CREAT), t, "%d"); + ft_assert(t, fd >= 0); + + if(fd >= 0) { + DO_E(rc, write(fd, "write odd byte count\n", 21), t, "%d"); + ft_assert(t, rc == 21); + DO_E(rc, write(fd, "again, cancelling it\n", 21), t, "%d"); + ft_assert(t, rc == 21); + } + + close(fd); +} + +static void _ft_unistd_write_odd_switch_2(ft_test *t) +{ + int fd, rc; + errno = 0; + + DO_E(fd, open("ft_odd2.txt", O_WRONLY | O_CREAT), t, "%d"); + ft_assert(t, fd >= 0); + + if(fd >= 0) { + DO_E(rc, write(fd, "write odd byte count\n", 21), t, "%d"); + ft_assert(t, rc == 21); + DO_E(rc, write(fd, "then even, keeping it\n", 22), t, "%d"); + ft_assert(t, rc == 22); + } + + close(fd); +} + +static void _ft_unistd_write_odd(ft_test *t) +{ + gint_world_switch(GINT_CALL(_ft_unistd_write_odd_switch_1, (void *)t)); + gint_world_switch(GINT_CALL(_ft_unistd_write_odd_switch_2, (void *)t)); +} + +ft_test ft_unistd_write_odd = { + .name = "Odd-length writes", + .function = _ft_unistd_write_odd, +}; diff --git a/src/widgets/fbar.c b/src/widgets/fbar.c index 7ab2d6c..bb83da5 100644 --- a/src/widgets/fbar.c +++ b/src/widgets/fbar.c @@ -18,7 +18,7 @@ fbar *fbar_create(void *parent) b->tests = NULL; b->lists = NULL; - jwidget_set_margin(b, 0, 8, 2, 8); + jwidget_set_margin(b, _(1,0), _(4,8), _(0,2), _(4,8)); return b; } @@ -82,10 +82,38 @@ static void stats_add_list(struct stats *st, ft_list *l) static void fbar_poly_csize(void *b0) { fbar *b = b0; - b->widget.w = 120; - b->widget.h = 13; + 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; @@ -169,20 +197,14 @@ static void fbar_poly_render(void *b0, int x, int y) } /* 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 + 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); @@ -196,6 +218,7 @@ static void fbar_poly_render(void *b0, int x, int y) gint_vram[i1] = (gint_vram[i1] & 0xf7de) >> 1; gint_vram[i2] = (gint_vram[i2] & 0xf7de) >> 1; } +#endif } /* fbar type definition */ diff --git a/src/widgets/fbrowser.c b/src/widgets/fbrowser.c index 3b25224..89e2e08 100644 --- a/src/widgets/fbrowser.c +++ b/src/widgets/fbrowser.c @@ -27,15 +27,15 @@ fbrowser *fbrowser_create(void *parent) b->data_tests = NULL; jwidget_init(&b->widget, fbrowser_type_id, parent); - jlayout_set_hbox(b)->spacing = 4; + jlayout_set_hbox(b)->spacing = _(0,4); // On the left, list of headers b->headers = flist_create(GINT_CALL_NULL, b); flist_set_rows(b->headers, 1); flist_select(b->headers, 0); - flist_set_row_height(b->headers, 13); - jwidget_set_fixed_width(b->headers, 120); + flist_set_row_height(b->headers, _(7,13)); + jwidget_set_fixed_width(b->headers, _(39,120)); jwidget_set_stretch(b->headers, 0, 1, false); // On the right, either a summary of the whole application... @@ -52,6 +52,13 @@ fbrowser *fbrowser_create(void *parent) jwidget_set_stretch(b->bar_top, 1, 0, false); l = jlabel_create( +#ifdef FX9860G + "fxlibc unit tests!\n" + "Run with F6:\n" + "- Here: all\n" + "- On header\n" + "- On single test", +#else "Summary here!\n\n" "Green: Passed\n" "Orange: Skipped\n" @@ -62,29 +69,34 @@ fbrowser *fbrowser_create(void *parent) "- Here: runs all tests\n" "- On a header: all tests in header\n" "- On a test: just that test", +#endif summary); jlabel_set_block_alignment(l, J_ALIGN_LEFT, J_ALIGN_TOP); - jlabel_set_line_spacing(l, 3); + jlabel_set_line_spacing(l, _(1,3)); + jlabel_set_font(l, _(&font_mini, dfont_default())); jwidget_set_stretch(l, 1, 1, false); + jwidget_set_margin(l, 0, 0, 0, _(1,0)); // ... or a label for headers with no tests yet... - l = jlabel_create("No test for this header.", b->rstack); + l = jlabel_create(_("No test", "No test for this header."), b->rstack); jlabel_set_block_alignment(l, J_ALIGN_LEFT, J_ALIGN_TOP); + jlabel_set_font(l, _(&font_mini, dfont_default())); jwidget_set_margin(l, 2, 0, 0, 0); jwidget_set_stretch(l, 1, 1, false); + jwidget_set_margin(l, 0, 0, 0, _(1,0)); // Or a header summary and a test list for the selected header jwidget *rvbox = jwidget_create(b->rstack); jwidget_set_stretch(rvbox, 1, 1, false); - jlayout_set_vbox(rvbox)->spacing = 4; + jlayout_set_vbox(rvbox)->spacing = _(1,4); b->bar_right = fbar_create(rvbox); jwidget_set_stretch(b->bar_right, 1, 0, false); b->tests = flist_create(GINT_CALL_NULL, rvbox); - flist_set_row_height(b->tests, 13); + flist_set_row_height(b->tests, _(7,13)); jwidget_set_stretch(b->tests, 1, 1, false); return b; @@ -150,9 +162,11 @@ static void render_entries(flist *l, void *data, int is_headers) int w = jwidget_content_width(l); int h = l->row_height; +#ifdef FXCG50 if(selected && !focused) { drect(l->x, l->y, l->x + w - 1, l->y + h - 1, C_RGB(24, 24, 24)); } +#endif char const *name = "(null)"; int color = C_BLACK; @@ -170,22 +184,35 @@ static void render_entries(flist *l, void *data, int is_headers) name = test->name; } + font_t const *old_font = dfont(_(&font_mini, dfont_default())); + if(is_headers && l->row == 0) - dtext(l->x + 2, l->y + 2, C_BLACK, "Summary"); + dtext(l->x+_(1,2), l->y+_(1,2), C_BLACK, "Summary"); + else if(is_headers) + dprint(l->x+_(1,16), l->y+_(1,2), C_BLACK, "%s", name); else - dprint(l->x + 16, l->y + 2, C_BLACK, "%s", name); + dprint(l->x+_(7,16), l->y+_(1,2), C_BLACK, "%s", name); if(selected && focused) { drect(l->x, l->y, l->x + w - 1, l->y + h - 1, C_INVERT); } - if(is_headers && l->row == 0) return; - for(int y = 0; y < 9; y++) - for(int x = 0; x < 9; x++) - { - if((x == 0 || x == 8) && (y == 0 || y == 8)) continue; - dpixel(l->x + 3 + x, l->y + 2 + y, color); + if(!is_headers || l->row != 0) { +#ifdef FX9860G + extern bopti_image_t img_status, img_status2; + bopti_image_t *i = (selected && focused) ? &img_status2 : &img_status; + if(!is_headers) + dsubimage(l->x+1, l->y+1, i, 6*(color-1), 0, 5, 5, DIMAGE_NONE); +#else + for(int y = 0; y < 9; y++) + for(int x = 0; x < 9; x++) { + if((x == 0 || x == 8) && (y == 0 || y == 8)) continue; + dpixel(l->x + 3 + x, l->y + 2 + y, color); + } +#endif } + + dfont(old_font); } //--- diff --git a/src/widgets/flist.c b/src/widgets/flist.c index 4bae050..acb1c20 100644 --- a/src/widgets/flist.c +++ b/src/widgets/flist.c @@ -147,8 +147,10 @@ static void flist_poly_render(void *l0, int x, int base_y) int bar_y = (l->top * area_h + l->rows/2) / l->rows; int bar_h = (l->visible * area_h + l->rows/2) / l->rows; +#ifdef FXCG50 drect(area_x, area_y, area_x+area_w-1, area_y+area_h-1, C_RGB(24,24,24)); +#endif drect(area_x, area_y + bar_y, area_x + area_w - 1, area_y + bar_y + bar_h, C_BLACK); } diff --git a/src/widgets/flog.c b/src/widgets/flog.c index a29d19f..c8c3427 100644 --- a/src/widgets/flog.c +++ b/src/widgets/flog.c @@ -73,7 +73,7 @@ static void flog_poly_layout(void *l0) l->visible = total_height / (l->font->line_height + l->line_spacing); /* Compute number of lines. Keep 3 pixels of room for the scrollbar */ - int const w = max(0, jwidget_content_width(l) - 33); + int const w = max(0, jwidget_content_width(l) - _(3,33)); char const *log = l->log; l->lines = 0; @@ -83,7 +83,7 @@ static void flog_poly_layout(void *l0) l->lines++; } else { - char const *endscreen = drsize(log, NULL, w, NULL); + char const *endscreen = drsize(log, l->font, w, NULL); char const *endline = strchrnul(log, '\n'); int len = max(1, min(endscreen-log, endline-log)); log += len + (log[len] == '\n'); @@ -100,38 +100,42 @@ static void flog_poly_render(void *l0, int x, int y) int const w = jwidget_content_width(l); int const h = jwidget_content_height(l); char const *log = l->log; + font_t const *old_font = dfont(l->font); /* current_y is ignored until current_line >= top, at which point it starts at y and increases each line */ int current_line = 0; int current_y = y; - while(log < l->log + l->log_size) { +#ifdef FXCG50 if(current_line >= l->top && current_line < l->top + l->visible) dprint_opt(x+22, current_y, C_BLACK, C_NONE, DTEXT_RIGHT, DTEXT_TOP, "%d", current_line+1); +#endif if(log[0] == '\n') { log++; } else { - char const *endscreen = drsize(log, NULL, w - 33, NULL); + char const *endscreen = drsize(log, NULL, w - _(3,33), NULL); char const *endline = strchrnul(log, '\n'); int len = max(1, min(endscreen-log, endline-log)); if(current_line >= l->top && current_line < l->top + l->visible) - dtext_opt(x+30, current_y, C_BLACK, C_NONE, DTEXT_LEFT, + dtext_opt(x+_(0,30), current_y, C_BLACK, C_NONE, DTEXT_LEFT, DTEXT_TOP, log, len); log += len + (log[len] == '\n'); } if(current_line >= l->top && current_line < l->top + l->visible) { +#ifdef FXCG50 int previous_y = current_y; - current_y += l->font->line_height + l->line_spacing; dline(x+26, previous_y, x+26, current_y-1, C_BLACK); +#endif + current_y += l->font->line_height + l->line_spacing; } current_line++; } @@ -147,11 +151,15 @@ static void flog_poly_render(void *l0, int x, int y) int bar_y = (l->top * area_h) / current_line; int bar_h = (l->visible * area_h) / current_line; +#ifdef FXCG50 drect(area_x, area_y, area_x+area_w-1, area_y+area_h-1, C_RGB(24,24,24)); +#endif drect(area_x, area_y + bar_y, area_x + area_w - 1, area_y + bar_y + bar_h, C_BLACK); } + + dfont(old_font); } static bool flog_poly_event(void *l0, jevent e) diff --git a/src/widgets/gscreen.c b/src/widgets/gscreen.c index 887fd91..4c84f30 100644 --- a/src/widgets/gscreen.c +++ b/src/widgets/gscreen.c @@ -43,7 +43,7 @@ gscreen *gscreen_create(char const *name, char const *labels) if(title) { jwidget_set_background(title, C_BLACK); jlabel_set_text_color(title, C_WHITE); - jlabel_set_font(title, _(&font_title, dfont_default())); + jlabel_set_font(title, dfont_default()); jwidget_set_stretch(title, 1, 0, false); #ifdef FX9860G