Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

How to scroll elements , not components #907

Open
Deshdeepak1 opened this issue Jul 29, 2024 · 2 comments
Open

How to scroll elements , not components #907

Deshdeepak1 opened this issue Jul 29, 2024 · 2 comments

Comments

@Deshdeepak1
Copy link

If I have Components like menu, radiobox, etc in container, it is scrollable. But elements don't seem to be scrollable.

#include <ftxui/component/component.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <ftxui/dom/elements.hpp>
#include <ftxui/screen/screen.hpp>
#include <iostream>

ftxui::Element get_document() {
  using namespace ftxui;
  auto cell = [](const char* t) { return text(t) | border; };
  auto document =  //
      gridbox({
          {
              cell("north-west"),
              cell("north"),
              cell("north-east"),
          },
          {
              cell("center-west"),
              gridbox({
                  {
                      cell("center-north-west"),
                      cell("center-north-east"),
                  },
                  {
                      cell("center-south-west"),
                      cell("center-south-east"),
                  },
              }),
              cell("center-east"),
          },
          {
              cell("south-west"),
              cell("south"),
              cell("south-east"),
          },
      });
  return document;
}

int main() {
  using namespace ftxui;
  auto cell = [](const char* t) { return text(t) | border; };

  int n;
  std::cin >> n;

  if (n == 1) {
    Element document = get_document();
    auto component =
        Renderer([document] { return document | vscroll_indicator | frame; });
    auto screen = ScreenInteractive::FullscreenAlternateScreen();
    screen.Loop(component);
  } else {
    Elements documents;
    for (int i = 0; i < 10; i++) {
      auto document = get_document();
      document |= border;
      documents.push_back(document);
    }
    auto component = Renderer(
        [documents] { return vbox(documents) | vscroll_indicator | frame; });
    auto screen = ScreenInteractive::FullscreenAlternateScreen();
    screen.Loop(component);
  }

  return 0;
}

neither the gridbox seems to scroll, nor the vbox containing multiple gridbox

@ArthurSonzogni
Copy link
Owner

Hello,

You have to use the selected/focus decorator to put the focus on the selected or focused element. Then, the frame will automatically center its view toward this element.

See:

// --- Frame ---
// A frame is a scrollable area. The internal area is potentially larger than
// the external one. The internal area is scrolled in order to make visible the
// focused element.
Element frame(Element);
Element xframe(Element);
Element yframe(Element);
Element focus(Element);
Element select(Element);

See also the radiobox implementation.

--

Alternatively, you might want to look at:

@Deshdeepak1
Copy link
Author

Deshdeepak1 commented Jul 30, 2024

Thanks,

#include <ftxui/component/component.hpp>
#include <ftxui/component/screen_interactive.hpp>
#include <ftxui/dom/elements.hpp>
#include <ftxui/screen/screen.hpp>
#include <iostream>
#include "scroller.hpp"

ftxui::Element get_document() {
  using namespace ftxui;
  auto cell = [](const char* t) { return text(t) | border; };
  auto document =  //
      gridbox({
          {
              cell("north-west"),
              cell("north"),
              cell("north-east"),
          },
          {
              cell("center-west"),
              gridbox({
                  {
                      cell("center-north-west"),
                      cell("center-north-east"),
                  },
                  {
                      cell("center-south-west"),
                      cell("center-south-east"),
                  },
              }),
              cell("center-east"),
          },
          {
              cell("south-west"),
              cell("south"),
              cell("south-east"),
          },
      });
  return document;
}

int main() {
  using namespace ftxui;
  auto cell = [](const char* t) { return text(t) | border; };

  int n;
  std::cin >> n;

  if (n == 1) {
    Element document = get_document();

    auto component = Renderer([document] { return document; });
    component |= Scroller;
    auto screen = ScreenInteractive::FullscreenAlternateScreen();
    screen.Loop(component);
  } else {
    Elements documents;
    for (int i = 0; i < 10; i++) {
      auto document = get_document();
      document |= border;
      documents.push_back(document);
    }
    auto component = Renderer([documents] { return vbox(documents); });
    component |= Scroller;
    auto screen = ScreenInteractive::FullscreenAlternateScreen();
    screen.Loop(component);
  }

  return 0;
}

I am using Scroller , both works .

But This Scroller if applied to component makes component unresponsive to event , but I use
this ComponenetDecorator with them, which works.

ftxui::ComponentDecorator vscroll_renderer = ftxui::Renderer(
  [](ftxui::Element e) { return e | ftxui::vscroll_indicator | ftxui::frame; });

Is this the correct way?

Also I want to ask, is this the correct way to convert element to Component, am I doing it correct,

auto component = Renderer([document] { return document; });

or is there some better way ?

Also in catch event is there a way to map bindings to scroll to top /bottom , e.g. something vim like gg for top , G for bottom.

Anyway, thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants