diff --git a/apps/dmview/src/main.c b/apps/dmview/src/main.c index c12c3d8..5cf0ee2 100644 --- a/apps/dmview/src/main.c +++ b/apps/dmview/src/main.c @@ -392,6 +392,7 @@ static void show_view(service_t* s, char* path) Dmod_Free(path); return; } + bool was_shown = s->view != NULL; libdmview_close(s->view); s->view = NULL; if (s->view_path != NULL) @@ -400,6 +401,8 @@ static void show_view(service_t* s, char* path) if (path == NULL) { DMOD_LOG_WARN("dmview: no view for %s (DMVIEW_VIEWS, DMVIEW_DEFAULT)\n", s->name); + if (!was_shown) + return; /* What the display shows - a splash screen - stays */ dmdrvi_gfx_fill_rect_t all = { 0, 0, s->info.width, s->info.height, 0xFF000000u }; (void)Dmod_Ioctl(s->gfx, DMDRVI_IOCTL_GFX_FILL_RECT, &all); present(s, NULL); diff --git a/src/exec.c b/src/exec.c index c94d04f..f692d6b 100644 --- a/src/exec.c +++ b/src/exec.c @@ -744,6 +744,28 @@ static void redraw(struct libdmview* v, int32_t target, const rect_t* area) run(v, b->begin * DMV_CODE_WORD, true); } +/* + * A box that changed but is not seen - a screen of a page behind the one + * shown, its opacity 0 - draws nothing, yet redrawing it redraws what is + * seen beneath it (a page's animations ran under the shown page all the + * time). Unseen: a box around it was not seen when last drawn (when that + * one's opacity changes, it is redrawn itself, with all inside it), or it + * was not seen itself and its OPACITY still makes it so. + */ +static bool stays_unseen(struct libdmview* v, const rbox_t* b) +{ + for (int32_t p = b->parent; p != ROOT; p = v->boxes[p].parent) + { + if (v->boxes[p].seen == 0) + return true; + } + if (b->seen != 0) + return false; + const uint8_t* insn = v->code + b->begin * DMV_CODE_WORD; + const uint8_t* next = insn + insn[1]; + return next[0] == DMV_OP_OPACITY && v16(v, next, 0, OPOFF(OPACITY, 0)) <= 0; +} + void exec_draw(struct libdmview* v, rect_t* changed) { rect_t screen = { 0, 0, v->surface_w, v->surface_h }; @@ -766,7 +788,7 @@ void exec_draw(struct libdmview* v, rect_t* changed) rbox_t* b = &v->boxes[i]; if ((b->flags & BOXF_DIRTY) == 0) continue; - if ((b->flags & BOXF_VISIBLE) == 0) + if ((b->flags & BOXF_VISIBLE) == 0 || stays_unseen(v, b)) { b->flags &= (uint8_t)~BOXF_DIRTY; continue; diff --git a/tests/fixtures/hidden.dmvs b/tests/fixtures/hidden.dmvs index 6b88859..b14b00e 100644 --- a/tests/fixtures/hidden.dmvs +++ b/tests/fixtures/hidden.dmvs @@ -1,12 +1,14 @@ ; Two screens one on another, as a page's views: the one below shown, with ; a button; the one on top hidden by its opacity ($top), with a box taking -; no contact over the button - and a button of its own elsewhere. +; no contact over the button - and a button of its own elsewhere. $tick +; changes what the hidden screen shows: a bar's width, a box's place. .view hidden .entry draw .var $top, int, 0 .var $below, int, 0 .var $above, int, 0 +.var $tick, int, 1 draw: FILL #000000 @@ -25,6 +27,12 @@ draw: ON CLICK, press_above FILL #00FF00 END + BOX @bar, 0, 28, 64, 4 + RECT 0, 0, $tick, 4, #FFFFFF + END + BOX @mover, $tick, 24, 4, 4 + FILL #FFFF00 + END END RET diff --git a/tests/libdmview_test.c b/tests/libdmview_test.c index b3722ba..e9500ea 100644 --- a/tests/libdmview_test.c +++ b/tests/libdmview_test.c @@ -742,6 +742,10 @@ DMOD_TEST_STEP(libdmview_hidden_boxes_take_no_contact) return; DMOD_TEST_EXPECT_EQ(libdmview_render(g_view, &g_s32, NULL), 1); + /* What the hidden screen shows changes: nothing is drawn */ + DMOD_TEST_EXPECT_EQ(libdmview_set_int(g_view, "tick", 9), 0); + DMOD_TEST_EXPECT_EQ(libdmview_render(g_view, &g_s32, NULL), 0); + /* The screen on top is not seen: the button beneath it is clicked */ touch(1, 15, 15, 10); touch(0, 0, 0, 20); @@ -755,6 +759,10 @@ DMOD_TEST_STEP(libdmview_hidden_boxes_take_no_contact) /* Shown: it covers the button, its own takes the contact */ DMOD_TEST_EXPECT_EQ(libdmview_set_int(g_view, "top", 255), 0); DMOD_TEST_EXPECT_EQ(libdmview_render(g_view, &g_s32, NULL), 1); + DMOD_TEST_EXPECT_EQ(px(1, 29), 0xFFFFFFFFu); /* The bar as $tick has it now */ + DMOD_TEST_EXPECT_EQ(px(9, 25), 0xFFFFFF00u); + DMOD_TEST_EXPECT_EQ(libdmview_set_int(g_view, "tick", 20), 0); + DMOD_TEST_EXPECT_EQ(libdmview_render(g_view, &g_s32, NULL), 1); /* Seen: drawn */ touch(1, 15, 15, 50); touch(0, 0, 0, 60); DMOD_TEST_EXPECT_EQ(libdmview_get_int(g_view, "below", &value), 0);