mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-11-01 02:58:12 +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:
		 Arthur Sonzogni
					Arthur Sonzogni
				
			
				
					committed by
					
						 ArthurSonzogni
						ArthurSonzogni
					
				
			
			
				
	
			
			
			 ArthurSonzogni
						ArthurSonzogni
					
				
			
						parent
						
							dd6a5d371f
						
					
				
				
					commit
					19ffc37696
				
			| @@ -8,6 +8,11 @@ current (development) | |||||||
| - Feature: Add support for `Input`'s insert mode. Add `InputOption::insert` | - Feature: Add support for `Input`'s insert mode. Add `InputOption::insert` | ||||||
|   option. Added by @mingsheng13. |   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 | ### Build | ||||||
| - Support for cmake's "unity/jumbo" builds. Fixed by @ClausKlein. | - Support for cmake's "unity/jumbo" builds. Fixed by @ClausKlein. | ||||||
|  |  | ||||||
|   | |||||||
| @@ -25,6 +25,7 @@ example(menu2) | |||||||
| example(menu_entries) | example(menu_entries) | ||||||
| example(menu_entries_animated) | example(menu_entries_animated) | ||||||
| example(menu_in_frame) | example(menu_in_frame) | ||||||
|  | example(menu_in_frame_horizontal) | ||||||
| example(menu_multiple) | example(menu_multiple) | ||||||
| example(menu_style) | example(menu_style) | ||||||
| example(menu_underline_animated_gallery) | example(menu_underline_animated_gallery) | ||||||
|   | |||||||
							
								
								
									
										30
									
								
								examples/component/menu_in_frame_horizontal.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								examples/component/menu_in_frame_horizontal.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -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; | ||||||
|  | } | ||||||
| @@ -170,6 +170,7 @@ Element focusCursorUnderlineBlinking(Element); | |||||||
|  |  | ||||||
| // --- Misc --- | // --- Misc --- | ||||||
| Element vscroll_indicator(Element); | Element vscroll_indicator(Element); | ||||||
|  | Element hscroll_indicator(Element); | ||||||
| Decorator reflect(Box& box); | Decorator reflect(Box& box); | ||||||
| // Before drawing the |element| clear the pixel below. This is useful in | // Before drawing the |element| clear the pixel below. This is useful in | ||||||
| // combinaison with dbox. | // combinaison with dbox. | ||||||
|   | |||||||
| @@ -12,7 +12,7 @@ | |||||||
|  |  | ||||||
| namespace ftxui { | namespace ftxui { | ||||||
|  |  | ||||||
|   namespace { | namespace { | ||||||
| class BgColor : public NodeDecorator { | class BgColor : public NodeDecorator { | ||||||
|  public: |  public: | ||||||
|   BgColor(Element child, Color color) |   BgColor(Element child, Color color) | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ | |||||||
|  |  | ||||||
| namespace ftxui { | namespace ftxui { | ||||||
|  |  | ||||||
|   namespace { | namespace { | ||||||
| class DBox : public Node { | class DBox : public Node { | ||||||
|  public: |  public: | ||||||
|   explicit DBox(Elements children) : Node(std::move(children)) {} |   explicit DBox(Elements children) : Node(std::move(children)) {} | ||||||
|   | |||||||
| @@ -37,7 +37,6 @@ class Select : public Node { | |||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| class Focus : public Select { | class Focus : public Select { | ||||||
|  public: |  public: | ||||||
|   using Select::Select; |   using Select::Select; | ||||||
| @@ -143,7 +142,6 @@ class FocusCursor : public Focus { | |||||||
|   Screen::Cursor::Shape shape_; |   Screen::Cursor::Shape shape_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
| }  // namespace | }  // namespace | ||||||
|  |  | ||||||
| /// @brief Set the `child` to be the one selected among its siblings. | /// @brief Set the `child` to be the one selected among its siblings. | ||||||
|   | |||||||
| @@ -159,7 +159,7 @@ class Gauge : public Node { | |||||||
|   Direction direction_; |   Direction direction_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace ftxui | }  // namespace | ||||||
|  |  | ||||||
| /// @brief Draw a high definition progress bar progressing in specified | /// @brief Draw a high definition progress bar progressing in specified | ||||||
| /// direction. | /// direction. | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
| #include <utility>    // for move | #include <utility>    // for move | ||||||
| #include <vector>     // for __alloc_traits<>::value_type | #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.hpp"            // for Node, Elements | ||||||
| #include "ftxui/dom/node_decorator.hpp"  // for NodeDecorator | #include "ftxui/dom/node_decorator.hpp"  // for NodeDecorator | ||||||
| #include "ftxui/dom/requirement.hpp"     // for Requirement | #include "ftxui/dom/requirement.hpp"     // for Requirement | ||||||
| @@ -16,7 +16,7 @@ | |||||||
|  |  | ||||||
| namespace ftxui { | namespace ftxui { | ||||||
|  |  | ||||||
| /// @brief Add a filter that will invert the foreground and the background | /// @brief Display a vertical scrollbar to the right. | ||||||
| /// colors. | /// colors. | ||||||
| /// @ingroup dom | /// @ingroup dom | ||||||
| Element vscroll_indicator(Element child) { | Element vscroll_indicator(Element child) { | ||||||
| @@ -72,4 +72,61 @@ Element vscroll_indicator(Element child) { | |||||||
|   return std::make_shared<Impl>(std::move(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 | }  // namespace ftxui | ||||||
|   | |||||||
| @@ -26,6 +26,18 @@ Element MakeVerticalList(int focused_index, int n) { | |||||||
|   return vbox(std::move(list)) | vscroll_indicator | frame | border; |   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) { | std::string PrintVerticalList(int focused_index, int n) { | ||||||
|   auto element = MakeVerticalList(focused_index, n); |   auto element = MakeVerticalList(focused_index, n); | ||||||
|   Screen screen(6, 6); |   Screen screen(6, 6); | ||||||
| @@ -33,9 +45,16 @@ std::string PrintVerticalList(int focused_index, int n) { | |||||||
|   return screen.ToString(); |   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 | }  // namespace | ||||||
|  |  | ||||||
| TEST(ScrollIndicator, Basic) { | TEST(ScrollIndicator, BasicVertical) { | ||||||
|   EXPECT_EQ(PrintVerticalList(0, 10), |   EXPECT_EQ(PrintVerticalList(0, 10), | ||||||
|             "╭────╮\r\n" |             "╭────╮\r\n" | ||||||
|             "│0  ┃│\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 { | namespace { | ||||||
|  |  | ||||||
| Element MakeHorizontalFlexboxList(int n) { | Element MakeHorizontalFlexboxList(int n) { | ||||||
|   | |||||||
| @@ -47,7 +47,6 @@ Table::Table() { | |||||||
|   Initialize({}); |   Initialize({}); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| /// @brief Create a table from a vector of vector of string. | /// @brief Create a table from a vector of vector of string. | ||||||
| /// @param input The input data. | /// @param input The input data. | ||||||
| /// @ingroup dom | /// @ingroup dom | ||||||
|   | |||||||
| @@ -164,4 +164,4 @@ TEST(StringTest, to_wstring) { | |||||||
|   EXPECT_EQ(to_wstring(std::string("🎅🎄")), L"🎅🎄"); |   EXPECT_EQ(to_wstring(std::string("🎅🎄")), L"🎅🎄"); | ||||||
| } | } | ||||||
|  |  | ||||||
| } | }  // namespace ftxui | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user