Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Last scroll position of the vertical/horizontal container being reset when it's out of focus. #935

Open
s0nx opened this issue Oct 7, 2024 · 2 comments
Assignees
Labels
bug Something isn't working

Comments

@s0nx
Copy link
Contributor

s0nx commented Oct 7, 2024

Let's say we have a vertical split and both top and bottom components are of Container::Vertical type.
If we added some child components which are Container::Vertical / Container::Horizontal themselves to the top or bottom parent components, the current scroll position resets to 0 when the parent component is not focused.

Here is the simple reproducer:

#include <random>
#include <algorithm>

#include <ftxui/dom/elements.hpp>
#include <ftxui/screen/screen.hpp>

#include <ftxui/component/component.hpp>
#include <ftxui/component/component_base.hpp>
#include <ftxui/component/event.hpp>
#include <ftxui/component/mouse.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <ftxui/dom/canvas.hpp>
#include <ftxui/screen/color.hpp>
#include <string>

using namespace ftxui;

int main()
{
    int size = 40;
    int size2 = 40;

    auto top_comp    = Container::Vertical({});
    auto bottom_comp = Container::Vertical({});
    bottom_comp->Add(Button("exit", []{}));

    for (int i = 0; i < 30; i++)
    {
        if (i % 2 == 0)
        {
            top_comp->Add(Button("Button #" + std::to_string(i), []{}));
        }
        else
        {
            auto hor_button_comp = Container::Horizontal({
                Button("Button #" + std::to_string(i), []{}),
                Button("nottuB #" + std::to_string(i * 2), []{}),
            });
            top_comp->Add(hor_button_comp);
        }
    }

    auto rendered_top_comp = Renderer(top_comp, [&] {
        return top_comp->Render() | vscroll_indicator | hscroll_indicator | frame;
    });

    auto vert_split_comp = ResizableSplitTop(rendered_top_comp, bottom_comp, &size2);

    auto right_comp = Container::Horizontal({});
    right_comp->Add(Button("right split button 1", []{}));
    right_comp->Add(Button("right split button 2", []{}));

    auto hor_split_comp = ResizableSplitRight(right_comp, vert_split_comp, &size);

    auto screen = ftxui::ScreenInteractive::Fullscreen();
    screen.Loop(hor_split_comp);
}

That's not happening when child component is not a container itself (Button for example).
I've tried to capture the problem:
ftxui-embed-container-scroll-issue

When i move the focus from Nottub #30 button to right split button, the vertical scroller moves all the way to the top. That's not happening if top_comp consists of Button components only. The scroller stays in place.

@ArthurSonzogni
Copy link
Owner

ArthurSonzogni commented Oct 8, 2024

Thanks for the reproducer!

I believe the problem is that ftxui/dom was made without knowing ftxui/component will be something.

The hbox selection is computed by:

  void ComputeRequirement() override {
    requirement_.min_x = 0;
    requirement_.min_y = 0;
    requirement_.flex_grow_x = 0;
    requirement_.flex_grow_y = 0;
    requirement_.flex_shrink_x = 0;
    requirement_.flex_shrink_y = 0;
    requirement_.selection = Requirement::NORMAL;
    for (auto& child : children_) {
      child->ComputeRequirement();
      if (requirement_.selection < child->requirement().selection) {
        requirement_.selection = child->requirement().selection;
        requirement_.selected_box = child->requirement().selected_box;
        requirement_.selected_box.x_min += requirement_.min_x;
        requirement_.selected_box.x_max += requirement_.min_x;
      }
      requirement_.min_x += child->requirement().min_x;
      requirement_.min_y =
          std::max(requirement_.min_y, child->requirement().min_y);
    }
  }

So, we are keeping the selection of the child with the largest priority among focused and selected.

In your case, none of the button are focused, but they are all selected. So, the frame is focusing the first one.

The Container::Horizontal doesn't really specify which of the children must be prioritized.

@ArthurSonzogni ArthurSonzogni self-assigned this Oct 8, 2024
@ArthurSonzogni ArthurSonzogni added the bug Something isn't working label Oct 8, 2024
@ArthurSonzogni
Copy link
Owner

I will be very busy this month. If you have some propositions or want to submit a PR, we can discuss them if you are interested.

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants