mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-10-31 18:48:11 +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` | ||||
|   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. | ||||
|  | ||||
|   | ||||
| @@ -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) | ||||
|   | ||||
							
								
								
									
										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 --- | ||||
| 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. | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -164,4 +164,4 @@ TEST(StringTest, to_wstring) { | ||||
|   EXPECT_EQ(to_wstring(std::string("🎅🎄")), L"🎅🎄"); | ||||
| } | ||||
|  | ||||
| } | ||||
| }  // namespace ftxui | ||||
|   | ||||
		Reference in New Issue
	
	Block a user