Skip to content

Bug in Input cursor visibility with Renderer on nested containers #1220

@nmarks99

Description

@nmarks99

EDIT: I missed this PR: #1214 which I believe attempts to address this problem, or at least a similar problem

I have had an ongoing problem with the Input cursor being invisible when applying a Renderer to a container with nested sub containers. I believe this functionality should be supported and this is a bug. Initially I started this discussion about this problem: #1140. I now have a more concrete example.

Working

Here is an example that works without issue. Running this you will see the navigation works and the blinking cursor is shown properly in all four Input components.

int main() {
    auto screen = App::Fullscreen();

    std::string s1, s2, s3, s4;
    auto inp1 = Input(&s1, "one");
    auto inp2 = Input(&s2, "two");
    auto inp3 = Input(&s3, "three");
    auto inp4 = Input(&s4, "four");

    auto style = bgcolor(Color::White) | color(Color::Black);

    auto c1 = Container::Vertical({
        inp1,inp2,
    }) |  Renderer([&](Element){
        return vbox({
            inp1->Render() | style,
            separatorEmpty(),
            inp2->Render() | style
        }) | xflex;
    });

    auto c2 = Container::Vertical({
        inp3,inp4,
    }) | Renderer([&](Element){
        return vbox({
            inp3->Render() | style,
            separatorEmpty(),
            inp4->Render() | style
        }) | xflex;
    });

    auto container = Container::Horizontal({c1, c2});

    screen.Loop(container);

    return 0;
}

Broken

Here is another example which I find more readable, and I believe it should be supported in FTXUI, though it does not work correctly. In this example the cursor will not be shown at all for the second Container::Horizontal (inp3 and inp4). If there were more nested components in the container, the additional ones will also not show the input cursor. Only the first nested container will work correctly.

int main() {
    auto screen = App::Fullscreen();

    std::string s1, s2, s3, s4;
    auto inp1 = Input(&s1, "one");
    auto inp2 = Input(&s2, "two");
    auto inp3 = Input(&s3, "three");
    auto inp4 = Input(&s4, "four");

    auto style = bgcolor(Color::White) | color(Color::Black);

    auto container = Container::Horizontal({
        Container::Vertical({
            inp1,
            inp2
        }),
        Container::Vertical({
            inp3,
            inp4
        }),
    });

    auto renderer = Renderer(container, [&]{
        return hbox({
            vbox({
                inp1->Render() | style,
                separatorEmpty(),
                inp2->Render() | style
            }) | xflex,
            vbox({
                inp3->Render() | style,
                separatorEmpty(),
                inp4->Render() | style
            }) | xflex,
        });
    });

    screen.Loop(renderer);

    return 0;
}

Ideas

I have just started looking deeper into the source code to try and understand what is going on, but I don't quite understand yet how the active/focused logic works, but I think the issue is related to this and how it is handled with the Input component. Interestingly, (thanks to LLMs) I found that if I change Active() to Focused() on this line, it fixes the problem in the above example, though likely this breaks other things as is not a proper fix.

return std::make_shared<Wrapper>(std::move(element), Active());

Any suggestions would be appreciated and I would be happy to work on a fix for this, but will need some assistance to get started.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions