mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-10-31 10:38:09 +08:00 
			
		
		
		
	Add example homepage.cpp
This commit is contained in:
		| @@ -16,3 +16,4 @@ example(radiobox_in_frame) | |||||||
| example(tab_horizontal) | example(tab_horizontal) | ||||||
| example(tab_vertical) | example(tab_vertical) | ||||||
| example(toggle) | example(toggle) | ||||||
|  | example(homescreen) | ||||||
|   | |||||||
							
								
								
									
										244
									
								
								examples/component/homescreen.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										244
									
								
								examples/component/homescreen.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,244 @@ | |||||||
|  | #include <cmath> | ||||||
|  | #include <thread> | ||||||
|  | #include "ftxui/component/checkbox.hpp" | ||||||
|  | #include "ftxui/component/container.hpp" | ||||||
|  | #include "ftxui/component/input.hpp" | ||||||
|  | #include "ftxui/component/menu.hpp" | ||||||
|  | #include "ftxui/component/radiobox.hpp" | ||||||
|  | #include "ftxui/component/screen_interactive.hpp" | ||||||
|  | #include "ftxui/component/toggle.hpp" | ||||||
|  | #include "ftxui/screen/string.hpp" | ||||||
|  |  | ||||||
|  | using namespace ftxui; | ||||||
|  |  | ||||||
|  | int shift = 0; | ||||||
|  | class Graph { | ||||||
|  |  public: | ||||||
|  |   std::vector<int> operator()(int width, int height) { | ||||||
|  |     std::vector<int> output(width); | ||||||
|  |     for (int i = 0; i < width; ++i) { | ||||||
|  |       float v = 0; | ||||||
|  |       v += 0.1 * sin((i + shift) * 0.1); | ||||||
|  |       v += 0.2 * sin((i + shift+10) * 0.15); | ||||||
|  |       v += 0.1 * sin((i + shift) * 0.03); | ||||||
|  |       v *= height; | ||||||
|  |       v += 0.5 * height; | ||||||
|  |       output[i] = v; | ||||||
|  |     } | ||||||
|  |     return output; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class HTopComponent : public Component { | ||||||
|  |   Graph my_graph; | ||||||
|  |  | ||||||
|  |  public: | ||||||
|  |   HTopComponent() {} | ||||||
|  |   ~HTopComponent() override {} | ||||||
|  |  | ||||||
|  |   Element Render() override { | ||||||
|  |     return | ||||||
|  |       vbox( | ||||||
|  |         text(L"Frequency [Mhz]") | hcenter, | ||||||
|  |         hbox( | ||||||
|  |           vbox( | ||||||
|  |             text(L"2400 "), filler(), | ||||||
|  |             text(L"1200 "), filler(), | ||||||
|  |             text(L"0% ") | ||||||
|  |           ), | ||||||
|  |           graph(std::ref(my_graph)) | ||||||
|  |         ) | flex, | ||||||
|  |         separator(), | ||||||
|  |         text(L"Utilization [%]") | hcenter, | ||||||
|  |         hbox( | ||||||
|  |           vbox( | ||||||
|  |             text(L"100 "), filler(), | ||||||
|  |             text(L"50 "), filler(), | ||||||
|  |             text(L"0 ") | ||||||
|  |           ), | ||||||
|  |           graph(std::ref(my_graph)) | color(Color::RedLight) | ||||||
|  |         ) | flex, | ||||||
|  |         separator(), | ||||||
|  |         text(L"Ram [Go]") | hcenter, | ||||||
|  |         hbox( | ||||||
|  |           vbox( | ||||||
|  |             text(L"8192"), filler(), | ||||||
|  |             text(L"4096 "), filler(), | ||||||
|  |             text(L"0 ") | ||||||
|  |           ), | ||||||
|  |           graph(std::ref(my_graph)) | color(Color::BlueLight) | ||||||
|  |         ) | flex | ||||||
|  |       ) | border; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class CompilerComponent : public Component { | ||||||
|  |   Container container = Container::Horizontal(); | ||||||
|  |     RadioBox compiler; | ||||||
|  |     Container flag = Container::Vertical(); | ||||||
|  |       CheckBox flag_checkbox[4]; | ||||||
|  |     Container subcontainer = Container::Vertical(); | ||||||
|  |       Container input_container = Container::Horizontal(); | ||||||
|  |         Input input_add; | ||||||
|  |         Menu input; | ||||||
|  |       Input executable; | ||||||
|  |  | ||||||
|  |  public: | ||||||
|  |   ~CompilerComponent() override {} | ||||||
|  |   CompilerComponent() { | ||||||
|  |     Add(&container); | ||||||
|  |  | ||||||
|  |     // Compiler ---------------------------------------------------------------- | ||||||
|  |     compiler.entries = { | ||||||
|  |       L"gcc", | ||||||
|  |       L"clang", | ||||||
|  |       L"emcc", | ||||||
|  |       L"game_maker" | ||||||
|  |     }; | ||||||
|  |     container.Add(&compiler); | ||||||
|  |  | ||||||
|  |     // Flags    ---------------------------------------------------------------- | ||||||
|  |     container.Add(&flag); | ||||||
|  |     flag_checkbox[0].label = L"-Wall"; | ||||||
|  |     flag_checkbox[1].label = L"-Werror"; | ||||||
|  |     flag_checkbox[2].label = L"-lpthread"; | ||||||
|  |     flag_checkbox[3].label = L"-O3"; | ||||||
|  |     for(auto& c : flag_checkbox) | ||||||
|  |       flag.Add(&c); | ||||||
|  |  | ||||||
|  |     container.Add(&subcontainer); | ||||||
|  |     // Executable    ---------------------------------------------------------------- | ||||||
|  |     executable.placeholder = L"executable"; | ||||||
|  |     subcontainer.Add(&executable); | ||||||
|  |  | ||||||
|  |     // Input    ---------------------------------------------------------------- | ||||||
|  |     subcontainer.Add(&input_container); | ||||||
|  |  | ||||||
|  |     input_add.placeholder = L"input files"; | ||||||
|  |     input_add.on_enter = [this] { | ||||||
|  |       input.entries.push_back(input_add.content); | ||||||
|  |       input_add.content = L""; | ||||||
|  |     }; | ||||||
|  |     input_container.Add(&input_add); | ||||||
|  |     input_container.Add(&input); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Element Render() override { | ||||||
|  |     return | ||||||
|  |       vbox( | ||||||
|  |         hbox( | ||||||
|  |           window(text(L"Compiler"), compiler.Render()), | ||||||
|  |           window(text(L"Flags"), flag.Render()), | ||||||
|  |           vbox( | ||||||
|  |             window(text(L"Executable:"), executable.Render()) | ||||||
|  |               | size(WIDTH, EQUAL, 20), | ||||||
|  |             window(text(L"Input"), | ||||||
|  |               hbox( | ||||||
|  |                 vbox( | ||||||
|  |                   hbox(text(L"Add: "), input_add.Render()) | ||||||
|  |                     | size(WIDTH, EQUAL, 20) | ||||||
|  |                     | size(HEIGHT, EQUAL, 1), | ||||||
|  |                   filler() | ||||||
|  |                 ), | ||||||
|  |                 separator(), | ||||||
|  |                 input.Render() | frame | size(HEIGHT, EQUAL, 3) | flex | ||||||
|  |               ) | ||||||
|  |             ) | size(WIDTH, EQUAL, 60) | ||||||
|  |           ), | ||||||
|  |           filler() | ||||||
|  |         ), | ||||||
|  |         hflow(RenderCommandLine()) | ||||||
|  |       ) | border; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Elements RenderCommandLine() { | ||||||
|  |     Elements line; | ||||||
|  |     // Compiler | ||||||
|  |     line.push_back(text(compiler.entries[compiler.selected]) | bold); | ||||||
|  |     // flags | ||||||
|  |     for(auto& it : flag_checkbox) { | ||||||
|  |       if (it.state) { | ||||||
|  |         line.push_back(text(L" ")); | ||||||
|  |         line.push_back(text(it.label) | dim); | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     // Executable | ||||||
|  |     if (!executable.content.empty()) { | ||||||
|  |       line.push_back(text(L" -O ") | bold); | ||||||
|  |       line.push_back(text(executable.content) | color(Color::BlueLight) | bold); | ||||||
|  |     } | ||||||
|  |     // Input | ||||||
|  |     for(auto& it : input.entries) { | ||||||
|  |       line.push_back(text(L" " + it) | color(Color::RedLight)); | ||||||
|  |     } | ||||||
|  |     return line; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class SpinnerComponent : public Component { | ||||||
|  |   Element Render() override { | ||||||
|  |     Elements entries; | ||||||
|  |     for(int i = 0; i<22; ++i) { | ||||||
|  |       if (i != 0) | ||||||
|  |       entries.push_back( | ||||||
|  |         spinner(i, shift/2) | ||||||
|  |           | bold | ||||||
|  |           | size(WIDTH, GREATER_THAN, 2) | ||||||
|  |           | border | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  |     return hflow(std::move(entries)) | border; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | class Tab : public Component { | ||||||
|  |   public: | ||||||
|  |     Container main_container = Container::Vertical(); | ||||||
|  |  | ||||||
|  |     Toggle tab_selection; | ||||||
|  |     Container container = Container::Tab(&tab_selection.selected); | ||||||
|  |  | ||||||
|  |     HTopComponent htop; | ||||||
|  |     CompilerComponent compiler; | ||||||
|  |     SpinnerComponent spinner_component; | ||||||
|  |  | ||||||
|  |     Tab() { | ||||||
|  |       Add(&main_container); | ||||||
|  |       main_container.Add(&tab_selection); | ||||||
|  |       tab_selection.entries = { | ||||||
|  |         L"compiler", | ||||||
|  |         L"htop", | ||||||
|  |         L"spinner" | ||||||
|  |       }; | ||||||
|  |       main_container.Add(&container); | ||||||
|  |       container.Add(&compiler); | ||||||
|  |       container.Add(&htop); | ||||||
|  |       container.Add(&spinner_component); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     Element Render() override { | ||||||
|  |       return vbox( | ||||||
|  |         text(L"FTXUI Demo") | bold | hcenter, | ||||||
|  |         tab_selection.Render() | hcenter, | ||||||
|  |         container.Render() | ||||||
|  |       ); | ||||||
|  |     } | ||||||
|  | }; | ||||||
|  |  | ||||||
|  | int main(int argc, const char* argv[]) { | ||||||
|  |   auto screen = ScreenInteractive::Fullscreen(); | ||||||
|  |  | ||||||
|  |   std::thread update([&screen]() { | ||||||
|  |     for (;;) { | ||||||
|  |       using namespace std::chrono_literals; | ||||||
|  |       std::this_thread::sleep_for(0.05s); | ||||||
|  |       shift++; | ||||||
|  |       screen.PostEvent(Event::Custom); | ||||||
|  |     } | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   Tab tab; | ||||||
|  |   screen.Loop(&tab); | ||||||
|  |  | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
| @@ -1,13 +1,12 @@ | |||||||
| #include "ftxui/dom/elements.hpp" |  | ||||||
| #include "ftxui/dom/graph.hpp" |  | ||||||
| #include "ftxui/screen/screen.hpp" |  | ||||||
| #include "ftxui/screen/string.hpp" |  | ||||||
| #include <chrono> | #include <chrono> | ||||||
| #include <cmath> | #include <cmath> | ||||||
| #include <iostream> | #include <iostream> | ||||||
| #include <thread> | #include <thread> | ||||||
|  | #include "ftxui/dom/elements.hpp" | ||||||
|  | #include "ftxui/screen/screen.hpp" | ||||||
|  | #include "ftxui/screen/string.hpp" | ||||||
|  |  | ||||||
| class Graph : public ftxui::GraphFunction { | class Graph { | ||||||
|  public: |  public: | ||||||
|   std::vector<int> operator()(int width, int height) { |   std::vector<int> operator()(int width, int height) { | ||||||
|     std::vector<int> output(width); |     std::vector<int> output(width); | ||||||
| @@ -16,8 +15,6 @@ class Graph : public ftxui::GraphFunction { | |||||||
|       v += 0.1 * sin((i + shift) * 0.1); |       v += 0.1 * sin((i + shift) * 0.1); | ||||||
|       v += 0.2 * sin((i + shift+10) * 0.15); |       v += 0.2 * sin((i + shift+10) * 0.15); | ||||||
|       v += 0.1 * sin((i + shift) * 0.03); |       v += 0.1 * sin((i + shift) * 0.03); | ||||||
|       // v += 0.2*sin((i+shift)*0.3); |  | ||||||
|       // v += 0.1*sin((i+shift)*0.9); |  | ||||||
|       v *= height; |       v *= height; | ||||||
|       v += 0.5 * height; |       v += 0.5 * height; | ||||||
|       output[i] = v; |       output[i] = v; | ||||||
| @@ -27,6 +24,14 @@ class Graph : public ftxui::GraphFunction { | |||||||
|   int shift = 0; |   int shift = 0; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | std::vector<int> triangle(int width, int height) { | ||||||
|  |   std::vector<int> output(width); | ||||||
|  |   for (int i = 0; i < width; ++i) { | ||||||
|  |     output[i] = i % (height - 4) + 2; | ||||||
|  |   } | ||||||
|  |   return output; | ||||||
|  | } | ||||||
|  |  | ||||||
| int main(int argc, const char* argv[]) { | int main(int argc, const char* argv[]) { | ||||||
|   using namespace ftxui; |   using namespace ftxui; | ||||||
|   using namespace std::chrono_literals; |   using namespace std::chrono_literals; | ||||||
| @@ -36,20 +41,20 @@ int main(int argc, const char* argv[]) { | |||||||
|   std::string reset_position; |   std::string reset_position; | ||||||
|   for (int i = 0;; ++i) { |   for (int i = 0;; ++i) { | ||||||
|     auto document = |     auto document = | ||||||
|       window(text(L"Your graphs"), |       hbox( | ||||||
|         hbox( |         vbox( | ||||||
|           vbox( |           graph(std::ref(my_graph)), separator(), | ||||||
|             graph(my_graph), separator(), |           graph(triangle) | inverted | ||||||
|             graph(my_graph) | inverted |         ) | flex, | ||||||
|           ) | flex, |         separator(), | ||||||
|           separator(), |         vbox( | ||||||
|           vbox( |           graph(std::ref(my_graph)) | color(Color::BlueLight), separator(), | ||||||
|             graph(my_graph) | color(Color::BlueLight), separator(), |           graph(std::ref(my_graph)) | color(Color::RedLight), separator(), | ||||||
|             graph(my_graph) | color(Color::RedLight), separator(), |           graph(std::ref(my_graph)) | color(Color::YellowLight) | ||||||
|             graph(my_graph) | color(Color::YellowLight) |         ) | flex | ||||||
|           ) | flex |       ) | ||||||
|         ) |       | border | ||||||
|       ) | size(HEIGHT, GREATER_THAN, 40); |       | size(HEIGHT, GREATER_THAN, 40); | ||||||
|  |  | ||||||
|     auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); |     auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); | ||||||
|     Render(screen, document.get()); |     Render(screen, document.get()); | ||||||
|   | |||||||
| @@ -1,4 +1,5 @@ | |||||||
| cmake_minimum_required(VERSION 3.0) | cmake_minimum_required(VERSION 3.0) | ||||||
|  | find_package(Threads) | ||||||
|  |  | ||||||
| add_library(screen | add_library(screen | ||||||
|   src/ftxui/screen/box.cpp |   src/ftxui/screen/box.cpp | ||||||
| @@ -48,7 +49,7 @@ add_library(component | |||||||
|  |  | ||||||
| target_link_libraries(dom PUBLIC screen) | target_link_libraries(dom PUBLIC screen) | ||||||
| target_link_libraries(component PUBLIC dom) | target_link_libraries(component PUBLIC dom) | ||||||
|  | target_link_libraries(component PUBLIC Threads::Threads) | ||||||
|  |  | ||||||
| foreach(lib screen dom component) | foreach(lib screen dom component) | ||||||
|   target_include_directories(${lib} |   target_include_directories(${lib} | ||||||
| @@ -86,7 +87,6 @@ install(EXPORT ftxui-export | |||||||
| # Note: For gtest, please follow: | # Note: For gtest, please follow: | ||||||
| # https://stackoverflow.com/questions/24295876/cmake-cannot-find-a-googletest-required-library | # https://stackoverflow.com/questions/24295876/cmake-cannot-find-a-googletest-required-library | ||||||
| find_package(GTest) | find_package(GTest) | ||||||
| find_package(Threads) |  | ||||||
| if (GTEST_FOUND AND THREADS_FOUND) | if (GTEST_FOUND AND THREADS_FOUND) | ||||||
|   add_executable(dom_tests |   add_executable(dom_tests | ||||||
|     src/ftxui/dom/gauge_test.cpp |     src/ftxui/dom/gauge_test.cpp | ||||||
|   | |||||||
| @@ -24,10 +24,14 @@ struct Event{ | |||||||
|   static Event Escape; |   static Event Escape; | ||||||
|   static Event F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12; |   static Event F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12; | ||||||
|  |  | ||||||
|  |   // --- Custom --- | ||||||
|  |   static Event Custom; | ||||||
|  |  | ||||||
|   bool operator==(const Event& other) { return values == other.values; } |   bool operator==(const Event& other) { return values == other.values; } | ||||||
|  |  | ||||||
|   // Internal representation. |   // Internal representation. | ||||||
|   std::array<int, 5> values = {0, 0, 0, 0, 0}; |   std::array<int, 5> values = {0, 0, 0, 0, 0}; | ||||||
|  |    | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,9 +1,15 @@ | |||||||
| #ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP | #ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP | ||||||
| #define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP | #define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP | ||||||
|  |  | ||||||
| #include "ftxui/screen/screen.hpp" | #include <condition_variable> | ||||||
| #include <functional> | #include <functional> | ||||||
| #include <memory> | #include <memory> | ||||||
|  | #include <mutex> | ||||||
|  | #include <queue> | ||||||
|  | #include <atomic> | ||||||
|  |  | ||||||
|  | #include "ftxui/component/event.hpp" | ||||||
|  | #include "ftxui/screen/screen.hpp" | ||||||
|  |  | ||||||
| namespace ftxui { | namespace ftxui { | ||||||
| class Component; | class Component; | ||||||
| @@ -19,9 +25,11 @@ class ScreenInteractive : public Screen { | |||||||
|     void Loop(Component*); |     void Loop(Component*); | ||||||
|     std::function<void()> ExitLoopClosure(); |     std::function<void()> ExitLoopClosure(); | ||||||
|  |  | ||||||
|  |     void PostEvent(Event event); | ||||||
|  |  | ||||||
|   private: |   private: | ||||||
|    void Draw(Component* component); |    void Draw(Component* component); | ||||||
|    bool quit_ = false; |    void EventLoop(Component* component); | ||||||
|  |  | ||||||
|    enum class Dimension { |    enum class Dimension { | ||||||
|      FitComponent, |      FitComponent, | ||||||
| @@ -31,6 +39,11 @@ class ScreenInteractive : public Screen { | |||||||
|    }; |    }; | ||||||
|    Dimension dimension_ = Dimension::Fixed; |    Dimension dimension_ = Dimension::Fixed; | ||||||
|    ScreenInteractive(int dimx, int dimy, Dimension dimension); |    ScreenInteractive(int dimx, int dimy, Dimension dimension); | ||||||
|  |  | ||||||
|  |    std::condition_variable events_queue_wait; | ||||||
|  |    std::mutex events_queue_mutex; | ||||||
|  |    std::queue<Event> events_queue; | ||||||
|  |    std::atomic<bool> quit_ = false; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| }  // namespace ftxui | }  // namespace ftxui | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ | |||||||
|  |  | ||||||
| #include <functional> | #include <functional> | ||||||
|  |  | ||||||
| #include "ftxui/dom/graph.hpp" |  | ||||||
| #include "ftxui/dom/node.hpp" | #include "ftxui/dom/node.hpp" | ||||||
| #include "ftxui/screen/color.hpp" | #include "ftxui/screen/color.hpp" | ||||||
|  |  | ||||||
| @@ -12,16 +11,19 @@ namespace ftxui { | |||||||
| using Element = std::unique_ptr<Node>; | using Element = std::unique_ptr<Node>; | ||||||
| using Elements = std::vector<Element>; | using Elements = std::vector<Element>; | ||||||
| using Decorator = std::function<Element(Element)>; | using Decorator = std::function<Element(Element)>; | ||||||
|  | using GraphFunction = std::function<std::vector<int>(int,int)>; | ||||||
|  |  | ||||||
| // --- Widget --- | // --- Widget --- | ||||||
| Element text(std::wstring text); | Element text(std::wstring text); | ||||||
| Element separator(); | Element separator(); | ||||||
|  | Element separator(Pixel); | ||||||
| Element gauge(float ratio); | Element gauge(float ratio); | ||||||
| Element border(Element); | Element border(Element); | ||||||
|  | Decorator borderWith(Pixel); | ||||||
| Element window(Element title, Element content); | Element window(Element title, Element content); | ||||||
| Element spinner(int charset_index, size_t image_index); | Element spinner(int charset_index, size_t image_index); | ||||||
| Elements paragraph(std::wstring text); // Use inside hflow(). Split by space. | Elements paragraph(std::wstring text); // Use inside hflow(). Split by space. | ||||||
| Element graph(GraphFunction&); // See graph.hpp | Element graph(GraphFunction); | ||||||
|  |  | ||||||
| // -- Decorator --- | // -- Decorator --- | ||||||
| Element bold(Element); | Element bold(Element); | ||||||
| @@ -46,6 +48,7 @@ Element hflow(Elements); | |||||||
| // container. | // container. | ||||||
| Element filler(); | Element filler(); | ||||||
| Element flex(Element); | Element flex(Element); | ||||||
|  | Element notflex(Element); | ||||||
|  |  | ||||||
| // -- Size override; | // -- Size override; | ||||||
| enum Direction { WIDTH, HEIGHT }; | enum Direction { WIDTH, HEIGHT }; | ||||||
|   | |||||||
| @@ -1,15 +0,0 @@ | |||||||
| #ifndef FTXUI_DOM_GRAPH_HPP |  | ||||||
| #define FTXUI_DOM_GRAPH_HPP |  | ||||||
|  |  | ||||||
| #include "ftxui/dom/elements.hpp" |  | ||||||
|  |  | ||||||
| namespace ftxui { |  | ||||||
|  |  | ||||||
| class GraphFunction { |  | ||||||
|  public: |  | ||||||
|   virtual std::vector<int> operator()(int width, int height) = 0; |  | ||||||
| }; |  | ||||||
|  |  | ||||||
| } // namespace ftxui |  | ||||||
|  |  | ||||||
| #endif /* end of include guard: FTXUI_DOM_GRAPH_HPP */ |  | ||||||
| @@ -34,4 +34,6 @@ Event Event::F10{ESC, '[', '2', '1', '~'}; | |||||||
| Event Event::F11{ESC, '[', '2', '1', '~'};  // Same as F10 ? | Event Event::F11{ESC, '[', '2', '1', '~'};  // Same as F10 ? | ||||||
| Event Event::F12{ESC, '[', '2', '4', '~'}; | Event Event::F12{ESC, '[', '2', '4', '~'}; | ||||||
|  |  | ||||||
|  | Event Event::Custom{0, 0, 0, 0, 0}; | ||||||
|  |  | ||||||
| } // namespace ftxui | } // namespace ftxui | ||||||
|   | |||||||
| @@ -5,19 +5,21 @@ namespace ftxui { | |||||||
|  |  | ||||||
| // Component implementation. | // Component implementation. | ||||||
| Element Input::Render() { | Element Input::Render() { | ||||||
|  |   cursor_position = std::max(0, std::min<int>(content.size(), cursor_position)); | ||||||
|  |   auto main_decorator = flex | size(HEIGHT, EQUAL, 1); | ||||||
|   bool is_focused = Focused(); |   bool is_focused = Focused(); | ||||||
|  |  | ||||||
|   // Placeholder. |   // Placeholder. | ||||||
|   if (content.size() == 0) { |   if (content.size() == 0) { | ||||||
|     if (is_focused) |     if (is_focused) | ||||||
|       return text(placeholder) | dim | inverted | flex; |       return text(placeholder) | dim | inverted | main_decorator; | ||||||
|     else |     else | ||||||
|       return text(placeholder) | dim | flex; |       return text(placeholder) | dim | main_decorator; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Not focused. |   // Not focused. | ||||||
|   if (!is_focused) |   if (!is_focused) | ||||||
|     return text(content) | flex; |     return text(content) | main_decorator; | ||||||
|  |  | ||||||
|   std::wstring part_before_cursor = content.substr(0,cursor_position); |   std::wstring part_before_cursor = content.substr(0,cursor_position); | ||||||
|   std::wstring part_at_cursor = cursor_position < (int)content.size() |   std::wstring part_at_cursor = cursor_position < (int)content.size() | ||||||
| @@ -34,9 +36,11 @@ Element Input::Render() { | |||||||
|       text(part_before_cursor), |       text(part_before_cursor), | ||||||
|       text(part_at_cursor) | underlined | focused, |       text(part_at_cursor) | underlined | focused, | ||||||
|       text(part_after_cursor) |       text(part_after_cursor) | ||||||
|     ) | flex | inverted | frame; |     ) | flex | inverted | frame | main_decorator; | ||||||
|  |      | ||||||
| } | } | ||||||
| bool Input::OnEvent(Event event) { | bool Input::OnEvent(Event event) { | ||||||
|  |   cursor_position = std::max(0, std::min<int>(content.size(), cursor_position)); | ||||||
|   std::wstring c; |   std::wstring c; | ||||||
|  |  | ||||||
|   // Backspace. |   // Backspace. | ||||||
| @@ -50,9 +54,14 @@ bool Input::OnEvent(Event event) { | |||||||
|  |  | ||||||
|   // Enter. |   // Enter. | ||||||
|   if (event == Event::Return) { |   if (event == Event::Return) { | ||||||
|  |     on_enter(); | ||||||
|     return true; |     return true; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   if (event == Event::Custom) { | ||||||
|  |     return false; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   if (event == Event::ArrowLeft && cursor_position > 0) { |   if (event == Event::ArrowLeft && cursor_position > 0) { | ||||||
|     cursor_position--; |     cursor_position--; | ||||||
|     return true; |     return true; | ||||||
|   | |||||||
| @@ -6,6 +6,7 @@ | |||||||
| #include <iostream> | #include <iostream> | ||||||
| #include "ftxui/component/component.hpp" | #include "ftxui/component/component.hpp" | ||||||
| #include "ftxui/screen/terminal.hpp" | #include "ftxui/screen/terminal.hpp" | ||||||
|  | #include <thread> | ||||||
|  |  | ||||||
| namespace ftxui { | namespace ftxui { | ||||||
|  |  | ||||||
| @@ -70,6 +71,28 @@ ScreenInteractive ScreenInteractive::FitComponent() { | |||||||
|   return ScreenInteractive(0, 0, Dimension::FitComponent); |   return ScreenInteractive(0, 0, Dimension::FitComponent); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | void ScreenInteractive::PostEvent(Event event) {  | ||||||
|  |   std::unique_lock<std::mutex> lock(events_queue_mutex); | ||||||
|  |   events_queue.push(event); | ||||||
|  |   events_queue_wait.notify_one(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | void ScreenInteractive::EventLoop(Component* component) { | ||||||
|  |   bool handled = 0; | ||||||
|  |   for (;;) { | ||||||
|  |     std::unique_lock<std::mutex> lock(events_queue_mutex); | ||||||
|  |     while (!events_queue.empty()) { | ||||||
|  |       component->OnEvent(events_queue.front()); | ||||||
|  |       events_queue.pop(); | ||||||
|  |       handled = true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if (handled) | ||||||
|  |       return; | ||||||
|  |     events_queue_wait.wait(lock); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
| void ScreenInteractive::Loop(Component* component) { | void ScreenInteractive::Loop(Component* component) { | ||||||
|   //std::cout << "\033[?9h";    [> Send Mouse Row & Column on Button Press <] |   //std::cout << "\033[?9h";    [> Send Mouse Row & Column on Button Press <] | ||||||
|   //std::cout << "\033[?1000h"; [> Send Mouse X & Y on button press and release <] |   //std::cout << "\033[?1000h"; [> Send Mouse X & Y on button press and release <] | ||||||
| @@ -89,18 +112,25 @@ void ScreenInteractive::Loop(Component* component) { | |||||||
|   terminal_configuration_new.c_lflag &= ~ECHO; |   terminal_configuration_new.c_lflag &= ~ECHO; | ||||||
|   tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_new); |   tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_new); | ||||||
|  |  | ||||||
|  |   std::thread read_char([this]() { | ||||||
|  |     while (!quit_) | ||||||
|  |       PostEvent(GetEvent()); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|   std::string reset_position; |   std::string reset_position; | ||||||
|   while (!quit_) { |   while (!quit_) { | ||||||
|     reset_position = ResetPosition(); |     reset_position = ResetPosition(); | ||||||
|     Draw(component); |     Draw(component); | ||||||
|     std::cout << reset_position << ToString() << std::flush; |     std::cout << reset_position << ToString() << std::flush; | ||||||
|     Clear(); |     Clear(); | ||||||
|     component->OnEvent(GetEvent()); |     EventLoop(component); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   // Restore the old terminal configuration. |   // Restore the old terminal configuration. | ||||||
|   tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_old); |   tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_old); | ||||||
|  |  | ||||||
|  |   read_char.join(); | ||||||
|  |  | ||||||
|   std::cout << std::endl; |   std::cout << std::endl; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,13 +5,21 @@ namespace ftxui { | |||||||
|  |  | ||||||
| using namespace ftxui; | using namespace ftxui; | ||||||
|  |  | ||||||
| static wchar_t charset[] = L"┌┐└┘─│┬┴┤├"; | static wchar_t simple_border_charset[] = L"┌┐└┘─│┬┴┤├"; | ||||||
|  |  | ||||||
| class Border : public Node { | class Border : public Node { | ||||||
|  public: |  public: | ||||||
|   Border(Elements children) : Node(std::move(children)) {} |   Border(Elements children) | ||||||
|  |       : Node(std::move(children)), | ||||||
|  |         charset(std::begin(simple_border_charset), | ||||||
|  |                 std::end(simple_border_charset)) {} | ||||||
|  |   Border(Elements children, Pixel pixel) | ||||||
|  |       : Node(std::move(children)), charset_pixel(10, pixel) {} | ||||||
|   ~Border() override {} |   ~Border() override {} | ||||||
|  |  | ||||||
|  |   std::vector<Pixel> charset_pixel;  | ||||||
|  |   std::vector<wchar_t> charset; | ||||||
|  |  | ||||||
|   void ComputeRequirement() override { |   void ComputeRequirement() override { | ||||||
|     Node::ComputeRequirement(); |     Node::ComputeRequirement(); | ||||||
|     requirement_ = children[0]->requirement(); |     requirement_ = children[0]->requirement(); | ||||||
| @@ -52,6 +60,13 @@ class Border : public Node { | |||||||
|     if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) |     if (box_.x_min >= box_.x_max || box_.y_min >= box_.y_max) | ||||||
|       return; |       return; | ||||||
|  |  | ||||||
|  |     if (!charset.empty()) | ||||||
|  |       RenderPixel(screen); | ||||||
|  |     else | ||||||
|  |       RenderChar(screen); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void RenderPixel(Screen& screen) { | ||||||
|     screen.at(box_.x_min, box_.y_min) = charset[0]; |     screen.at(box_.x_min, box_.y_min) = charset[0]; | ||||||
|     screen.at(box_.x_max, box_.y_min) = charset[1]; |     screen.at(box_.x_max, box_.y_min) = charset[1]; | ||||||
|     screen.at(box_.x_min, box_.y_max) = charset[2]; |     screen.at(box_.x_min, box_.y_max) = charset[2]; | ||||||
| @@ -69,6 +84,21 @@ class Border : public Node { | |||||||
|     if (children.size() == 2) |     if (children.size() == 2) | ||||||
|       children[1]->Render(screen); |       children[1]->Render(screen); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   void RenderChar(Screen& screen) { | ||||||
|  |     screen.PixelAt(box_.x_min, box_.y_min) = charset_pixel[0]; | ||||||
|  |     screen.PixelAt(box_.x_max, box_.y_min) = charset_pixel[1]; | ||||||
|  |     screen.PixelAt(box_.x_min, box_.y_max) = charset_pixel[2]; | ||||||
|  |     screen.PixelAt(box_.x_max, box_.y_max) = charset_pixel[3]; | ||||||
|  |     for(float x = box_.x_min + 1; x<box_.x_max; ++x) { | ||||||
|  |       screen.PixelAt(x, box_.y_min) = charset_pixel[4]; | ||||||
|  |       screen.PixelAt(x, box_.y_max) = charset_pixel[4]; | ||||||
|  |     } | ||||||
|  |     for(float y = box_.y_min + 1; y<box_.y_max; ++y) { | ||||||
|  |       screen.PixelAt(box_.x_min, y) = charset_pixel[5]; | ||||||
|  |       screen.PixelAt(box_.x_max,y) = charset_pixel[5]; | ||||||
|  |     } | ||||||
|  |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Node> border(Element child) { | std::unique_ptr<Node> border(Element child) { | ||||||
| @@ -79,9 +109,9 @@ std::unique_ptr<Node> window(Element title, Element content) { | |||||||
|   return std::make_unique<Border>(unpack(std::move(content), std::move(title))); |   return std::make_unique<Border>(unpack(std::move(content), std::move(title))); | ||||||
| } | } | ||||||
|  |  | ||||||
| Decorator boxed() { | Decorator borderWith(Pixel pixel) { | ||||||
|   return [](Element child) { |   return [pixel](Element child) { | ||||||
|     return border(std::move(child)); |     return std::make_unique<Border>(unpack(std::move(child)), pixel); | ||||||
|   }; |   }; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ class Flex : public Node { | |||||||
|   Flex() {} |   Flex() {} | ||||||
|   Flex(Element child) : Node(unpack(std::move(child))) {} |   Flex(Element child) : Node(unpack(std::move(child))) {} | ||||||
|   ~Flex() override {} |   ~Flex() override {} | ||||||
|   void ComputeRequirement() { |   void ComputeRequirement() override { | ||||||
|     requirement_.min.x = 0; |     requirement_.min.x = 0; | ||||||
|     requirement_.min.y = 0; |     requirement_.min.y = 0; | ||||||
|     if (!children.empty()) { |     if (!children.empty()) { | ||||||
| @@ -26,6 +26,23 @@ class Flex : public Node { | |||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | class NotFlex : public Flex { | ||||||
|  |  public: | ||||||
|  |   NotFlex() {} | ||||||
|  |   NotFlex(Element child) : Flex(std::move(child)) {} | ||||||
|  |   ~NotFlex() override {} | ||||||
|  |   void ComputeRequirement() override { | ||||||
|  |     requirement_.min.x = 0; | ||||||
|  |     requirement_.min.y = 0; | ||||||
|  |     if (!children.empty()) { | ||||||
|  |       children[0]->ComputeRequirement(); | ||||||
|  |       requirement_ = children[0]->requirement(); | ||||||
|  |     } | ||||||
|  |     requirement_.flex.x = 0; | ||||||
|  |     requirement_.flex.y = 0; | ||||||
|  |   } | ||||||
|  | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Node> filler() { | std::unique_ptr<Node> filler() { | ||||||
|   return std::make_unique<Flex>(); |   return std::make_unique<Flex>(); | ||||||
| } | } | ||||||
| @@ -34,4 +51,8 @@ std::unique_ptr<Node> flex(Element child) { | |||||||
|   return std::make_unique<Flex>(std::move(child)); |   return std::make_unique<Flex>(std::move(child)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | std::unique_ptr<Node> notflex(Element child) { | ||||||
|  |   return std::make_unique<NotFlex>(std::move(child)); | ||||||
|  | } | ||||||
|  |  | ||||||
| };  // namespace ftxui | };  // namespace ftxui | ||||||
|   | |||||||
| @@ -6,7 +6,7 @@ const wchar_t charset[] = L" ▗▐▖▄▟▌▙█"; | |||||||
|  |  | ||||||
| class Graph : public Node { | class Graph : public Node { | ||||||
|  public: |  public: | ||||||
|   Graph(GraphFunction& graph_function) : graph_function_(graph_function) {} |   Graph(GraphFunction graph_function) : graph_function_(graph_function) {} | ||||||
|   ~Graph() override {} |   ~Graph() override {} | ||||||
|  |  | ||||||
|   void ComputeRequirement() override { |   void ComputeRequirement() override { | ||||||
| @@ -35,10 +35,10 @@ class Graph : public Node { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|  private: |  private: | ||||||
|   GraphFunction& graph_function_; |   GraphFunction graph_function_; | ||||||
| }; | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Node> graph(GraphFunction& graph_function) { | std::unique_ptr<Node> graph(GraphFunction graph_function) { | ||||||
|   return std::make_unique<Graph>(graph_function); |   return std::make_unique<Graph>(graph_function); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -23,16 +23,34 @@ class Separator : public Node { | |||||||
|     else |     else | ||||||
|       c = U'│'; |       c = U'│'; | ||||||
|  |  | ||||||
|  |     Pixel p; | ||||||
|  |     p.character = c; | ||||||
|  |     RenderWithPixel(screen, p); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   void RenderWithPixel(Screen& screen, Pixel pixel) { | ||||||
|     for (int y = box_.y_min; y <= box_.y_max; ++y) { |     for (int y = box_.y_min; y <= box_.y_max; ++y) { | ||||||
|       for (int x = box_.x_min; x <= box_.x_max; ++x) { |       for (int x = box_.x_min; x <= box_.x_max; ++x) { | ||||||
|         screen.at(x, y) = c; |         screen.PixelAt(x, y) = pixel; | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | class SeparatorWithPixel : public Separator { | ||||||
|  |  public: | ||||||
|  |   SeparatorWithPixel(Pixel p) : p(p) {} | ||||||
|  |   ~SeparatorWithPixel() override {} | ||||||
|  |   void Render(Screen& screen) override { RenderWithPixel(screen, p); } | ||||||
|  |   Pixel p; | ||||||
|  | }; | ||||||
|  |  | ||||||
| std::unique_ptr<Node> separator() { | std::unique_ptr<Node> separator() { | ||||||
|   return std::make_unique<Separator>(); |   return std::make_unique<Separator>(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | std::unique_ptr<Node> separator(Pixel pixel) { | ||||||
|  |   return std::make_unique<SeparatorWithPixel>(pixel); | ||||||
|  | } | ||||||
|  |  | ||||||
| };  // namespace ftxui | };  // namespace ftxui | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 ArthurSonzogni
					ArthurSonzogni