FTXUI
FTXUI copied to clipboard
Scrollable paragraph
Hello. I sincerely apologize for using issues as helpdesk but cannot figure out how to make a thing which looks trivial: scrollable paragraph frame. Meaning, I need to display quite a wall of text and want to let user to scroll it with arrows/mouse wheel. I checked the other issues and the code of git-tui and chrome-log-beautifier, but they seem to operate with lists, not paragraphs. Or there is no easy builtin way to do that, and I need to write a component for this purpose from scratch?
Thanks in advance, the library is very neat and handy!
Hello, Maybe you can try wrapping your component with the scroller from git-tui: https://github.com/ArthurSonzogni/git-tui/blob/master/src/scroller.cpp
Thanks, I'll give it another shot today or later this week.
Still got no luck with paragraph, can't find an easy way to shift viewport there, as with a single paragraph element, the size is always 1. However, it works with just a list of strings which satisfies my needs for now:
class ScrollerBase : public ComponentBase {
public:
explicit ScrollerBase(Component child) {
Add(std::move(child));
}
private:
Element Render() final {
auto focused = Focused() ? focus : ftxui::select;
Element background = ComponentBase::Render();
background->ComputeRequirement();
size_ = background->requirement().min_y;
// Values a bit hardcoded for bordered window, should be -0 and -2 if no border is used.
min_selected_ = int(box_.y_max / 2) - 1;
max_selected_ = size_ - int(box_.y_max / 2) - 1;
if (selected_ == 0) {
selected_ = min_selected_;
}
return dbox({
std::move(background),
vbox({
text("") | size(HEIGHT, EQUAL, selected_),
text("") | focused,
}),
}) |
vscroll_indicator | yframe | yflex | reflect(box_) | border;
}
bool OnEvent(Event event) final {
if (event.is_mouse() && box_.Contain(event.mouse().x, event.mouse().y))
TakeFocus();
int selected_old = selected_;
if (event == Event::ArrowUp || event == Event::Character('k') ||
(event.is_mouse() && event.mouse().button == Mouse::WheelUp)) {
selected_--;
}
if ((event == Event::ArrowDown || event == Event::Character('j') ||
(event.is_mouse() && event.mouse().button == Mouse::WheelDown))) {
selected_++;
}
if (event == Event::PageDown)
selected_ += box_.y_max - box_.y_min;
if (event == Event::PageUp)
selected_ -= box_.y_max - box_.y_min;
if (event == Event::Home)
selected_ = 0;
if (event == Event::End)
selected_ = size_;
if (selected_ < min_selected_) {
selected_ = min_selected_;
}
if (selected_ > max_selected_) {
selected_ = max_selected_;
}
selected_ = std::max(0, std::min(size_ - 1, selected_));
return selected_old != selected_;
}
[[nodiscard]] bool Focusable() const final {
return true;
}
int min_selected_ = 0;
int max_selected_ = 0;
int selected_ = 0;
int size_ = 0;
Box box_;
};
Something tells me that there should be an easier way to do that.