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

Feature: hscroll_indicator #753

Merged
merged 1 commit into from
Sep 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ current (development)
- Feature: Add support for `Input`'s insert mode. Add `InputOption::insert`
option. Added by @mingsheng13.

### Dom
- Feature: Add `hscroll_indicator`. It display an horizontal indicator
reflecting the current scroll position. Proposed by @ibrahimnasson in
[issue 752](https://github.com/ArthurSonzogni/FTXUI/issues/752)

### Build
- Support for cmake's "unity/jumbo" builds. Fixed by @ClausKlein.

Expand Down
1 change: 1 addition & 0 deletions examples/component/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ example(menu2)
example(menu_entries)
example(menu_entries_animated)
example(menu_in_frame)
example(menu_in_frame_horizontal)
example(menu_multiple)
example(menu_style)
example(menu_underline_animated_gallery)
Expand Down
21 changes: 12 additions & 9 deletions examples/component/button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,30 @@ ButtonOption ButtonStyle() {
int main() {
int value = 50;


// The tree of components. This defines how to navigate using the keyboard.
auto buttons =
Container::Vertical({
auto buttons = Container::Vertical({
Container::Horizontal({
Button("-1", [&] { value--; }, ButtonStyle()),
Button("+1", [&] { value++; }, ButtonStyle()),
Button(
"-1", [&] { value--; }, ButtonStyle()),
Button(
"+1", [&] { value++; }, ButtonStyle()),
}) | flex,
Container::Horizontal({
Button("-10", [&] { value -= 10; }, ButtonStyle()),
Button("+10", [&] { value += 10; }, ButtonStyle()),
Button(
"-10", [&] { value -= 10; }, ButtonStyle()),
Button(
"+10", [&] { value += 10; }, ButtonStyle()),
}) | flex,
});
});

// Modify the way to render them on screen:
auto component = Renderer(buttons, [&] {
return vbox({
text("value = " + std::to_string(value)),
separator(),
buttons->Render() | flex,
}) | flex | border;
}) |
flex | border;
});

auto screen = ScreenInteractive::Fullscreen();
Expand Down
30 changes: 30 additions & 0 deletions examples/component/menu_in_frame_horizontal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
#include <memory> // for shared_ptr, __shared_ptr_access
#include <string> // for string, basic_string, operator+, to_string
#include <vector> // for vector

#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Radiobox, Renderer
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for operator|, Element, size, border, frame, HEIGHT, LESS_THAN

using namespace ftxui;

int main() {
std::vector<std::string> entries;
int selected = 0;

for (int i = 0; i < 100; ++i)
entries.push_back(std::to_string(i));
auto radiobox = Menu(&entries, &selected, MenuOption::Horizontal());
auto renderer = Renderer(
radiobox, [&] { return radiobox->Render() | hscroll_indicator | frame; });

auto screen = ScreenInteractive::FitComponent();
screen.Loop(renderer);

return 0;
}
1 change: 1 addition & 0 deletions include/ftxui/dom/elements.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ Element focusCursorUnderlineBlinking(Element);

// --- Misc ---
Element vscroll_indicator(Element);
Element hscroll_indicator(Element);
Decorator reflect(Box& box);
// Before drawing the |element| clear the pixel below. This is useful in
// combinaison with dbox.
Expand Down
2 changes: 1 addition & 1 deletion src/ftxui/component/screen_interactive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ void ScreenInteractive::TrackMouse(bool enable) {
track_mouse_ = enable;
}

/// @brief Add a task to the main loop.
/// @brief Add a task to the main loop.
/// It will be executed later, after every other scheduled tasks.
/// @ingroup component
void ScreenInteractive::Post(Task task) {
Expand Down
2 changes: 1 addition & 1 deletion src/ftxui/dom/color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

namespace ftxui {

namespace {
namespace {
class BgColor : public NodeDecorator {
public:
BgColor(Element child, Color color)
Expand Down
2 changes: 1 addition & 1 deletion src/ftxui/dom/dbox.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

namespace ftxui {

namespace {
namespace {
class DBox : public Node {
public:
explicit DBox(Elements children) : Node(std::move(children)) {}
Expand Down
2 changes: 0 additions & 2 deletions src/ftxui/dom/frame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class Select : public Node {
}
};


class Focus : public Select {
public:
using Select::Select;
Expand Down Expand Up @@ -143,7 +142,6 @@ class FocusCursor : public Focus {
Screen::Cursor::Shape shape_;
};


} // namespace

/// @brief Set the `child` to be the one selected among its siblings.
Expand Down
2 changes: 1 addition & 1 deletion src/ftxui/dom/gauge.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@ class Gauge : public Node {
Direction direction_;
};

} // namespace ftxui
} // namespace

/// @brief Draw a high definition progress bar progressing in specified
/// direction.
Expand Down
61 changes: 59 additions & 2 deletions src/ftxui/dom/scroll_indicator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include <utility> // for move
#include <vector> // for __alloc_traits<>::value_type

#include "ftxui/dom/elements.hpp" // for Element, vscroll_indicator
#include "ftxui/dom/elements.hpp" // for Element, vscroll_indicator, hscroll_indicator
#include "ftxui/dom/node.hpp" // for Node, Elements
#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator
#include "ftxui/dom/requirement.hpp" // for Requirement
Expand All @@ -16,7 +16,7 @@

namespace ftxui {

/// @brief Add a filter that will invert the foreground and the background
/// @brief Display a vertical scrollbar to the right.
/// colors.
/// @ingroup dom
Element vscroll_indicator(Element child) {
Expand Down Expand Up @@ -72,4 +72,61 @@ Element vscroll_indicator(Element child) {
return std::make_shared<Impl>(std::move(child));
}

/// @brief Display an horizontal scrollbar to the bottom.
/// colors.
/// @ingroup dom
Element hscroll_indicator(Element child) {
class Impl : public NodeDecorator {
using NodeDecorator::NodeDecorator;

void ComputeRequirement() override {
NodeDecorator::ComputeRequirement();
requirement_ = children_[0]->requirement();
requirement_.min_y++;
}

void SetBox(Box box) override {
box_ = box;
box.y_max--;
children_[0]->SetBox(box);
}

void Render(Screen& screen) final {
NodeDecorator::Render(screen);

const Box& stencil = screen.stencil;

const int size_inner = box_.x_max - box_.x_min;
if (size_inner <= 0) {
return;
}
const int size_outter = stencil.x_max - stencil.x_min + 1;
if (size_outter >= size_inner) {
return;
}

int size = 2 * size_outter * size_outter / size_inner;
size = std::max(size, 1);

const int start_x =
2 * stencil.x_min + //
2 * (stencil.x_min - box_.x_min) * size_outter / size_inner;

const int y = stencil.y_max;
for (int x = stencil.x_min; x <= stencil.x_max; ++x) {
const int x_left = 2 * x + 0;
const int x_right = 2 * x + 1;
const bool left = (start_x <= x_left) && (x_left <= start_x + size);
const bool right = (start_x <= x_right) && (x_right <= start_x + size);

const char* c =
left ? (right ? "─" : "╴") : (right ? "╶" : " "); // NOLINT
screen.PixelAt(x, y) = Pixel();
screen.PixelAt(x, y).character = c;
}
}
};
return std::make_shared<Impl>(std::move(child));
}

} // namespace ftxui
71 changes: 70 additions & 1 deletion src/ftxui/dom/scroll_indicator_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,35 @@ Element MakeVerticalList(int focused_index, int n) {
return vbox(std::move(list)) | vscroll_indicator | frame | border;
}

Element MakeHorizontalList(int focused_index, int n) {
Elements list;
for (int i = 0; i < n; ++i) {
auto element = text(std::to_string(i));
if (i == focused_index) {
element |= focus;
}
list.push_back(element);
}
return hbox(std::move(list)) | hscroll_indicator | frame | border;
}

std::string PrintVerticalList(int focused_index, int n) {
auto element = MakeVerticalList(focused_index, n);
Screen screen(6, 6);
Render(screen, element);
return screen.ToString();
}

std::string PrintHorizontalList(int focused_index, int n) {
auto element = MakeHorizontalList(focused_index, n);
Screen screen(6, 4);
Render(screen, element);
return screen.ToString();
}

} // namespace

TEST(ScrollIndicator, Basic) {
TEST(ScrollIndicator, BasicVertical) {
EXPECT_EQ(PrintVerticalList(0, 10),
"╭────╮\r\n"
"│0 ┃│\r\n"
Expand Down Expand Up @@ -108,6 +127,56 @@ TEST(ScrollIndicator, Basic) {
"╰────╯");
}

TEST(ScrollIndicator, BasicHorizontal) {
EXPECT_EQ(PrintHorizontalList(0, 10),
"╭────╮\r\n"
"│0123│\r\n"
"│── │\r\n"
"╰────╯");

EXPECT_EQ(PrintHorizontalList(1, 10),
"╭────╮\r\n"
"│0123│\r\n"
"│── │\r\n"
"╰────╯");

EXPECT_EQ(PrintHorizontalList(2, 10),
"╭────╮\r\n"
"│1234│\r\n"
"│── │\r\n"
"╰────╯");
EXPECT_EQ(PrintHorizontalList(3, 10),
"╭────╮\r\n"
"│2345│\r\n"
"│╶─╴ │\r\n"
"╰────╯");
EXPECT_EQ(PrintHorizontalList(4, 10),
"╭────╮\r\n"
"│3456│\r\n"
"│ ── │\r\n"
"╰────╯");
EXPECT_EQ(PrintHorizontalList(5, 10),
"╭────╮\r\n"
"│4567│\r\n"
"│ ╶─╴│\r\n"
"╰────╯");
EXPECT_EQ(PrintHorizontalList(6, 10),
"╭────╮\r\n"
"│5678│\r\n"
"│ ──│\r\n"
"╰────╯");
EXPECT_EQ(PrintHorizontalList(7, 10),
"╭────╮\r\n"
"│6789│\r\n"
"│ ──│\r\n"
"╰────╯");
EXPECT_EQ(PrintHorizontalList(8, 10),
"╭────╮\r\n"
"│6789│\r\n"
"│ ──│\r\n"
"╰────╯");
}

namespace {

Element MakeHorizontalFlexboxList(int n) {
Expand Down
2 changes: 1 addition & 1 deletion src/ftxui/dom/size.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ class Size : public Node {
Constraint constraint_;
int value_;
};
} // namespace
} // namespace

/// @brief Apply a constraint on the size of an element.
/// @param direction Whether the WIDTH of the HEIGHT of the element must be
Expand Down
1 change: 0 additions & 1 deletion src/ftxui/dom/table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ Table::Table() {
Initialize({});
}


/// @brief Create a table from a vector of vector of string.
/// @param input The input data.
/// @ingroup dom
Expand Down
2 changes: 1 addition & 1 deletion src/ftxui/screen/string.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.
//
//
// Content of this file was created thanks to:
// -
// https://www.unicode.org/Public/UCD/latest/ucd/auxiliary/WordBreakProperty.txt
Expand Down
2 changes: 1 addition & 1 deletion src/ftxui/screen/string_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,4 +164,4 @@ TEST(StringTest, to_wstring) {
EXPECT_EQ(to_wstring(std::string("🎅🎄")), L"🎅🎄");
}

}
} // namespace ftxui
Loading