ArthurSonzogni / FTXUI

:computer: C++ Functional Terminal User Interface. :heart:
MIT License
6.73k stars 401 forks source link

How can I get frame to actual scroll the content? #125

Closed MichaelGoulding closed 2 years ago

MichaelGoulding commented 3 years ago

If you look at this sample, https://github.com/MichaelGoulding/vcpkg-ftxui-sample, if you enter enough text, the input box gets squashed and the content doesn't scroll.

What am I doing wrong?

Thanks!

ArthurSonzogni commented 3 years ago

Inside a frame, you need to specify which element has the focus, so that FTXUI knows which element it needs to focus one.

You can get: asciicast

if you replace:

g_cmdHistoryContainer->Render() | yframe | flex_grow,
vbox({
  g_cmdHistoryContainer->Render(),
  text(L"Focus") | focus,
}) | yframe | yflex,

I added an element text(L"Focus") at the bottom and used focus to bring focus to it.

matthesoundman commented 3 years ago

Inside a frame, you need to specify which element has the focus, so that FTXUI knows which element it needs to focus one.

You can get: asciicast

if you replace:

g_cmdHistoryContainer->Render() | yframe | flex_grow,
vbox({
  g_cmdHistoryContainer->Render(),
  text(L"Focus") | focus,
}) | yframe | yflex,

I added an element text(L"Focus") at the bottom and used focus to bring focus to it.

I am interested in understanding how to make a list of entries dynamically scroll. This suggestion does work, however I was not able to scroll back the history to see the commands that scroll out of focus. Any other suggestions here?

ArthurSonzogni commented 3 years ago

@matthesoundman, I replied in: https://github.com/ArthurSonzogni/FTXUI/issues/130

Basically, the solution I used above is only about drawing the element, not about they dynamic behavior and reaction with Events. So was purely implemented within ftxui::dom. To react to user's input, this would need to be implemented within ftxui::component.

MichaelGoulding commented 3 years ago

I ended up using this:


// A vertical component that places the focus always on the last child,
// allowing an outer frame to keep that child in view.
class KeepLastInFocusComponent : public ftxui::ComponentBase
{
public:
    void Clear()
    {
        children_.clear();
    }

    ftxui::Element Render() override
    {
        std::vector<ftxui::Element> elements;

        const size_t lastItem = (children_.size() - 1);
        for (size_t i = 0; i < children_.size(); ++i)
        {
            // Set focus on the last line so that the outer frame keeps it in view.
            if (lastItem != i)
            {
                elements.emplace_back(children_[i]->Render());
            }
            else
            {
                elements.emplace_back(children_[i]->Render() | ftxui::focus);
            }
        }

        return vbox(std::move(elements));
    }
};
MichaelGoulding commented 3 years ago

The ability to scroll up would be good, but I don't want any selection of the text, and I would want the focus to move down to the bottom if new text was added.

ArthurSonzogni commented 3 years ago

git-tui uses a Scroller component. I might one day make it built in into FTXUI: https://github.com/ArthurSonzogni/git-tui/blob/master/src/scroller.cpp Feel free to copy paste.

ArthurSonzogni commented 3 years ago

I ended up using this: [...]

Alternatively, your Component could have been a dom element, since it doesn't have to deal with user's input.

Elements AddFocusBottom(Elements list) {
  if (list.size() != 0)
    list.back() = focus(std::move(list.back());
  return std::move(list)
}

And then replace:

vbox(list)

by:

vbox(AddFocusBottom(list))
ArthurSonzogni commented 3 years ago

I can add some dom element that put the focus on one side of the component.

Decorator focusTop();
Decorator focusBottom();
Decorator focusLeft();
Decorator focusRight();

If you believe it could be useful.

ArthurSonzogni commented 2 years ago

This can be closed.

I added focusPositionRelative(x,y) to move the focus to one direction within the frame.

big_document() | focusPositionRelative(0, 1) | yframe