dankamongmen / notcurses

blingful character graphics/TUI library. definitely not curses.
https://nick-black.com/dankwiki/index.php/Notcurses
Other
3.4k stars 113 forks source link

How to hide an ncvisual object #2776

Open lokxii opened 2 months ago

lokxii commented 2 months ago

ncplanes can be hidden by rendering off screen. But when you blit an ncvisual object to an ncplane, and move the ncplane off screen, the ncvisual object stays on the screen. Is there anyway to properly hide an ncvisual object

lokxii commented 2 months ago

And I observe that calling notcurses_refresh() after notcurses_render() causes the ncvisual object to disappear

lokxii commented 2 months ago

I think I can just detect and destroy out of bounds ncplanes. But this seems inefficient

dankamongmen commented 2 months ago

you can just hide the plane on which the ncvisual has been blitted, unless i'm misunderstanding you?

dankamongmen commented 2 months ago

an ncvisual is not a drawn object. it's just memory holding an image.

until you blit it, it's not visible. after you blit it, the ncvisual itself has nothing to do with what is seen. you can freely change it if you want; what's visible remains the same unless you reblit it.

so to hide what's been drawn, you hide the ncplane. to destroy what's been drawn, you destroy the ncplane. etc.

dankamongmen commented 2 months ago

and know you can freely reblit the ncvisual onto the plane (if it's transparent, you'll want to clear the plane first). like to play multiple frames of an animation, it's:

blit render clear plane blit next frame render clear plane blit next frame render

let me know if this isn't clear!

lokxii commented 2 months ago

I forgot to mention that I blited ncvisual to a child plane (using NCVISUAL_OPTION_CHILDPLANE and setting .n = parent_plane), and then I moved the parent plane. The ncvisual stays on screen even when the parent plane is moved off screen completely

lokxii commented 2 months ago

i also tried to call ncplane_erase() and then reblit the ncvisual on an off screen plane, the image stays on screen.

dankamongmen commented 2 months ago

I forgot to mention that I blited ncvisual to a child plane (using NCVISUAL_OPTION_CHILDPLANE and setting .n = parent_plane), and then I moved the parent plane. The ncvisual stays on screen even when the parent plane is moved off screen completely

hrmmmm, that seems like an error. if you can put together a minimum example, i'll look into it.

this is strange. does e.g. ncplayer work like you'd expect on your setup?

lokxii commented 2 months ago
int main() {
    const char* path = "some_picture.png";
    setlocale(LC_ALL, "");
    notcurses* nc = NULL;
    notcurses_options opt = {
        .loglevel = NCLOGLEVEL_INFO,
        .flags = NCOPTION_NO_QUIT_SIGHANDLERS | NCOPTION_SUPPRESS_BANNERS
    };
    if ((nc = notcurses_init(&opt, NULL)) == NULL) {
        exit(EXIT_FAILURE);
    }

    ncplane* stdplane = notcurses_stdplane(nc);

    ncplane_options plane_opt = {
        .y = 0, .x = 0,
        .rows = 2, .cols = 4,
    };
    ncplane* plane = ncplane_create(stdplane, &plane_opt);

    ncvisual* ncv = ncvisual_from_file(path);
    if (!ncv) {
        exit(EXIT_FAILURE);
    }

    ncvisual_options vopts = {
        .n = plane,
        .blitter = NCBLIT_PIXEL,
        // .flags = NCVISUAL_OPTION_CHILDPLANE,
    };

    ncvgeom geom;
    ncvisual_geom(nc, ncv, &vopts, &geom);
    ncvisual_resize(ncv, 2 * 2 * geom.cdimx, 4 * geom.cdimx);

    ncvisual_blit(nc, ncv, &vopts);

    auto in_range = [=](int y, int x) {
        unsigned int h, w;
        notcurses_stddim_yx(nc, &h, &w);
        return y >= 0 && y <= h && x >= 0 && x <= w;
    };

    ncinput ni;
    bool flag = true;
    while (flag) {
        notcurses_render(nc);
        if (notcurses_get_blocking(nc, &ni) == -1) {
            continue;
        }
        if (ni.evtype != NCTYPE_PRESS) {
            continue;
        }
        switch (ni.id) {
            case 'q': flag = false; break;
            case 'j': ncplane_move_rel(plane, 5, 0); break;
            case 'k': ncplane_move_rel(plane, -5, 0); break;
            case 'l': ncplane_move_rel(plane, 0, 10); break;
            case 'h': ncplane_move_rel(plane, 0, -10); break;
        }
        ncplane_erase(plane);
        ncvisual_blit(nc, ncv, &vopts);
    }

    notcurses_stop(nc);
}

It's the same if I blit on a child plane or blit on the parent plane.

lokxii commented 2 months ago

My solution now is to check if the child plane with ncvisual is off screen, destroy or recreate the plane accordingly. But this adds significant complexity to my project that will handle a lot of images.

dankamongmen commented 2 months ago

yeah that shouldn't be necessary. btw what terminal are you running in? it'll be important to know whether you're using the sixel protocol or kitty. the code here is kinda fragile and you may well be hitting a bug.

lokxii commented 2 months ago

kitty