mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-11-01 02:58:12 +08:00 
			
		
		
		
	Add menu styles.
This commit is contained in:
		| @@ -1,4 +1,5 @@ | ||||
| cmake_minimum_required(VERSION 3.0) | ||||
|  | ||||
| enable_testing() | ||||
|  | ||||
| add_subdirectory(ftxui) | ||||
|   | ||||
| @@ -1,3 +1,5 @@ | ||||
| cmake_minimum_required(VERSION 3.0) | ||||
|  | ||||
| function(example name) | ||||
|   add_executable(${name} ${name}.cpp) | ||||
|   target_link_libraries(${name} PUBLIC ftxui) | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| example(color) | ||||
| example(gauge) | ||||
| example(input) | ||||
| example(menu) | ||||
| example(menu2) | ||||
| example(menu_style) | ||||
| example(toggle) | ||||
|   | ||||
| @@ -70,7 +70,7 @@ class MyComponent : ComponentHorizontal { | ||||
|  | ||||
| int main(int argc, const char *argv[]) | ||||
| { | ||||
|   ftxui::ScreenInteractive screen(60,17); | ||||
|   ftxui::ScreenInteractive screen(60,18); | ||||
|   MyComponent component(screen.delegate()); | ||||
|   component.on_enter = screen.ExitLoopClosure(); | ||||
|   screen.Loop(); | ||||
|   | ||||
							
								
								
									
										87
									
								
								examples/component/menu_style.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										87
									
								
								examples/component/menu_style.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,87 @@ | ||||
| #include <iostream> | ||||
| #include <thread> | ||||
|  | ||||
| #include "ftxui/component/component_horizontal.hpp" | ||||
| #include "ftxui/component/menu.hpp" | ||||
| #include "ftxui/screen_interactive.hpp" | ||||
| #include "ftxui/util/string.hpp" | ||||
|  | ||||
| using namespace ftxui; | ||||
| using namespace ftxui::component; | ||||
| using namespace ftxui::dom; | ||||
|  | ||||
| class MyComponent : ComponentHorizontal { | ||||
|   public: | ||||
|    MyComponent(ftxui::component::Delegate* delegate) | ||||
|        : ComponentHorizontal(delegate), | ||||
|          menu_1(delegate->NewChild()), | ||||
|          menu_2(delegate->NewChild()), | ||||
|          menu_3(delegate->NewChild()), | ||||
|          menu_4(delegate->NewChild()), | ||||
|          menu_5(delegate->NewChild()), | ||||
|          menu_6(delegate->NewChild()) { | ||||
|  | ||||
|      for(Menu* menu : {&menu_1, &menu_2, &menu_3, &menu_4, &menu_5, &menu_6}) { | ||||
|        menu->entries = { | ||||
|          L"Monkey", | ||||
|          L"Dog", | ||||
|          L"Cat", | ||||
|          L"Bird", | ||||
|          L"Elephant", | ||||
|        }; | ||||
|        menu->on_enter = [this]() { on_enter(); }; | ||||
|      } | ||||
|  | ||||
|      menu_2.selected_style = color(Color::Blue); | ||||
|      menu_2.active_style = compose(bold, color(Color::Blue)); | ||||
|  | ||||
|      menu_3.selected_style = color(Color::Blue); | ||||
|      menu_3.active_style = bgcolor(Color::Blue); | ||||
|  | ||||
|      menu_4.selected_style = bgcolor(Color::Blue); | ||||
|      menu_4.active_style = bgcolor(Color::BlueLight); | ||||
|  | ||||
|      menu_5.normal_style = bgcolor(Color::Blue); | ||||
|      menu_5.selected_style = bgcolor(Color::Yellow); | ||||
|      menu_5.active_style = bgcolor(Color::Red); | ||||
|  | ||||
|      menu_6.normal_style = compose(dim, color(Color::Blue)); | ||||
|      menu_6.selected_style = compose(nothing, color(Color::Blue)); | ||||
|      menu_6.active_style = compose(bold, color(Color::Blue)); | ||||
|  | ||||
|      Focus(&menu_1); | ||||
|    } | ||||
|  | ||||
|    std::function<void()> on_enter = [](){}; | ||||
|   private: | ||||
|    Menu menu_1; | ||||
|    Menu menu_2; | ||||
|    Menu menu_3; | ||||
|    Menu menu_4; | ||||
|    Menu menu_5; | ||||
|    Menu menu_6; | ||||
|  | ||||
|    Element Render() override { | ||||
|      return | ||||
|       vbox( | ||||
|         hbox( | ||||
|           flex(frame(center(text(L" menu_1 ")), menu_1.Render())), | ||||
|           flex(frame(center(text(L" menu_2 ")), menu_2.Render())), | ||||
|           flex(frame(center(text(L" menu_3 ")), menu_3.Render())) | ||||
|         ), | ||||
|         hbox( | ||||
|           flex(frame(center(text(L" menu_4 ")), menu_4.Render())), | ||||
|           flex(frame(center(text(L" menu_5 ")), menu_5.Render())), | ||||
|           flex(frame(center(text(L" menu_6 ")), menu_6.Render())) | ||||
|         ) | ||||
|       ); | ||||
|    } | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char *argv[]) | ||||
| { | ||||
|   ftxui::ScreenInteractive screen(90,14); | ||||
|   MyComponent component(screen.delegate()); | ||||
|   component.on_enter = screen.ExitLoopClosure(); | ||||
|   screen.Loop(); | ||||
| } | ||||
| @@ -18,15 +18,12 @@ class MyComponent : ComponentVertical { | ||||
|       : ComponentVertical(delegate), | ||||
|         toggle_1(delegate->NewChild()), | ||||
|         toggle_2(delegate->NewChild()), | ||||
|         toggle_3(delegate->NewChild()) { | ||||
|     toggle_1.on = L"On"; | ||||
|     toggle_1.off = L"Off"; | ||||
|  | ||||
|     toggle_2.on = L"Enabled"; | ||||
|     toggle_2.off = L"Disabled"; | ||||
|  | ||||
|     toggle_3.on = L"10€"; | ||||
|     toggle_3.off = L"0€"; | ||||
|         toggle_3(delegate->NewChild()), | ||||
|         toggle_4(delegate->NewChild()) { | ||||
|     toggle_1.options = {L"On", L"Off"}; | ||||
|     toggle_2.options = {L"Enabled", L"Disabled"}; | ||||
|     toggle_3.options = {L"10€", L"0€"}; | ||||
|     toggle_4.options = {L"Nothing", L"One element", L"Several elements"}; | ||||
|  | ||||
|     Focus(&toggle_1); | ||||
|   } | ||||
| @@ -37,6 +34,7 @@ class MyComponent : ComponentVertical { | ||||
|   Toggle toggle_1; | ||||
|   Toggle toggle_2; | ||||
|   Toggle toggle_3; | ||||
|   Toggle toggle_4; | ||||
|  | ||||
|   Element Render() override { | ||||
|     return | ||||
| @@ -45,7 +43,8 @@ class MyComponent : ComponentVertical { | ||||
|         text(L""), | ||||
|         hbox(text(L" * Poweroff on startup      : "), toggle_1.Render()), | ||||
|         hbox(text(L" * Out of process           : "), toggle_2.Render()), | ||||
|         hbox(text(L" * Price of the information : "), toggle_3.Render()) | ||||
|         hbox(text(L" * Price of the information : "), toggle_3.Render()), | ||||
|         hbox(text(L" * Number of elements       : "), toggle_4.Render()) | ||||
|       ); | ||||
|   } | ||||
|  | ||||
| @@ -63,7 +62,7 @@ class MyComponent : ComponentVertical { | ||||
| }; | ||||
|  | ||||
| int main(int argc, const char* argv[]) { | ||||
|   ftxui::ScreenInteractive screen(50,5); | ||||
|   ftxui::ScreenInteractive screen(70,7); | ||||
|   MyComponent component(screen.delegate()); | ||||
|   component.on_enter = screen.ExitLoopClosure(); | ||||
|   screen.Loop(); | ||||
|   | ||||
| @@ -1,3 +1,6 @@ | ||||
| example(color) | ||||
| example(dbox) | ||||
| example(frame) | ||||
| example(gauge) | ||||
| example(separator) | ||||
| example(vbox_hbox) | ||||
|   | ||||
							
								
								
									
										31
									
								
								examples/dom/dbox.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								examples/dom/dbox.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | ||||
| #include "ftxui/screen.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include <iostream> | ||||
|  | ||||
| int main(int argc, const char *argv[]) | ||||
| { | ||||
|   using namespace ftxui::dom; | ||||
|   auto document = | ||||
|     dbox( | ||||
|       frame( | ||||
|         vbox( | ||||
|           text(L"line_1"), | ||||
|           text(L"line_2"), | ||||
|           text(L"line_3"), | ||||
|           text(L"line_4"), | ||||
|           text(L"line_5") | ||||
|         ) | ||||
|       ), | ||||
|       center( | ||||
|         frame( | ||||
|           text(L"overlay") | ||||
|         ) | ||||
|       ) | ||||
|     ); | ||||
|   auto screen = ftxui::Screen::TerminalOutput(document); | ||||
|   Render(screen, document.get()); | ||||
|  | ||||
|   std::cout << screen.ToString(); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| @@ -7,9 +7,9 @@ | ||||
| 
 | ||||
| int main(int argc, const char *argv[]) | ||||
| { | ||||
|   for(float percentage = 0; percentage <= 1.0; percentage+=0.001) { | ||||
|   for(float percentage = 0; percentage <= 1.0; percentage+=0.002) { | ||||
|     std::wstring data_downloaded = | ||||
|         std::to_wstring(int(percentage * 44100)) + L"/44100"; | ||||
|         std::to_wstring(int(percentage * 5000)) + L"/5000"; | ||||
|     using namespace ftxui::dom; | ||||
|     auto document = | ||||
|         hbox( | ||||
| @@ -1,5 +1,4 @@ | ||||
| cmake_minimum_required(VERSION 3.0) | ||||
| project(ftxui) | ||||
|  | ||||
| add_library(ftxui | ||||
|   src/ftxui/component/component.cpp | ||||
| @@ -13,6 +12,7 @@ add_library(ftxui | ||||
|   src/ftxui/dom/bold.cpp | ||||
|   src/ftxui/dom/color.cpp | ||||
|   src/ftxui/dom/composite_decorator.cpp | ||||
|   src/ftxui/dom/dbox.cpp | ||||
|   src/ftxui/dom/dim.cpp | ||||
|   src/ftxui/dom/flex.cpp | ||||
|   src/ftxui/dom/frame.cpp | ||||
|   | ||||
| @@ -2,6 +2,7 @@ | ||||
| #define FTXUI_COMPONENT_MENU | ||||
|  | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include <functional> | ||||
|  | ||||
| namespace ftxui { | ||||
| @@ -16,6 +17,10 @@ class Menu : public Component { | ||||
|   std::vector<std::wstring> entries = {}; | ||||
|   int selected = 0; | ||||
|  | ||||
|   dom::Decorator active_style = dom::inverted; | ||||
|   dom::Decorator selected_style = dom::bold; | ||||
|   dom::Decorator normal_style = dom::nothing; | ||||
|  | ||||
|   // State update callback. | ||||
|   std::function<void()> on_change = [](){}; | ||||
|   std::function<void()> on_enter = [](){}; | ||||
|   | ||||
| @@ -3,6 +3,7 @@ | ||||
|  | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include <functional> | ||||
| #include <string> | ||||
|  | ||||
| namespace ftxui { | ||||
| namespace component { | ||||
| @@ -13,9 +14,8 @@ class Toggle : public Component { | ||||
|   Toggle(Delegate*); | ||||
|  | ||||
|   // State. | ||||
|   bool activated = true; | ||||
|   std::wstring on = L"On"; | ||||
|   std::wstring off = L"Off"; | ||||
|   size_t activated = 0; | ||||
|   std::vector<std::wstring> options = {L"On", L"Off"}; | ||||
|  | ||||
|   // Callback. | ||||
|   std::function<void()> on_change = [](){}; | ||||
|   | ||||
| @@ -1,6 +1,8 @@ | ||||
| #ifndef FTXUI_DOM_ELEMENTS_HPP | ||||
| #define FTXUI_DOM_ELEMENTS_HPP | ||||
|  | ||||
| #include <functional> | ||||
|  | ||||
| #include "ftxui/color.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
|  | ||||
| @@ -8,12 +10,14 @@ namespace ftxui { | ||||
| namespace dom { | ||||
|  | ||||
| using Element = std::unique_ptr<Node>; | ||||
| using Decorator = std::function<Element(Element)>; | ||||
| using Child = std::unique_ptr<Node>; | ||||
| using Children = std::vector<Child>; | ||||
|  | ||||
| // --- Layout ---- | ||||
| Element vbox(Children); | ||||
| Element hbox(Children); | ||||
| Element dbox(Children); | ||||
| Element flex(); | ||||
| Element flex(Element); | ||||
|  | ||||
| @@ -32,6 +36,8 @@ Element underlined(Element); | ||||
| Element blink(Element); | ||||
| Element color(Color, Element); | ||||
| Element bgcolor(Color, Element); | ||||
| Decorator color(Color); | ||||
| Decorator bgcolor(Color); | ||||
|  | ||||
| // --- Util --- | ||||
| Element hcenter(Element); | ||||
| @@ -40,6 +46,7 @@ Element center(Element); | ||||
|  | ||||
| // --- Util --- | ||||
| Element nothing(Element element); | ||||
| Decorator compose(Decorator, Decorator); | ||||
|  | ||||
| template <class... Args> | ||||
| Children unpack(Args... args) { | ||||
| @@ -58,6 +65,11 @@ Element hbox(Args... children) { | ||||
|   return hbox(unpack(std::forward<Args>(children)...)); | ||||
| } | ||||
|  | ||||
| template <class... Args> | ||||
| Element dbox(Args... children) { | ||||
|   return dbox(unpack(std::forward<Args>(children)...)); | ||||
| } | ||||
|  | ||||
| };  // namespace dom | ||||
| };  // namespace ftxui | ||||
|  | ||||
|   | ||||
| @@ -24,9 +24,6 @@ dom::Element Input::Render() { | ||||
|   if (!is_focused) | ||||
|     return flex(text(content)); | ||||
|  | ||||
|   std::wstring sub_content = content; | ||||
|   size_t sub_cursor_position = cursor_position; | ||||
|  | ||||
|   std::wstring part_before_cursor = content.substr(0,cursor_position); | ||||
|   std::wstring part_at_cursor = cursor_position < (int)content.size() | ||||
|                                     ? content.substr(cursor_position, 1) | ||||
|   | ||||
| @@ -14,12 +14,12 @@ dom::Element Menu::Render() { | ||||
|   for (size_t i = 0; i < entries.size(); ++i) { | ||||
|     if (size_t(selected) == i) { | ||||
|       if (focused) | ||||
|         elements.push_back(inverted(text(L"> " + entries[i]))); | ||||
|         elements.push_back(active_style(text(L"> " + entries[i]))); | ||||
|       else | ||||
|         elements.push_back(bold(text(L"> " + entries[i]))); | ||||
|         elements.push_back(selected_style(text(L"> " + entries[i]))); | ||||
|     } | ||||
|     else { | ||||
|       elements.push_back(text(L"  " + entries[i])); | ||||
|       elements.push_back(normal_style(text(L"  " + entries[i]))); | ||||
|     } | ||||
|   } | ||||
|   return vbox(std::move(elements)); | ||||
|   | ||||
| @@ -11,33 +11,34 @@ dom::Element Toggle::Render() { | ||||
|  | ||||
|   Children children; | ||||
|   children.push_back(text(L"[")); | ||||
|   if (activated) { | ||||
|     children.push_back(highlight(text(on))); | ||||
|  | ||||
|   for(size_t i = 0; i<options.size(); ++i) { | ||||
|     // Separator. | ||||
|     if (i != 0) | ||||
|       children.push_back(text(L"|")); | ||||
|     children.push_back(dim(text(off))); | ||||
|   } else { | ||||
|     children.push_back(dim(text(on))); | ||||
|     children.push_back(text(L"|")); | ||||
|     children.push_back(highlight(text(off))); | ||||
|  | ||||
|     // Entry. | ||||
|     auto style = i == activated ? highlight : dim; | ||||
|     children.push_back(style(text(options[i]))); | ||||
|   } | ||||
|   children.push_back(text(L"]")); | ||||
|   return hbox(std::move(children)); | ||||
| } | ||||
|  | ||||
| bool Toggle::OnEvent(Event event) { | ||||
|   if (activated) { | ||||
|     if (event == Event::ArrowRight || event == Event::Character('l')) { | ||||
|       activated = false; | ||||
|   if (activated > 0 && | ||||
|       (event == Event::ArrowLeft || event == Event::Character('h'))) { | ||||
|     activated--; | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
|   } else { | ||||
|     if (event == Event::ArrowLeft || event == Event::Character('h')) { | ||||
|       activated = true; | ||||
|  | ||||
|   if (activated < options.size() - 1 && | ||||
|       (event == Event::ArrowRight || event == Event::Character('l'))) { | ||||
|     activated++; | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|   | ||||
| @@ -47,5 +47,17 @@ std::unique_ptr<Node> bgcolor(Color c, Child child) { | ||||
|   return std::make_unique<BgColor>(unpack(std::move(child)), c); | ||||
| } | ||||
|  | ||||
| Decorator color(Color c) { | ||||
|   return [c](Child child) { | ||||
|     return color(c, std::move(child)); | ||||
|   }; | ||||
| } | ||||
|  | ||||
| Decorator bgcolor(Color c) { | ||||
|   return [c](Child child) { | ||||
|     return bgcolor(c, std::move(child)); | ||||
|   }; | ||||
| } | ||||
|  | ||||
| };  // namespace dom | ||||
| };  // namespace ftxui | ||||
|   | ||||
							
								
								
									
										37
									
								
								ftxui/src/ftxui/dom/dbox.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								ftxui/src/ftxui/dom/dbox.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
| namespace dom { | ||||
|  | ||||
| class DBox : public Node { | ||||
|  public: | ||||
|   DBox(Children children) : Node(std::move(children)) {} | ||||
|   ~DBox() {} | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
|     requirement_.min.x = 0; | ||||
|     requirement_.min.y = 0; | ||||
|     requirement_.flex.x = 1; | ||||
|     requirement_.flex.y = 0; | ||||
|     for (auto& child : children) { | ||||
|       child->ComputeRequirement(); | ||||
|       requirement_.min.x = std::max(requirement_.min.x, child->requirement().min.x); | ||||
|       requirement_.min.y = std::max(requirement_.min.y, child->requirement().min.y); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void SetBox(Box box) override { | ||||
|     Node::SetBox(box); | ||||
|  | ||||
|     for (auto& child : children) | ||||
|       child->SetBox(box); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> dbox(Children children) { | ||||
|   return std::make_unique<DBox>(std::move(children)); | ||||
| } | ||||
|  | ||||
| };  // namespace dom | ||||
| };  // namespace ftxui | ||||
| @@ -7,5 +7,14 @@ Element nothing(Element element) { | ||||
|   return std::move(element); | ||||
| } | ||||
|  | ||||
| Decorator compose(Decorator a, Decorator b) { | ||||
|   return [ | ||||
|     a = std::move(a), | ||||
|     b = std::move(b) | ||||
|   ](Element element) { | ||||
|     return a(b(std::move(element))); | ||||
|   }; | ||||
| } | ||||
|  | ||||
| };  // namespace dom | ||||
| };  // namespace ftxui | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Arthur Sonzogni
					Arthur Sonzogni