mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-11-04 05:28:15 +08:00 
			
		
		
		
	Feature: hscroll_indicator (#753)
				
					
				
			This is the symetrical of `vscroll_indicator`. Requested by @ibrahimnasson. Fixed:https://github.com/ArthurSonzogni/FTXUI/issues/752
This commit is contained in:
		
				
					committed by
					
						
						ArthurSonzogni
					
				
			
			
				
	
			
			
			
						parent
						
							dd6a5d371f
						
					
				
				
					commit
					19ffc37696
				
			@@ -12,7 +12,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ftxui {
 | 
			
		||||
 | 
			
		||||
  namespace {
 | 
			
		||||
namespace {
 | 
			
		||||
class BgColor : public NodeDecorator {
 | 
			
		||||
 public:
 | 
			
		||||
  BgColor(Element child, Color color)
 | 
			
		||||
 
 | 
			
		||||
@@ -13,7 +13,7 @@
 | 
			
		||||
 | 
			
		||||
namespace ftxui {
 | 
			
		||||
 | 
			
		||||
  namespace {
 | 
			
		||||
namespace {
 | 
			
		||||
class DBox : public Node {
 | 
			
		||||
 public:
 | 
			
		||||
  explicit DBox(Elements children) : Node(std::move(children)) {}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,6 @@ class Select : public Node {
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Focus : public Select {
 | 
			
		||||
 public:
 | 
			
		||||
  using Select::Select;
 | 
			
		||||
@@ -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.
 | 
			
		||||
 
 | 
			
		||||
@@ -159,7 +159,7 @@ class Gauge : public Node {
 | 
			
		||||
  Direction direction_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace ftxui
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
/// @brief Draw a high definition progress bar progressing in specified
 | 
			
		||||
/// direction.
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
@@ -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) {
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,18 @@ 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);
 | 
			
		||||
@@ -33,9 +45,16 @@ std::string PrintVerticalList(int focused_index, int n) {
 | 
			
		||||
  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"
 | 
			
		||||
@@ -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) {
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user