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_vertical) | ||||
| 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 <cmath> | ||||
| #include <iostream> | ||||
| #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: | ||||
|   std::vector<int> operator()(int width, int height) { | ||||
|     std::vector<int> output(width); | ||||
| @@ -16,8 +15,6 @@ class Graph : public ftxui::GraphFunction { | ||||
|       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 += 0.2*sin((i+shift)*0.3); | ||||
|       // v += 0.1*sin((i+shift)*0.9); | ||||
|       v *= height; | ||||
|       v += 0.5 * height; | ||||
|       output[i] = v; | ||||
| @@ -27,6 +24,14 @@ class Graph : public ftxui::GraphFunction { | ||||
|   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[]) { | ||||
|   using namespace ftxui; | ||||
|   using namespace std::chrono_literals; | ||||
| @@ -36,20 +41,20 @@ int main(int argc, const char* argv[]) { | ||||
|   std::string reset_position; | ||||
|   for (int i = 0;; ++i) { | ||||
|     auto document = | ||||
|       window(text(L"Your graphs"), | ||||
|         hbox( | ||||
|           vbox( | ||||
|             graph(my_graph), separator(), | ||||
|             graph(my_graph) | inverted | ||||
|           ) | flex, | ||||
|           separator(), | ||||
|           vbox( | ||||
|             graph(my_graph) | color(Color::BlueLight), separator(), | ||||
|             graph(my_graph) | color(Color::RedLight), separator(), | ||||
|             graph(my_graph) | color(Color::YellowLight) | ||||
|           ) | flex | ||||
|         ) | ||||
|       ) | size(HEIGHT, GREATER_THAN, 40); | ||||
|       hbox( | ||||
|         vbox( | ||||
|           graph(std::ref(my_graph)), separator(), | ||||
|           graph(triangle) | inverted | ||||
|         ) | flex, | ||||
|         separator(), | ||||
|         vbox( | ||||
|           graph(std::ref(my_graph)) | color(Color::BlueLight), separator(), | ||||
|           graph(std::ref(my_graph)) | color(Color::RedLight), separator(), | ||||
|           graph(std::ref(my_graph)) | color(Color::YellowLight) | ||||
|         ) | flex | ||||
|       ) | ||||
|       | border | ||||
|       | size(HEIGHT, GREATER_THAN, 40); | ||||
|  | ||||
|     auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); | ||||
|     Render(screen, document.get()); | ||||
|   | ||||
| @@ -1,4 +1,5 @@ | ||||
| cmake_minimum_required(VERSION 3.0) | ||||
| find_package(Threads) | ||||
|  | ||||
| add_library(screen | ||||
|   src/ftxui/screen/box.cpp | ||||
| @@ -48,7 +49,7 @@ add_library(component | ||||
|  | ||||
| target_link_libraries(dom PUBLIC screen) | ||||
| target_link_libraries(component PUBLIC dom) | ||||
|  | ||||
| target_link_libraries(component PUBLIC Threads::Threads) | ||||
|  | ||||
| foreach(lib screen dom component) | ||||
|   target_include_directories(${lib} | ||||
| @@ -86,7 +87,6 @@ install(EXPORT ftxui-export | ||||
| # Note: For gtest, please follow: | ||||
| # https://stackoverflow.com/questions/24295876/cmake-cannot-find-a-googletest-required-library | ||||
| find_package(GTest) | ||||
| find_package(Threads) | ||||
| if (GTEST_FOUND AND THREADS_FOUND) | ||||
|   add_executable(dom_tests | ||||
|     src/ftxui/dom/gauge_test.cpp | ||||
|   | ||||
| @@ -24,10 +24,14 @@ struct Event{ | ||||
|   static Event Escape; | ||||
|   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; } | ||||
|  | ||||
|   // Internal representation. | ||||
|   std::array<int, 5> values = {0, 0, 0, 0, 0}; | ||||
|    | ||||
| }; | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -1,9 +1,15 @@ | ||||
| #ifndef FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP | ||||
| #define FTXUI_COMPONENT_SCREEN_INTERACTIVE_HPP | ||||
|  | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include <condition_variable> | ||||
| #include <functional> | ||||
| #include <memory> | ||||
| #include <mutex> | ||||
| #include <queue> | ||||
| #include <atomic> | ||||
|  | ||||
| #include "ftxui/component/event.hpp" | ||||
| #include "ftxui/screen/screen.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
| class Component; | ||||
| @@ -19,9 +25,11 @@ class ScreenInteractive : public Screen { | ||||
|     void Loop(Component*); | ||||
|     std::function<void()> ExitLoopClosure(); | ||||
|  | ||||
|     void PostEvent(Event event); | ||||
|  | ||||
|   private: | ||||
|    void Draw(Component* component); | ||||
|    bool quit_ = false; | ||||
|    void EventLoop(Component* component); | ||||
|  | ||||
|    enum class Dimension { | ||||
|      FitComponent, | ||||
| @@ -31,6 +39,11 @@ class ScreenInteractive : public Screen { | ||||
|    }; | ||||
|    Dimension dimension_ = Dimension::Fixed; | ||||
|    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 | ||||
|   | ||||
| @@ -3,7 +3,6 @@ | ||||
|  | ||||
| #include <functional> | ||||
|  | ||||
| #include "ftxui/dom/graph.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/screen/color.hpp" | ||||
|  | ||||
| @@ -12,16 +11,19 @@ namespace ftxui { | ||||
| using Element = std::unique_ptr<Node>; | ||||
| using Elements = std::vector<Element>; | ||||
| using Decorator = std::function<Element(Element)>; | ||||
| using GraphFunction = std::function<std::vector<int>(int,int)>; | ||||
|  | ||||
| // --- Widget --- | ||||
| Element text(std::wstring text); | ||||
| Element separator(); | ||||
| Element separator(Pixel); | ||||
| Element gauge(float ratio); | ||||
| Element border(Element); | ||||
| Decorator borderWith(Pixel); | ||||
| Element window(Element title, Element content); | ||||
| Element spinner(int charset_index, size_t image_index); | ||||
| Elements paragraph(std::wstring text); // Use inside hflow(). Split by space. | ||||
| Element graph(GraphFunction&); // See graph.hpp | ||||
| Element graph(GraphFunction); | ||||
|  | ||||
| // -- Decorator --- | ||||
| Element bold(Element); | ||||
| @@ -46,6 +48,7 @@ Element hflow(Elements); | ||||
| // container. | ||||
| Element filler(); | ||||
| Element flex(Element); | ||||
| Element notflex(Element); | ||||
|  | ||||
| // -- Size override; | ||||
| 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::F12{ESC, '[', '2', '4', '~'}; | ||||
|  | ||||
| Event Event::Custom{0, 0, 0, 0, 0}; | ||||
|  | ||||
| } // namespace ftxui | ||||
|   | ||||
| @@ -5,19 +5,21 @@ namespace ftxui { | ||||
|  | ||||
| // Component implementation. | ||||
| 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(); | ||||
|  | ||||
|   // Placeholder. | ||||
|   if (content.size() == 0) { | ||||
|     if (is_focused) | ||||
|       return text(placeholder) | dim | inverted | flex; | ||||
|       return text(placeholder) | dim | inverted | main_decorator; | ||||
|     else | ||||
|       return text(placeholder) | dim | flex; | ||||
|       return text(placeholder) | dim | main_decorator; | ||||
|   } | ||||
|  | ||||
|   // Not 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_at_cursor = cursor_position < (int)content.size() | ||||
| @@ -34,9 +36,11 @@ Element Input::Render() { | ||||
|       text(part_before_cursor), | ||||
|       text(part_at_cursor) | underlined | focused, | ||||
|       text(part_after_cursor) | ||||
|     ) | flex | inverted | frame; | ||||
|     ) | flex | inverted | frame | main_decorator; | ||||
|      | ||||
| } | ||||
| bool Input::OnEvent(Event event) { | ||||
|   cursor_position = std::max(0, std::min<int>(content.size(), cursor_position)); | ||||
|   std::wstring c; | ||||
|  | ||||
|   // Backspace. | ||||
| @@ -50,9 +54,14 @@ bool Input::OnEvent(Event event) { | ||||
|  | ||||
|   // Enter. | ||||
|   if (event == Event::Return) { | ||||
|     on_enter(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   if (event == Event::Custom) { | ||||
|     return false; | ||||
|   } | ||||
|  | ||||
|   if (event == Event::ArrowLeft && cursor_position > 0) { | ||||
|     cursor_position--; | ||||
|     return true; | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
| #include <iostream> | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/screen/terminal.hpp" | ||||
| #include <thread> | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| @@ -70,6 +71,28 @@ ScreenInteractive ScreenInteractive::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) { | ||||
|   //std::cout << "\033[?9h";    [> Send Mouse Row & Column on Button Press <] | ||||
|   //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; | ||||
|   tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_new); | ||||
|  | ||||
|   std::thread read_char([this]() { | ||||
|     while (!quit_) | ||||
|       PostEvent(GetEvent()); | ||||
|   }); | ||||
|  | ||||
|   std::string reset_position; | ||||
|   while (!quit_) { | ||||
|     reset_position = ResetPosition(); | ||||
|     Draw(component); | ||||
|     std::cout << reset_position << ToString() << std::flush; | ||||
|     Clear(); | ||||
|     component->OnEvent(GetEvent()); | ||||
|     EventLoop(component); | ||||
|   } | ||||
|  | ||||
|   // Restore the old terminal configuration. | ||||
|   tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_old); | ||||
|  | ||||
|   read_char.join(); | ||||
|  | ||||
|   std::cout << std::endl; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -5,13 +5,21 @@ namespace ftxui { | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| static wchar_t charset[] = L"┌┐└┘─│┬┴┤├"; | ||||
| static wchar_t simple_border_charset[] = L"┌┐└┘─│┬┴┤├"; | ||||
|  | ||||
| class Border : public Node { | ||||
|  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 {} | ||||
|  | ||||
|   std::vector<Pixel> charset_pixel;  | ||||
|   std::vector<wchar_t> charset; | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
|     Node::ComputeRequirement(); | ||||
|     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) | ||||
|       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_max, box_.y_min) = charset[1]; | ||||
|     screen.at(box_.x_min, box_.y_max) = charset[2]; | ||||
| @@ -69,6 +84,21 @@ class Border : public Node { | ||||
|     if (children.size() == 2) | ||||
|       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) { | ||||
| @@ -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))); | ||||
| } | ||||
|  | ||||
| Decorator boxed() { | ||||
|   return [](Element child) { | ||||
|     return border(std::move(child)); | ||||
| Decorator borderWith(Pixel pixel) { | ||||
|   return [pixel](Element child) { | ||||
|     return std::make_unique<Border>(unpack(std::move(child)), pixel); | ||||
|   }; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -8,7 +8,7 @@ class Flex : public Node { | ||||
|   Flex() {} | ||||
|   Flex(Element child) : Node(unpack(std::move(child))) {} | ||||
|   ~Flex() override {} | ||||
|   void ComputeRequirement() { | ||||
|   void ComputeRequirement() override { | ||||
|     requirement_.min.x = 0; | ||||
|     requirement_.min.y = 0; | ||||
|     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() { | ||||
|   return std::make_unique<Flex>(); | ||||
| } | ||||
| @@ -34,4 +51,8 @@ std::unique_ptr<Node> flex(Element 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 | ||||
|   | ||||
| @@ -6,7 +6,7 @@ const wchar_t charset[] = L" ▗▐▖▄▟▌▙█"; | ||||
|  | ||||
| class Graph : public Node { | ||||
|  public: | ||||
|   Graph(GraphFunction& graph_function) : graph_function_(graph_function) {} | ||||
|   Graph(GraphFunction graph_function) : graph_function_(graph_function) {} | ||||
|   ~Graph() override {} | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
| @@ -35,10 +35,10 @@ class Graph : public Node { | ||||
|   } | ||||
|  | ||||
|  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); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -23,16 +23,34 @@ class Separator : public Node { | ||||
|     else | ||||
|       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 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() { | ||||
|   return std::make_unique<Separator>(); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Node> separator(Pixel pixel) { | ||||
|   return std::make_unique<SeparatorWithPixel>(pixel); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ArthurSonzogni
					ArthurSonzogni