mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-11-01 02:58:12 +08:00 
			
		
		
		
	
							
								
								
									
										23
									
								
								src/ftxui/component/checkbox.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/ftxui/component/checkbox.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| #include "ftxui/component/checkbox.hpp" | ||||
| #include <functional> | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Element CheckBox::Render() { | ||||
|   bool is_focused = Focused(); | ||||
|   auto style = is_focused ? focused_style : unfocused_style; | ||||
|   auto focus_management = is_focused ? focus : state ? select : nothing; | ||||
|   return hbox(text(state ? checked : unchecked), | ||||
|               text(label) | style | focus_management); | ||||
| } | ||||
|  | ||||
| bool CheckBox::OnEvent(Event event) { | ||||
|   if (event == Event::Character(' ') || event == Event::Return) { | ||||
|     state = !state; | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
|   return false;   | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui | ||||
							
								
								
									
										56
									
								
								src/ftxui/component/component.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/ftxui/component/component.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include <assert.h> | ||||
|  | ||||
| namespace ftxui { | ||||
| void Component::Detach() { if (!parent_) return; auto it = std::find(std::begin(parent_->children_), | ||||
|                       std::end(parent_->children_), this); | ||||
|   parent_->children_.erase(it); | ||||
|  | ||||
| } | ||||
|  | ||||
| void Component::Attach(Component* parent) { | ||||
|   Detach(); | ||||
|   parent_ = parent; | ||||
|   parent_->children_.push_back(this); | ||||
| } | ||||
|  | ||||
| void Component::Add(Component* child) { | ||||
|   child->Attach(this); | ||||
| } | ||||
|  | ||||
| Component::~Component() { | ||||
|   Detach(); | ||||
| } | ||||
|  | ||||
| bool Component::OnEvent(Event event) { | ||||
|   for(Component* child : children_) { | ||||
|     if (child->OnEvent(event)) | ||||
|       return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| Component* Component::ActiveChild() { | ||||
|   return children_.empty() ? nullptr : children_.front(); | ||||
| } | ||||
|  | ||||
| Element Component::Render() { | ||||
|   if (children_.size() == 1) | ||||
|     return children_.front()->Render(); | ||||
|  | ||||
|   return text(L"Not implemented component"); | ||||
| } | ||||
|  | ||||
| bool Component::Focused() { | ||||
|   Component* current = this; | ||||
|   for(;;) { | ||||
|     Component* parent = current->parent_; | ||||
|     if (!parent) | ||||
|       return true; | ||||
|     if (parent->ActiveChild() != current) | ||||
|       return false; | ||||
|     current = parent; | ||||
|   } | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui | ||||
							
								
								
									
										108
									
								
								src/ftxui/component/container.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										108
									
								
								src/ftxui/component/container.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,108 @@ | ||||
| #include "ftxui/component/container.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| // static | ||||
| Container Container::Horizontal() { | ||||
|   Container container; | ||||
|   container.event_handler_ = &Container::HorizontalEvent; | ||||
|   container.render_handler_ = &Container::HorizontalRender; | ||||
|   return container; | ||||
| } | ||||
|  | ||||
| // static | ||||
| Container Container::Vertical() { | ||||
|   Container container; | ||||
|   container.event_handler_ = &Container::VerticalEvent; | ||||
|   container.render_handler_ = &Container::VerticalRender; | ||||
|   return container; | ||||
| } | ||||
|  | ||||
| // static | ||||
| Container Container::Tab(int* selector) { | ||||
|   Container container; | ||||
|   container.event_handler_ = &Container::TabEvent; | ||||
|   container.render_handler_ = &Container::TabRender; | ||||
|   container.selector_ = selector; | ||||
|   return container; | ||||
| } | ||||
|  | ||||
| bool Container::OnEvent(Event event) { | ||||
|   if (!Focused()) | ||||
|     return false; | ||||
|  | ||||
|   if (ActiveChild()->OnEvent(event)) | ||||
|     return true; | ||||
|  | ||||
|   return (this->*event_handler_)(event); | ||||
| } | ||||
|  | ||||
| Component* Container::ActiveChild() { | ||||
|   return children_[*selector_ % children_.size()]; | ||||
| } | ||||
|  | ||||
| bool Container::VerticalEvent(Event event) { | ||||
|   selected_ %= children_.size(); | ||||
|   // Left pressed ? | ||||
|   if (event == Event::ArrowUp || event == Event::Character('k')) { | ||||
|     if (selected_ != 0) { | ||||
|       selected_--; | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Left pressed ? | ||||
|   if (event == Event::ArrowDown || event == Event::Character('j')) { | ||||
|     if (selected_ != int(children_.size()) - 1) { | ||||
|       selected_++; | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| bool Container::HorizontalEvent(Event event) { | ||||
|   selected_ %= children_.size(); | ||||
|   // Left pressed ? | ||||
|   if (event == Event::ArrowLeft || event == Event::Character('h')) { | ||||
|     if (selected_ != 0) { | ||||
|       selected_--; | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   // Left pressed ? | ||||
|   if (event == Event::ArrowRight || event == Event::Character('l')) { | ||||
|     if (selected_ != int(children_.size()) - 1) { | ||||
|       selected_++; | ||||
|       return true; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| Element Container::Render() { | ||||
|   return (this->*render_handler_)(); | ||||
| } | ||||
|  | ||||
| Element Container::VerticalRender() { | ||||
|   Elements elements; | ||||
|   for(auto& it : children_) | ||||
|     elements.push_back(it->Render()); | ||||
|   return vbox(std::move(elements)); | ||||
| } | ||||
|  | ||||
| Element Container::HorizontalRender() { | ||||
|   Elements elements; | ||||
|   for(auto& it : children_) | ||||
|     elements.push_back(it->Render()); | ||||
|   return hbox(std::move(elements)); | ||||
| } | ||||
|  | ||||
| Element Container::TabRender() { | ||||
|   return ActiveChild()->Render(); | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui | ||||
							
								
								
									
										39
									
								
								src/ftxui/component/event.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/ftxui/component/event.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| #include "ftxui/component/event.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| constexpr int ESC = int(27); | ||||
|  | ||||
| // --- Character --- | ||||
| Event Event::Character(int c) { | ||||
|   return Event{c}; | ||||
| } | ||||
|  | ||||
| // --- Arrow --- | ||||
| Event Event::ArrowLeft{ESC, '[', 'D'}; | ||||
| Event Event::ArrowRight{ESC, '[', 'C'}; | ||||
| Event Event::ArrowUp{ESC, '[', 'A'}; | ||||
| Event Event::ArrowDown{ESC, '[', 'B'}; | ||||
|  | ||||
| // --- Other --- | ||||
| Event Event::Backspace{127}; | ||||
| Event Event::Delete{ESC, '[', '3', '~'}; | ||||
| Event Event::Escape{ESC}; | ||||
| Event Event::Return{10}; | ||||
|  | ||||
| Event Event::F1{ESC, '[', 'O', 'P'}; | ||||
| Event Event::F2{ESC, '[', 'O', 'Q'}; | ||||
| Event Event::F3{ESC, '[', 'O', 'R'}; | ||||
| Event Event::F4{ESC, '[', 'O', 'S'}; | ||||
| Event Event::F5{ESC, '[', '1', '5', '~'}; | ||||
| Event Event::F6{ESC, '[', '1', '7', '~'}; | ||||
| Event Event::F7{ESC, '[', '1', '8', '~'}; | ||||
| Event Event::F8{ESC, '[', '1', '9', '~'}; | ||||
| Event Event::F9{ESC, '[', '2', '0', '~'}; | ||||
| 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 | ||||
							
								
								
									
										86
									
								
								src/ftxui/component/input.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/ftxui/component/input.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| #include "ftxui/component/input.hpp" | ||||
| #include "ftxui/screen/string.hpp" | ||||
|  | ||||
| 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 | main_decorator; | ||||
|     else | ||||
|       return text(placeholder) | dim | main_decorator; | ||||
|   } | ||||
|  | ||||
|   // Not focused. | ||||
|   if (!is_focused) | ||||
|     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() | ||||
|                                     ? content.substr(cursor_position, 1) | ||||
|                                     : L" "; | ||||
|   std::wstring part_after_cursor = cursor_position < (int)content.size() - 1 | ||||
|                                        ? content.substr(cursor_position + 1) | ||||
|                                        : L""; | ||||
|   auto focused =  | ||||
|     is_focused ? focus : select; | ||||
|  | ||||
|   return | ||||
|     hbox( | ||||
|       text(part_before_cursor), | ||||
|       text(part_at_cursor) | underlined | focused, | ||||
|       text(part_after_cursor) | ||||
|     ) | 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. | ||||
|   if (event == Event::Backspace) { | ||||
|     if (cursor_position == 0) | ||||
|       return false; | ||||
|     content.erase(cursor_position - 1, 1); | ||||
|     cursor_position--; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // 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; | ||||
|   } | ||||
|  | ||||
|   if (event == Event::ArrowRight && cursor_position < (int)content.size()) { | ||||
|     cursor_position++; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   // Content | ||||
|   constexpr char ESC = char(27); | ||||
|   if (event.values[0] != ESC) { | ||||
|     wchar_t v = (char)event.values[0]; | ||||
|     content.insert(cursor_position, 1, v); | ||||
|     cursor_position++; | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui | ||||
							
								
								
									
										46
									
								
								src/ftxui/component/menu.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/ftxui/component/menu.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| #include "ftxui/component/menu.hpp" | ||||
| #include <algorithm> | ||||
| #include <iostream> | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Element Menu::Render() { | ||||
|   std::vector<Element> elements; | ||||
|   bool is_focused = Focused(); | ||||
|   for (size_t i = 0; i < entries.size(); ++i) { | ||||
|     auto style = (selected != int(i)) | ||||
|                      ? normal_style | ||||
|                      : is_focused ? focused_style : selected_style; | ||||
|     auto focused = (selected != int(i)) ? nothing : is_focused ? focus : select; | ||||
|     auto icon = (selected != int(i)) ? L"  " : L"> "; | ||||
|     elements.push_back(text(icon + entries[i]) | style | focused); | ||||
|   } | ||||
|   return vbox(std::move(elements)); | ||||
| } | ||||
|  | ||||
| bool Menu::OnEvent(Event event) { | ||||
|   if (!Focused()) | ||||
|     return false; | ||||
|  | ||||
|   int new_selected = selected; | ||||
|   if (event == Event::ArrowUp || event == Event::Character('k')) | ||||
|     new_selected--; | ||||
|   if (event == Event::ArrowDown || event == Event::Character('j')) | ||||
|     new_selected++; | ||||
|   new_selected = std::max(0, std::min(int(entries.size()) - 1, new_selected)); | ||||
|  | ||||
|   if (selected != new_selected) { | ||||
|     selected = new_selected; | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   if (event == Event::Return) { | ||||
|     on_enter(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui | ||||
							
								
								
									
										45
									
								
								src/ftxui/component/radiobox.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/ftxui/component/radiobox.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| #include "ftxui/component/radiobox.hpp" | ||||
| #include <functional> | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Element RadioBox::Render() { | ||||
|   std::vector<Element> elements; | ||||
|   bool is_focused = Focused(); | ||||
|   for (size_t i = 0; i < entries.size(); ++i) { | ||||
|     auto style = | ||||
|         (focused == int(i) && is_focused) ? focused_style : unfocused_style; | ||||
|     auto focus_management = | ||||
|         (focused != int(i)) ? nothing : is_focused ? focus : select; | ||||
|  | ||||
|     const std::wstring& symbol = selected == int(i) ? checked : unchecked; | ||||
|     elements.push_back(hbox(text(symbol), text(entries[i]) | style) | | ||||
|                        focus_management); | ||||
|   } | ||||
|   return vbox(std::move(elements)); | ||||
| } | ||||
|  | ||||
| bool RadioBox::OnEvent(Event event) { | ||||
|   if (!Focused()) | ||||
|     return false; | ||||
|  | ||||
|   int new_focused = focused; | ||||
|   if (event == Event::ArrowUp || event == Event::Character('k')) | ||||
|     new_focused--; | ||||
|   if (event == Event::ArrowDown || event == Event::Character('j')) | ||||
|     new_focused++; | ||||
|   new_focused = std::max(0, std::min(int(entries.size()) - 1, new_focused)); | ||||
|   if (focused != new_focused) { | ||||
|     focused = new_focused; | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   if (event == Event::Character(' ') || event==Event::Return) { | ||||
|     selected = focused; | ||||
|     on_change(); | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui | ||||
							
								
								
									
										177
									
								
								src/ftxui/component/screen_interactive.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										177
									
								
								src/ftxui/component/screen_interactive.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,177 @@ | ||||
| #include "ftxui/component/screen_interactive.hpp" | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <termios.h> | ||||
| #include <unistd.h> | ||||
| #include <iostream> | ||||
| #include "ftxui/component/component.hpp" | ||||
| #include "ftxui/screen/terminal.hpp" | ||||
| #include <thread> | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| namespace { | ||||
| constexpr int ESC = 27; | ||||
| constexpr int WAT = 195; | ||||
| constexpr int WAT2 = 194; | ||||
| constexpr int WATWAIT = 91; | ||||
|  | ||||
| Event GetEvent() { | ||||
|   int v1 = getchar(); | ||||
|   if (v1 == ESC) { | ||||
|     int v2 = getchar(); | ||||
|     int v3 = getchar(); | ||||
|  | ||||
|     // if (v2 == WATWAIT) { | ||||
|     // int v4 = getchar(); | ||||
|     // int v5 = getchar(); | ||||
|     // return Event{v1, v2, v3, v4, v5}; | ||||
|     //} | ||||
|     return Event{v1, v2, v3}; | ||||
|   } | ||||
|  | ||||
|   if (v1 == WAT) { | ||||
|     int v2 = getchar(); | ||||
|     return Event{v1, v2}; | ||||
|   } | ||||
|  | ||||
|   if (v1 == WAT2) { | ||||
|     int v2 = getchar(); | ||||
|     return Event{v1, v2}; | ||||
|   } | ||||
|  | ||||
|   return Event{v1}; | ||||
| }; | ||||
|  | ||||
| };  // namespace | ||||
|  | ||||
| ScreenInteractive::ScreenInteractive(int dimx, | ||||
|                                      int dimy, | ||||
|                                      Dimension dimension) | ||||
|     : Screen(dimx, dimy), dimension_(dimension) {} | ||||
| ScreenInteractive::~ScreenInteractive() {} | ||||
|  | ||||
| // static | ||||
| ScreenInteractive ScreenInteractive::FixedSize(int dimx, int dimy) { | ||||
|   return ScreenInteractive(dimx, dimy, Dimension::Fixed); | ||||
| } | ||||
|  | ||||
| // static | ||||
| ScreenInteractive ScreenInteractive::Fullscreen() { | ||||
|   return ScreenInteractive(0, 0, Dimension::Fullscreen); | ||||
| } | ||||
|  | ||||
| // static | ||||
| ScreenInteractive ScreenInteractive::TerminalOutput() { | ||||
|   return ScreenInteractive(0, 0, Dimension::TerminalOutput); | ||||
| } | ||||
|  | ||||
| // static | ||||
| 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 <] | ||||
|   //std::cout << std::flush; | ||||
|  | ||||
|   // Save the old terminal configuration. | ||||
|   struct termios terminal_configuration_old; | ||||
|   tcgetattr(STDIN_FILENO, &terminal_configuration_old); | ||||
|  | ||||
|   // Set the new terminal configuration | ||||
|   struct termios terminal_configuration_new; | ||||
|   terminal_configuration_new = terminal_configuration_old; | ||||
|  | ||||
|   // Non canonique terminal. | ||||
|   terminal_configuration_new.c_lflag &= ~ICANON; | ||||
|   // Do not print after a key press. | ||||
|   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(); | ||||
|     EventLoop(component); | ||||
|   } | ||||
|  | ||||
|   // Restore the old terminal configuration. | ||||
|   tcsetattr(STDIN_FILENO, TCSANOW, &terminal_configuration_old); | ||||
|  | ||||
|   read_char.join(); | ||||
|  | ||||
|   std::cout << std::endl; | ||||
| } | ||||
|  | ||||
| void ScreenInteractive::Draw(Component* component) { | ||||
|   auto document = component->Render(); | ||||
|   int dimx; | ||||
|   int dimy; | ||||
|   switch (dimension_) { | ||||
|     case Dimension::Fixed: | ||||
|       dimx = dimx_; | ||||
|       dimy = dimy_; | ||||
|       break; | ||||
|     case Dimension::TerminalOutput: | ||||
|       document->ComputeRequirement(); | ||||
|       dimx = Terminal::Size().dimx; | ||||
|       dimy = document->requirement().min.y; | ||||
|       break; | ||||
|     case Dimension::Fullscreen: | ||||
|       dimx = Terminal::Size().dimx; | ||||
|       dimy = Terminal::Size().dimy; | ||||
|       break; | ||||
|     case Dimension::FitComponent: | ||||
|       auto terminal = Terminal::Size(); | ||||
|       document->ComputeRequirement(); | ||||
|       dimx = std::min(document->requirement().min.x, terminal.dimx); | ||||
|       dimy = std::min(document->requirement().min.y, terminal.dimy); | ||||
|       break; | ||||
|   } | ||||
|  | ||||
|   if (dimx != dimx_ || dimy != dimy_) { | ||||
|     dimx_ = dimx; | ||||
|     dimy_ = dimy; | ||||
|     pixels_ = std::vector<std::vector<Pixel>>( | ||||
|         dimy, std::vector<Pixel>(dimx)); | ||||
|   } | ||||
|  | ||||
|   Render(*this, document.get()); | ||||
| } | ||||
|  | ||||
| std::function<void()> ScreenInteractive::ExitLoopClosure() { | ||||
|   return [this]() { quit_ = true; }; | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui. | ||||
							
								
								
									
										42
									
								
								src/ftxui/component/toggle.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/ftxui/component/toggle.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| #include "ftxui/component/toggle.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Element Toggle::Render() { | ||||
|   bool is_focused = Focused(); | ||||
|  | ||||
|   Elements children; | ||||
|   for(size_t i = 0; i<entries.size(); ++i) { | ||||
|     // Separator. | ||||
|     if (i != 0) | ||||
|       children.push_back(separator()); | ||||
|  | ||||
|     // Entry. | ||||
|     auto style = (selected != int(i)) | ||||
|                      ? normal_style | ||||
|                      : is_focused ? focused_style : selected_style; | ||||
|     auto focused = (selected != int(i)) ? nothing : is_focused ? focus : select; | ||||
|     children.push_back(text(entries[i]) | style | focused); | ||||
|   } | ||||
|   return hbox(std::move(children)); | ||||
| } | ||||
|  | ||||
| bool Toggle::OnEvent(Event event) { | ||||
|   if (selected > 0 && | ||||
|       (event == Event::ArrowLeft || event == Event::Character('h'))) { | ||||
|     selected--; | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   if (selected < int(entries.size()) - 1 && | ||||
|       (event == Event::ArrowRight || event == Event::Character('l'))) { | ||||
|     selected++; | ||||
|     on_change(); | ||||
|     return true; | ||||
|   } | ||||
|  | ||||
|   return false; | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui | ||||
							
								
								
									
										25
									
								
								src/ftxui/dom/blink.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/ftxui/dom/blink.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class Blink : public NodeDecorator { | ||||
|  public: | ||||
|   Blink(Elements children) : NodeDecorator(std::move(children)) {} | ||||
|   ~Blink() override {} | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     Node::Render(screen); | ||||
|     for (int y = box_.y_min; y <= box_.y_max; ++y) { | ||||
|       for (int x = box_.x_min; x <= box_.x_max; ++x) { | ||||
|         screen.PixelAt(x, y).blink = true; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> blink(Element child) { | ||||
|   return std::make_unique<Blink>(unpack(std::move(child))); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										25
									
								
								src/ftxui/dom/bold.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								src/ftxui/dom/bold.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class Bold : public NodeDecorator { | ||||
|  public: | ||||
|   Bold(Elements children) : NodeDecorator(std::move(children)) {} | ||||
|   ~Bold() override {} | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     for (int y = box_.y_min; y <= box_.y_max; ++y) { | ||||
|       for (int x = box_.x_min; x <= box_.x_max; ++x) { | ||||
|         screen.PixelAt(x,y).bold = true;  | ||||
|       } | ||||
|     } | ||||
|     Node::Render(screen); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> bold(Element child) { | ||||
|   return std::make_unique<Bold>(unpack(std::move(child))); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										118
									
								
								src/ftxui/dom/border.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										118
									
								
								src/ftxui/dom/border.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,118 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| static wchar_t simple_border_charset[] = L"┌┐└┘─│┬┴┤├"; | ||||
|  | ||||
| class Border : public Node { | ||||
|  public: | ||||
|   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(); | ||||
|     requirement_.min.x += 2; | ||||
|     requirement_.min.y += 2; | ||||
|     if (children.size() == 2) { | ||||
|       requirement_.min.x = | ||||
|           std::max(requirement_.min.x, children[1]->requirement().min.x + 2); | ||||
|     } | ||||
|     requirement_.selected_box.x_min++; | ||||
|     requirement_.selected_box.x_max++; | ||||
|     requirement_.selected_box.y_min++; | ||||
|     requirement_.selected_box.y_max++; | ||||
|   } | ||||
|  | ||||
|   void SetBox(Box box) override { | ||||
|     Node::SetBox(box); | ||||
|     if (children.size() == 2) { | ||||
|       Box title_box; | ||||
|       title_box.x_min = box.x_min + 1; | ||||
|       title_box.x_max = box.x_max - 1; | ||||
|       title_box.y_min = box.y_min; | ||||
|       title_box.y_max = box.y_min; | ||||
|       children[1]->SetBox(title_box); | ||||
|     } | ||||
|     box.x_min++; | ||||
|     box.x_max--; | ||||
|     box.y_min++; | ||||
|     box.y_max--; | ||||
|     children[0]->SetBox(box); | ||||
|   } | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     // Draw content. | ||||
|     children[0]->Render(screen); | ||||
|  | ||||
|     // Draw the border. | ||||
|     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]; | ||||
|     screen.at(box_.x_max, box_.y_max) = charset[3]; | ||||
|     for(float x = box_.x_min + 1; x<box_.x_max; ++x) { | ||||
|       screen.at(x, box_.y_min) = charset[4]; | ||||
|       screen.at(x, box_.y_max) = charset[4]; | ||||
|     } | ||||
|     for(float y = box_.y_min + 1; y<box_.y_max; ++y) { | ||||
|       screen.at(box_.x_min, y) = charset[5]; | ||||
|       screen.at(box_.x_max,y) = charset[5]; | ||||
|     } | ||||
|  | ||||
|     // Draw title. | ||||
|     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) { | ||||
|   return std::make_unique<Border>(unpack(std::move(child))); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Node> window(Element title, Element content) { | ||||
|   return std::make_unique<Border>(unpack(std::move(content), std::move(title))); | ||||
| } | ||||
|  | ||||
| Decorator borderWith(Pixel pixel) { | ||||
|   return [pixel](Element child) { | ||||
|     return std::make_unique<Border>(unpack(std::move(child)), pixel); | ||||
|   }; | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										61
									
								
								src/ftxui/dom/color.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								src/ftxui/dom/color.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class BgColor : public NodeDecorator { | ||||
|  public: | ||||
|   BgColor(Elements children, Color color) | ||||
|       : NodeDecorator(std::move(children)), color_(color) {} | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     for (int y = box_.y_min; y <= box_.y_max; ++y) { | ||||
|       for (int x = box_.x_min; x <= box_.x_max; ++x) { | ||||
|         screen.PixelAt(x, y).background_color = color_; | ||||
|       } | ||||
|     } | ||||
|     NodeDecorator::Render(screen); | ||||
|   } | ||||
|  | ||||
|   Color color_; | ||||
| }; | ||||
|  | ||||
| class FgColor : public NodeDecorator { | ||||
|  public: | ||||
|   FgColor(Elements children, Color color) | ||||
|       : NodeDecorator(std::move(children)), color_(color) {} | ||||
|   ~FgColor() override {} | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     for (int y = box_.y_min; y <= box_.y_max; ++y) { | ||||
|       for (int x = box_.x_min; x <= box_.x_max; ++x) { | ||||
|         screen.PixelAt(x, y).foreground_color = color_; | ||||
|       } | ||||
|     } | ||||
|     NodeDecorator::Render(screen); | ||||
|   } | ||||
|  | ||||
|   Color color_; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> color(Color c, Element child) { | ||||
|   return std::make_unique<FgColor>(unpack(std::move(child)), c); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Node> bgcolor(Color c, Element child) { | ||||
|   return std::make_unique<BgColor>(unpack(std::move(child)), c); | ||||
| } | ||||
|  | ||||
| Decorator color(Color c) { | ||||
|   return [c](Element child) { | ||||
|     return color(c, std::move(child)); | ||||
|   }; | ||||
| } | ||||
|  | ||||
| Decorator bgcolor(Color c) { | ||||
|   return [c](Element child) { | ||||
|     return bgcolor(c, std::move(child)); | ||||
|   }; | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										22
									
								
								src/ftxui/dom/composite_decorator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								src/ftxui/dom/composite_decorator.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| std::unique_ptr<Node> hcenter(Element child) { | ||||
|   return hbox(filler(), std::move(child), filler()); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Node> vcenter(Element child) { | ||||
|   return vbox(filler(), std::move(child), filler()); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Node> center(Element child) { | ||||
|   return hcenter(vcenter(std::move(child))); | ||||
| } | ||||
|  | ||||
| std::unique_ptr<Node> align_right(Element child) { | ||||
|   return hbox(filler(), std::move(child)); | ||||
| } | ||||
|  | ||||
| } // namespace ftxui | ||||
							
								
								
									
										40
									
								
								src/ftxui/dom/dbox.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/ftxui/dom/dbox.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class DBox : public Node { | ||||
|  public: | ||||
|   DBox(Elements 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); | ||||
|  | ||||
|       if (requirement_.selection < child->requirement().selection) { | ||||
|         requirement_.selection = child->requirement().selection; | ||||
|         requirement_.selected_box = child->requirement().selected_box; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void SetBox(Box box) override { | ||||
|     Node::SetBox(box); | ||||
|  | ||||
|     for (auto& child : children) | ||||
|       child->SetBox(box); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> dbox(Elements children) { | ||||
|   return std::make_unique<DBox>(std::move(children)); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										27
									
								
								src/ftxui/dom/dim.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/ftxui/dom/dim.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| using ftxui::Screen; | ||||
|  | ||||
| class Dim : public NodeDecorator { | ||||
|  public: | ||||
|   Dim(Elements children) : NodeDecorator(std::move(children)) {} | ||||
|   ~Dim() override {} | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     Node::Render(screen); | ||||
|     for (int y = box_.y_min; y <= box_.y_max; ++y) { | ||||
|       for (int x = box_.x_min; x <= box_.x_max; ++x) { | ||||
|         screen.PixelAt(x,y).dim = true;  | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> dim(Element child) { | ||||
|   return std::make_unique<Dim>(unpack(std::move(child))); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										58
									
								
								src/ftxui/dom/flex.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								src/ftxui/dom/flex.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,58 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class Flex : public Node { | ||||
|  public: | ||||
|   Flex() {} | ||||
|   Flex(Element child) : Node(unpack(std::move(child))) {} | ||||
|   ~Flex() 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 = 1; | ||||
|     requirement_.flex.y = 1; | ||||
|   } | ||||
|  | ||||
|   void SetBox(Box box) override { | ||||
|     if (children.empty()) | ||||
|       return; | ||||
|     children[0]->SetBox(box); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| 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>(); | ||||
| } | ||||
|  | ||||
| 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 | ||||
							
								
								
									
										121
									
								
								src/ftxui/dom/frame.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								src/ftxui/dom/frame.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/util/autoreset.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
|  | ||||
| class Select : public Node { | ||||
|  public: | ||||
|   Select(std::vector<std::unique_ptr<Node>> children) | ||||
|       : Node(std::move(children)) {} | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
|     Node::ComputeRequirement(); | ||||
|     requirement_ = children[0]->requirement(); | ||||
|     auto& selected_box = requirement_.selected_box; | ||||
|     selected_box.x_min = 0; | ||||
|     selected_box.y_min = 0; | ||||
|     selected_box.x_max = requirement_.min.x; | ||||
|     selected_box.y_max = requirement_.min.y; | ||||
|     requirement_.selection = Requirement::SELECTED; | ||||
|   }; | ||||
|  | ||||
|   void SetBox(Box box) override { | ||||
|     box_ = box; | ||||
|     children[0]->SetBox(box); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> select(Element child) { | ||||
|   return std::make_unique<Select>(unpack(std::move(child))); | ||||
| } | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
|  | ||||
| class Focus : public Select { | ||||
|  public: | ||||
|   Focus(std::vector<std::unique_ptr<Node>> children) | ||||
|       : Select(std::move(children)) {} | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
|     Select::ComputeRequirement(); | ||||
|     requirement_.selection = Requirement::FOCUSED; | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> focus(Element child) { | ||||
|   return std::make_unique<Focus>(unpack(std::move(child))); | ||||
| } | ||||
|  | ||||
| // ----------------------------------------------------------------------------- | ||||
|  | ||||
| class Frame : public Node { | ||||
|  public: | ||||
|   Frame(std::vector<std::unique_ptr<Node>> children) | ||||
|       : Node(std::move(children)) {} | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
|     Node::ComputeRequirement(); | ||||
|     requirement_ = children[0]->requirement(); | ||||
|   } | ||||
|  | ||||
|   void SetBox(Box box) override { | ||||
|     Node::SetBox(box); | ||||
|  | ||||
|     int external_dimx = box.x_max - box.x_min; | ||||
|     int external_dimy = box.y_max - box.y_min; | ||||
|  | ||||
|     int internal_dimx = std::max(requirement_.min.x, external_dimx); | ||||
|     int internal_dimy = std::max(requirement_.min.y, external_dimy); | ||||
|  | ||||
|     auto& selected_box = requirement_.selected_box; | ||||
|     int focused_dimx = selected_box.x_max - selected_box.x_min; | ||||
|     int focused_dimy = selected_box.y_max - selected_box.y_min; | ||||
|     int dx = selected_box.x_min - external_dimx / 2 + focused_dimx / 2; | ||||
|     int dy = selected_box.y_min - external_dimy / 2 + focused_dimy / 2; | ||||
|     dx = std::max(0, std::min(internal_dimx - external_dimx - 1, dx)); | ||||
|     dy = std::max(0, std::min(internal_dimy - external_dimy - 1, dy)); | ||||
|  | ||||
|     Box children_box = box; | ||||
|     children_box.x_min = box.x_min - dx; | ||||
|     children_box.y_min = box.y_min - dy; | ||||
|     children_box.x_max = box.x_min + internal_dimx - dx; | ||||
|     children_box.y_max = box.y_min + internal_dimy - dy; | ||||
|     children[0]->SetBox(children_box); | ||||
|  | ||||
|     // int dx = box.x_max - box.x_min; | ||||
|     // int dy = box.y_max - box.y_min; | ||||
|     // int cdx = std::min(children[0].requirement().min.x | ||||
|  | ||||
|     // Box children_box; | ||||
|     // children_box.x_min = | ||||
|     // if (box.x_max - box.x_min >= children[0].requirement().min.x && // | ||||
|  | ||||
|     // box.y_max - box.y_min >= children[0].requirement().min.y) { | ||||
|     // children_[0]->SetBox(box); | ||||
|     // dx = 0; | ||||
|     // dy = 0; | ||||
|     // return; | ||||
|     //} | ||||
|  | ||||
|     // Box children_box; | ||||
|     // children_box.x_min = box.x_min; | ||||
|     // children_box.y_min = box.x_min; | ||||
|   } | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     AutoReset<Box> stencil(&screen.stencil, | ||||
|                            Box::Intersection(box_, screen.stencil)); | ||||
|     children[0]->Render(screen); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> frame(Element child) { | ||||
|   return std::make_unique<Frame>(unpack(std::move(child))); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										39
									
								
								src/ftxui/dom/gauge.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								src/ftxui/dom/gauge.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| static wchar_t charset[] = L"  ▏▎▍▌▋▊▉█"; | ||||
|  | ||||
| class Gauge : public Node { | ||||
|  public: | ||||
|   Gauge(float progress) : progress_(progress) {} | ||||
|   ~Gauge() override {} | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
|     requirement_.flex.x = 1; | ||||
|     requirement_.min.y = 1; | ||||
|   } | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     float y = box_.y_min; | ||||
|     float limit = box_.x_min + progress_ * (box_.x_max - box_.x_min + 1); | ||||
|     int limit_int = limit; | ||||
|     int x = box_.x_min; | ||||
|     while (x < limit_int) | ||||
|       screen.at(x++, y) = charset[9]; | ||||
|     screen.at(x++, y) = charset[int(9*(limit-limit_int))]; | ||||
|     while (x <= box_.x_max) | ||||
|       screen.at(x++, y) = charset[0]; | ||||
|   } | ||||
|  private: | ||||
|   float progress_; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> gauge(float progress) { | ||||
|   return std::make_unique<Gauge>(progress); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										45
									
								
								src/ftxui/dom/graph.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								src/ftxui/dom/graph.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| const wchar_t charset[] = L" ▗▐▖▄▟▌▙█"; | ||||
|  | ||||
| class Graph : public Node { | ||||
|  public: | ||||
|   Graph(GraphFunction graph_function) : graph_function_(graph_function) {} | ||||
|   ~Graph() override {} | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
|     requirement_.flex.x = 1; | ||||
|     requirement_.flex.y = 1; | ||||
|     requirement_.min.x = 1; | ||||
|     requirement_.min.y = 1; | ||||
|   } | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     int width = (box_.x_max - box_.x_min + 1) * 2; | ||||
|     int height = (box_.y_max - box_.y_min + 1) * 2; | ||||
|     auto data = graph_function_(width, height); | ||||
|     int i = 0; | ||||
|     for (int x = box_.x_min; x <= box_.x_max; ++x) { | ||||
|       int height_1 = 2 * box_.y_max - data[i++]; | ||||
|       int height_2 = 2 * box_.y_max - data[i++]; | ||||
|       for (int y = box_.y_min; y <= box_.y_max; ++y) { | ||||
|         int yy = 2 * y; | ||||
|         int i_1 = yy < height_1 ? 0 : yy == height_1 ? 3 : 6; | ||||
|         int i_2 = yy < height_2 ? 0 : yy == height_2 ? 1 : 2; | ||||
|         wchar_t pix = charset[i_1 + i_2]; | ||||
|         screen.at(x, y) = pix; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   GraphFunction graph_function_; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> graph(GraphFunction graph_function) { | ||||
|   return std::make_unique<Graph>(graph_function); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										72
									
								
								src/ftxui/dom/hbox.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/ftxui/dom/hbox.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class HBox : public Node { | ||||
|  public: | ||||
|   HBox(Elements children) : Node(std::move(children)) {} | ||||
|   ~HBox() {} | ||||
|  | ||||
|   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(); | ||||
|       if (requirement_.selection < child->requirement().selection) { | ||||
|         requirement_.selection = child->requirement().selection; | ||||
|         requirement_.selected_box = child->requirement().selected_box; | ||||
|         requirement_.selected_box.x_min += requirement_.min.x; | ||||
|         requirement_.selected_box.x_max += requirement_.min.x; | ||||
|       } | ||||
|       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); | ||||
|  | ||||
|     int flex_sum = 0; | ||||
|     for (auto& child : children) | ||||
|       flex_sum += child->requirement().flex.x; | ||||
|  | ||||
|     int space = box.x_max - box.x_min + 1; | ||||
|     int extra_space = space - requirement_.min.x; | ||||
|  | ||||
|     int remaining_flex = flex_sum; | ||||
|     int remaining_extra_space = extra_space; | ||||
|  | ||||
|     int x = box.x_min; | ||||
|     for (auto& child : children) { | ||||
|       if (x > box.x_max) | ||||
|         break; | ||||
|  | ||||
|       Box child_box = box; | ||||
|       child_box.x_min = x; | ||||
|  | ||||
|       child_box.x_max = x + child->requirement().min.x - 1; | ||||
|  | ||||
|       if (child->requirement().flex.x && remaining_extra_space > 0) { | ||||
|         int added_space = remaining_extra_space * child->requirement().flex.x / | ||||
|                           remaining_flex; | ||||
|         remaining_extra_space -= added_space; | ||||
|         remaining_flex -= child->requirement().flex.x; | ||||
|         child_box.x_max += added_space; | ||||
|       } | ||||
|       child_box.x_max = std::min(child_box.x_max, box.x_max); | ||||
|  | ||||
|       child->SetBox(child_box); | ||||
|       x = child_box.x_max + 1; | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> hbox(Elements children) { | ||||
|   return std::make_unique<HBox>(std::move(children)); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										59
									
								
								src/ftxui/dom/hflow.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								src/ftxui/dom/hflow.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class HFlow : public Node { | ||||
|  public: | ||||
|   HFlow(Elements children) : Node(std::move(children)) {} | ||||
|   ~HFlow() {} | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
|     requirement_.min.x = 0; | ||||
|     requirement_.min.y = 0; | ||||
|     requirement_.flex.x = 1; | ||||
|     requirement_.flex.y = 1; | ||||
|     for(auto& child : children) | ||||
|       child->ComputeRequirement(); | ||||
|   } | ||||
|  | ||||
|   void SetBox(Box box) override { | ||||
|     Node::SetBox(box); | ||||
|  | ||||
|     // The position of the first component. | ||||
|     int x = box.x_min; | ||||
|     int y = box.y_min; | ||||
|     int y_next = y; // The position of next row of elements. | ||||
|  | ||||
|     for (auto& child : children) { | ||||
|       Requirement requirement = child->requirement(); | ||||
|  | ||||
|       // Does it fit the end of the row? | ||||
|       if (x + requirement.min.x > box.x_max) { | ||||
|         // No? Use the next row. | ||||
|         x = box.x_min; | ||||
|         y = y_next; | ||||
|       } | ||||
|  | ||||
|       // Does the current row big enough to contain the element? | ||||
|       if (y + requirement.min.y > box.y_max + 1) | ||||
|         break; // No? Ignore the element. | ||||
|  | ||||
|       Box children_box; | ||||
|       children_box.x_min = x; | ||||
|       children_box.x_max = x + requirement.min.x - 1; | ||||
|       children_box.y_min = y; | ||||
|       children_box.y_max = y + requirement.min.y - 1; | ||||
|       child->SetBox(children_box); | ||||
|  | ||||
|       x = x + requirement.min.x; | ||||
|       y_next = std::max(y_next, y + requirement.min.y); | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> hflow(Elements children) { | ||||
|   return std::make_unique<HFlow>(std::move(children)); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										27
									
								
								src/ftxui/dom/inverted.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/ftxui/dom/inverted.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| using ftxui::Screen; | ||||
|  | ||||
| class Inverted : public NodeDecorator { | ||||
|  public: | ||||
|   Inverted(Elements children) : NodeDecorator(std::move(children)) {} | ||||
|   ~Inverted() override {} | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     Node::Render(screen); | ||||
|     for (int y = box_.y_min; y <= box_.y_max; ++y) { | ||||
|       for (int x = box_.x_min; x <= box_.x_max; ++x) { | ||||
|         screen.PixelAt(x,y).inverted = true;  | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> inverted(Element child) { | ||||
|   return std::make_unique<Inverted>(unpack(std::move(child))); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										47
									
								
								src/ftxui/dom/node.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/ftxui/dom/node.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| using ftxui::Screen; | ||||
|  | ||||
| Node::Node() {} | ||||
| Node::Node(std::vector<std::unique_ptr<Node>> children) | ||||
|     : children(std::move(children)) {} | ||||
| Node::~Node() {} | ||||
|  | ||||
| void Node::ComputeRequirement() { | ||||
|   for(auto& child : children) | ||||
|     child->ComputeRequirement(); | ||||
| } | ||||
|  | ||||
| void Node::SetBox(Box box) { | ||||
|   box_ = box; | ||||
| } | ||||
|  | ||||
| void Node::Render(Screen& screen) { | ||||
|   for(auto& child : children) | ||||
|     child->Render(screen); | ||||
| } | ||||
|  | ||||
| void Render(Screen& screen, Node* node) { | ||||
|   // Step 1: Find what dimension this elements wants to be. | ||||
|   node->ComputeRequirement(); | ||||
|    | ||||
|   Box box; | ||||
|   box.x_min = 0; | ||||
|   box.y_min = 0; | ||||
|   box.x_max = screen.dimx() - 1; | ||||
|   box.y_max = screen.dimy() - 1; | ||||
|    | ||||
|   // Step 2: Assign a dimension to the element. | ||||
|   node->SetBox(box); | ||||
|   screen.stencil = box; | ||||
|  | ||||
|   // Step 3: Draw the element. | ||||
|   node->Render(screen); | ||||
|  | ||||
|   // Step 4: Apply shaders | ||||
|   screen.ApplyShader(); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										15
									
								
								src/ftxui/dom/node_decorator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								src/ftxui/dom/node_decorator.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| void NodeDecorator::ComputeRequirement() { | ||||
|   Node::ComputeRequirement(); | ||||
|   requirement_ = children[0]->requirement(); | ||||
| } | ||||
|  | ||||
| void NodeDecorator::SetBox(Box box) { | ||||
|   Node::SetBox(box); | ||||
|   children[0]->SetBox(box); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										20
									
								
								src/ftxui/dom/node_decorator.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								src/ftxui/dom/node_decorator.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| #ifndef FTXUI_DOM_NODE_DECORATOR_H_ | ||||
| #define FTXUI_DOM_NODE_DECORATOR_H_ | ||||
|  | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| // Helper class. | ||||
| class NodeDecorator : public Node { | ||||
|  public: | ||||
|   NodeDecorator(Elements children) : Node(std::move(children)) {} | ||||
|   ~NodeDecorator() override {} | ||||
|   void ComputeRequirement() override; | ||||
|   void SetBox(Box box) override; | ||||
| }; | ||||
|  | ||||
| };  // namespace ftxui | ||||
|  | ||||
| #endif /* end of include guard: FTXUI_DOM_NODE_DECORATOR_H_ */ | ||||
							
								
								
									
										16
									
								
								src/ftxui/dom/paragraph.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/ftxui/dom/paragraph.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| #include <sstream> | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Elements paragraph(std::wstring the_text) { | ||||
|   Elements output; | ||||
|   std::wstringstream ss(the_text); | ||||
|   std::wstring word; | ||||
|   while (std::getline(ss, word, L' ')) { | ||||
|     output.push_back(text(word + L' ')); | ||||
|   } | ||||
|   return output; | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui | ||||
							
								
								
									
										56
									
								
								src/ftxui/dom/separator.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								src/ftxui/dom/separator.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| using ftxui::Screen; | ||||
|  | ||||
| class Separator : public Node { | ||||
|  public: | ||||
|   Separator() {} | ||||
|   ~Separator() override {} | ||||
|   void ComputeRequirement() override { | ||||
|     requirement_.min.x = 1; | ||||
|     requirement_.min.y = 1; | ||||
|   } | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     bool is_column = (box_.x_max == box_.x_min); | ||||
|     bool is_line = (box_.y_min == box_.y_max); | ||||
|  | ||||
|     wchar_t c = U'+'; | ||||
|     if (is_line && !is_column) | ||||
|       c = U'─'; | ||||
|     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.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 | ||||
							
								
								
									
										77
									
								
								src/ftxui/dom/size.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								src/ftxui/dom/size.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| #include "ftxui/dom/elements.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class Size : public Node { | ||||
|  public: | ||||
|   Size(Element child, Direction direction, Constraint constraint, size_t value) | ||||
|       : Node(unpack(std::move(child))), | ||||
|         direction_(direction), | ||||
|         constraint_(constraint), | ||||
|         value_(value) {} | ||||
|  | ||||
|   ~Size() override {} | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
|     Node::ComputeRequirement(); | ||||
|     requirement_ = children[0]->requirement(); | ||||
|  | ||||
|     auto& value = direction_ == WIDTH ? requirement_.min.x : requirement_.min.y; | ||||
|  | ||||
|     switch (constraint_) { | ||||
|       case LESS_THAN: | ||||
|         value = std::min(value, value_); | ||||
|         break; | ||||
|       case EQUAL: | ||||
|         value = value_; | ||||
|         break; | ||||
|       case GREATER_THAN: | ||||
|         value = std::max(value, value_); | ||||
|         break; | ||||
|     } | ||||
|  | ||||
|     if (direction_ == WIDTH) | ||||
|       requirement_.flex.x = 0; | ||||
|     else | ||||
|       requirement_.flex.y = 0; | ||||
|   } | ||||
|  | ||||
|   void SetBox(Box box) override { | ||||
|     Node::SetBox(box); | ||||
|  | ||||
|     if (direction_ == WIDTH) { | ||||
|       switch(constraint_) { | ||||
|         case LESS_THAN: | ||||
|         case EQUAL: | ||||
|           box.x_max = std::min(box.x_min + value_ + 1, box.x_max); | ||||
|           break; | ||||
|         case GREATER_THAN: | ||||
|           break; | ||||
|       } | ||||
|     } else { | ||||
|       switch(constraint_) { | ||||
|         case LESS_THAN: | ||||
|         case EQUAL: | ||||
|           box.y_max = std::min(box.y_min + value_ + 1, box.y_max); | ||||
|           break; | ||||
|         case GREATER_THAN: | ||||
|           break; | ||||
|       } | ||||
|     } | ||||
|     children[0]->SetBox(box); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   Direction direction_; | ||||
|   Constraint constraint_; | ||||
|   int value_; | ||||
| }; | ||||
|  | ||||
| Decorator size(Direction direction, Constraint constraint, int value) { | ||||
|   return [=](Element e) { | ||||
|     return std::make_unique<Size>(std::move(e), direction, constraint, value); | ||||
|   }; | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										279
									
								
								src/ftxui/dom/spinner.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										279
									
								
								src/ftxui/dom/spinner.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,279 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| using namespace ftxui; | ||||
|  | ||||
| static const std::vector<std::vector<std::vector<std::wstring>>> elements = { | ||||
|   { | ||||
|     {L"Replaced by the gauge"}, | ||||
|   }, | ||||
|   { | ||||
|     {L".  "}, | ||||
|     {L".. "}, | ||||
|     {L"..."}, | ||||
|   }, | ||||
|   { | ||||
|     {L"|"}, | ||||
|     {L"/"}, | ||||
|     {L"-"}, | ||||
|     {L"\\"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"+"}, | ||||
|     {L"x"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"|  "}, | ||||
|     {L"|| "}, | ||||
|     {L"|||"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"←"}, | ||||
|     {L"↖"}, | ||||
|     {L"↑"}, | ||||
|     {L"↗"}, | ||||
|     {L"→"}, | ||||
|     {L"↘"}, | ||||
|     {L"↓"}, | ||||
|     {L"↙"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"▁"}, | ||||
|     {L"▂"}, | ||||
|     {L"▃"}, | ||||
|     {L"▄"}, | ||||
|     {L"▅"}, | ||||
|     {L"▆"}, | ||||
|     {L"▇"}, | ||||
|     {L"█"}, | ||||
|     {L"▇"}, | ||||
|     {L"▆"}, | ||||
|     {L"▅"}, | ||||
|     {L"▄"}, | ||||
|     {L"▃"}, | ||||
|     {L"▁"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"▉"}, | ||||
|     {L"▊"}, | ||||
|     {L"▋"}, | ||||
|     {L"▌"}, | ||||
|     {L"▍"}, | ||||
|     {L"▎"}, | ||||
|     {L"▏"}, | ||||
|     {L"▎"}, | ||||
|     {L"▍"}, | ||||
|     {L"▌"}, | ||||
|     {L"▋"}, | ||||
|     {L"▊"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"▖"}, | ||||
|     {L"▘"}, | ||||
|     {L"▝"}, | ||||
|     {L"▗"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"◢"}, | ||||
|     {L"◣"}, | ||||
|     {L"◤"}, | ||||
|     {L"◥"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"◰"}, | ||||
|     {L"◳"}, | ||||
|     {L"◲"}, | ||||
|     {L"◱"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"◴"}, | ||||
|     {L"◷"}, | ||||
|     {L"◶"}, | ||||
|     {L"◵"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"◐"}, | ||||
|     {L"◓"}, | ||||
|     {L"◑"}, | ||||
|     {L"◒"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"◡"}, | ||||
|     {L"⊙"}, | ||||
|     {L"◠"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"⠁"}, | ||||
|     {L"⠂"}, | ||||
|     {L"⠄"}, | ||||
|     {L"⡀"}, | ||||
|     {L"⢀"}, | ||||
|     {L"⠠"}, | ||||
|     {L"⠐"}, | ||||
|     {L"⠈"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"⠋"}, | ||||
|     {L"⠙"}, | ||||
|     {L"⠹"}, | ||||
|     {L"⠸"}, | ||||
|     {L"⠼"}, | ||||
|     {L"⠴"}, | ||||
|     {L"⠦"}, | ||||
|     {L"⠧"}, | ||||
|     {L"⠇"}, | ||||
|     {L"⠏"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"(*----------)"}, | ||||
|     {L"(-*---------)"}, | ||||
|     {L"(--*--------)"}, | ||||
|     {L"(---*-------)"}, | ||||
|     {L"(----*------)"}, | ||||
|     {L"(-----*-----)"}, | ||||
|     {L"(------*----)"}, | ||||
|     {L"(-------*---)"}, | ||||
|     {L"(--------*--)"}, | ||||
|     {L"(---------*-)"}, | ||||
|     {L"(----------*)"}, | ||||
|     {L"(---------*-)"}, | ||||
|     {L"(--------*--)"}, | ||||
|     {L"(-------*---)"}, | ||||
|     {L"(------*----)"}, | ||||
|     {L"(-----*-----)"}, | ||||
|     {L"(----*------)"}, | ||||
|     {L"(---*-------)"}, | ||||
|     {L"(--*--------)"}, | ||||
|     {L"(-*---------)"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"[      ]"}, | ||||
|     {L"[=     ]"}, | ||||
|     {L"[==    ]"}, | ||||
|     {L"[===   ]"}, | ||||
|     {L"[====  ]"}, | ||||
|     {L"[===== ]"}, | ||||
|     {L"[======]"}, | ||||
|     {L"[===== ]"}, | ||||
|     {L"[====  ]"}, | ||||
|     {L"[===   ]"}, | ||||
|     {L"[==    ]"}, | ||||
|     {L"[=     ]"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"[      ]"}, | ||||
|     {L"[=     ]"}, | ||||
|     {L"[==    ]"}, | ||||
|     {L"[===   ]"}, | ||||
|     {L"[====  ]"}, | ||||
|     {L"[===== ]"}, | ||||
|     {L"[======]"}, | ||||
|     {L"[ =====]"}, | ||||
|     {L"[  ====]"}, | ||||
|     {L"[   ===]"}, | ||||
|     {L"[    ==]"}, | ||||
|     {L"[     =]"}, | ||||
|   }, | ||||
|   { | ||||
|     {L"[==    ]"}, | ||||
|     {L"[==    ]"}, | ||||
|     {L"[==    ]"}, | ||||
|     {L"[==    ]"}, | ||||
|     {L"[==    ]"}, | ||||
|     {L" [==   ]"}, | ||||
|     {L"[  ==  ]"}, | ||||
|     {L"[   == ]"}, | ||||
|     {L"[    ==]"}, | ||||
|     {L"[    ==]"}, | ||||
|     {L"[    ==]"}, | ||||
|     {L"[    ==]"}, | ||||
|     {L"[    ==]"}, | ||||
|     {L"[   ==] "}, | ||||
|     {L"[  ==  ]"}, | ||||
|     {L"[ ==   ]"}, | ||||
|   }, | ||||
|   { | ||||
|     { | ||||
|       L" ─╮", | ||||
|       L"  │", | ||||
|       L"   ", | ||||
|     }, | ||||
|     { | ||||
|       L"  ╮", | ||||
|       L"  │", | ||||
|       L"  ╯", | ||||
|     }, | ||||
|     { | ||||
|       L"   ", | ||||
|       L"  │", | ||||
|       L" ─╯", | ||||
|     }, | ||||
|     { | ||||
|       L"   ", | ||||
|       L"   ", | ||||
|       L"╰─╯", | ||||
|     }, | ||||
|     { | ||||
|       L"   ", | ||||
|       L"│  ", | ||||
|       L"╰─ ", | ||||
|     }, | ||||
|     { | ||||
|       L"╭  ", | ||||
|       L"│  ", | ||||
|       L"╰  ", | ||||
|     }, | ||||
|     { | ||||
|       L"╭─ ", | ||||
|       L"│  ", | ||||
|       L"   ", | ||||
|     }, | ||||
|     { | ||||
|       L"╭─╮", | ||||
|       L"   ", | ||||
|       L"   ", | ||||
|     } | ||||
|   }, | ||||
|   { | ||||
|     { | ||||
|       L"   /\\O  ", | ||||
|       L"    /\\/ ", | ||||
|       L"   /\\   ", | ||||
|       L"  /  \\  ", | ||||
|       L"LOL  LOL", | ||||
|     }, | ||||
|     { | ||||
|       L"    _O  ", | ||||
|       L"   //|_ ", | ||||
|       L"    |   ", | ||||
|       L"   /|   ", | ||||
|       L"   LLOL ", | ||||
|     }, | ||||
|     { | ||||
|       L"     O  ", | ||||
|       L"    /_  ", | ||||
|       L"    |\\  ", | ||||
|       L"   / |  ", | ||||
|       L" LOLLOL ", | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> spinner(int c, size_t index) { | ||||
|   if (c == 0) { | ||||
|     index %= 40; | ||||
|     if (index > 20) | ||||
|       index = 40-index; | ||||
|     return gauge(index * 0.05); | ||||
|   } | ||||
|   c %= elements.size(); | ||||
|   index %= elements[c].size(); | ||||
|   std::vector<Element> lines; | ||||
|   for(const auto& it : elements[c][index]) | ||||
|     lines.push_back(text(it)); | ||||
|   return vbox(std::move(lines)); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										37
									
								
								src/ftxui/dom/text.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/ftxui/dom/text.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| using ftxui::Screen; | ||||
|  | ||||
| class Text : public Node { | ||||
|  public: | ||||
|   Text(std::wstring text) : Node(), text_(text) {} | ||||
|   ~Text() {} | ||||
|  | ||||
|   void ComputeRequirement() override { | ||||
|     requirement_.min.x = text_.size(); | ||||
|     requirement_.min.y = 1; | ||||
|   } | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     int x = box_.x_min; | ||||
|     int y = box_.y_min; | ||||
|     if (y > box_.y_max) | ||||
|       return; | ||||
|     for (wchar_t c : text_) { | ||||
|       if (x > box_.x_max) | ||||
|         return; | ||||
|       screen.at(x++, y) = c; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   std::wstring text_; | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> text(std::wstring text) { | ||||
|   return std::make_unique<Text>(text); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										27
									
								
								src/ftxui/dom/underlined.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/ftxui/dom/underlined.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,27 @@ | ||||
| #include "ftxui/dom/node_decorator.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| using ftxui::Screen; | ||||
|  | ||||
| class Underlined : public NodeDecorator { | ||||
|  public: | ||||
|   Underlined(Elements children) : NodeDecorator(std::move(children)) {} | ||||
|   ~Underlined() override {} | ||||
|  | ||||
|   void Render(Screen& screen) override { | ||||
|     Node::Render(screen); | ||||
|     for (int y = box_.y_min; y <= box_.y_max; ++y) { | ||||
|       for (int x = box_.x_min; x <= box_.x_max; ++x) { | ||||
|         screen.PixelAt(x, y).underlined = true; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> underlined(Element child) { | ||||
|   return std::make_unique<Underlined>(unpack(std::move(child))); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										33
									
								
								src/ftxui/dom/util.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/ftxui/dom/util.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Element nothing(Element element) { | ||||
|   return element; | ||||
| } | ||||
|  | ||||
| Decorator compose(Decorator a, Decorator b) { | ||||
|   return [ | ||||
|     a = std::move(a), | ||||
|     b = std::move(b) | ||||
|   ](Element element) { | ||||
|     return b(a(std::move(element))); | ||||
|   }; | ||||
| } | ||||
|  | ||||
| Decorator operator|(Decorator a, Decorator b) { | ||||
|   return compose(a, b); | ||||
| } | ||||
|  | ||||
| Elements operator|(Elements es, Decorator d) { | ||||
|   Elements output; | ||||
|   for (auto& it : es) | ||||
|     output.push_back(std::move(it) | d); | ||||
|   return output; | ||||
| } | ||||
|  | ||||
| Element operator|(Element e, Decorator d) { | ||||
|   return d(std::move(e)); | ||||
| } | ||||
|  | ||||
| }  // namespace ftxui | ||||
							
								
								
									
										72
									
								
								src/ftxui/dom/vbox.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/ftxui/dom/vbox.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/dom/elements.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class VBox : public Node { | ||||
|  public: | ||||
|   VBox(Elements children) : Node(std::move(children)) {} | ||||
|   ~VBox() {} | ||||
|  | ||||
|   void ComputeRequirement() { | ||||
|     requirement_.min.x = 0; | ||||
|     requirement_.min.y = 0; | ||||
|     requirement_.flex.x = 0; | ||||
|     requirement_.flex.y = 1; | ||||
|     for (auto& child : children) { | ||||
|       child->ComputeRequirement(); | ||||
|       if (requirement_.selection < child->requirement().selection) { | ||||
|         requirement_.selection = child->requirement().selection; | ||||
|         requirement_.selected_box = child->requirement().selected_box; | ||||
|         requirement_.selected_box.y_min += requirement_.min.y; | ||||
|         requirement_.selected_box.y_max += requirement_.min.y; | ||||
|       } | ||||
|       requirement_.min.y += child->requirement().min.y; | ||||
|       requirement_.min.x = | ||||
|           std::max(requirement_.min.x, child->requirement().min.x); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void SetBox(Box box) { | ||||
|     Node::SetBox(box); | ||||
|  | ||||
|     int flex_sum = 0; | ||||
|     for (auto& child : children) | ||||
|       flex_sum += child->requirement().flex.y; | ||||
|  | ||||
|     int space = box.y_max - box.y_min + 1; | ||||
|     int extra_space = space - requirement_.min.y; | ||||
|  | ||||
|     int remaining_flex = flex_sum; | ||||
|     int remaining_extra_space = extra_space; | ||||
|  | ||||
|     int y = box.y_min; | ||||
|     for (auto& child : children) { | ||||
|       if (y > box.y_max) | ||||
|         break; | ||||
|  | ||||
|       Box child_box = box; | ||||
|       child_box.y_min = y; | ||||
|  | ||||
|       child_box.y_max = y + child->requirement().min.y - 1; | ||||
|  | ||||
|       if (child->requirement().flex.y && remaining_extra_space > 0) { | ||||
|         int added_space = remaining_extra_space * child->requirement().flex.y / | ||||
|                           remaining_flex; | ||||
|         remaining_extra_space -= added_space; | ||||
|         remaining_flex -= child->requirement().flex.y; | ||||
|         child_box.y_max += added_space; | ||||
|       } | ||||
|       child_box.y_max = std::min(child_box.y_max, box.y_max); | ||||
|  | ||||
|       child->SetBox(child_box); | ||||
|       y = child_box.y_max + 1; | ||||
|     } | ||||
|   } | ||||
| }; | ||||
|  | ||||
| std::unique_ptr<Node> vbox(Elements children) { | ||||
|   return std::make_unique<VBox>(std::move(children)); | ||||
| } | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										14
									
								
								src/ftxui/screen/box.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/ftxui/screen/box.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #include "ftxui/screen/box.hpp" | ||||
| #include <algorithm> | ||||
|  | ||||
| namespace ftxui { | ||||
| // static | ||||
| Box Box::Intersection(Box a, Box b) { | ||||
|   return Box{ | ||||
|       std::max(a.x_min, b.x_min), | ||||
|       std::min(a.x_max, b.x_max), | ||||
|       std::max(a.y_min, b.y_min), | ||||
|       std::min(a.y_max, b.y_max), | ||||
|   }; | ||||
| } | ||||
| }  // namespace ftxui | ||||
							
								
								
									
										172
									
								
								src/ftxui/screen/screen.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								src/ftxui/screen/screen.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,172 @@ | ||||
| #include "ftxui/screen/screen.hpp" | ||||
| #include "ftxui/dom/node.hpp" | ||||
| #include "ftxui/screen/string.hpp" | ||||
| #include "ftxui/screen/terminal.hpp" | ||||
|  | ||||
| #include <sstream> | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| namespace { | ||||
| static const wchar_t* BOLD_SET = L"\e[1m"; | ||||
| static const wchar_t* BOLD_RESET = L"\e[22m"; // Can't use 21 here. | ||||
|  | ||||
| static const wchar_t* DIM_SET = L"\e[2m"; | ||||
| static const wchar_t* DIM_RESET = L"\e[22m"; | ||||
|  | ||||
| static const wchar_t* UNDERLINED_SET = L"\e[4m"; | ||||
| static const wchar_t* UNDERLINED_RESET = L"\e[24m"; | ||||
|  | ||||
| static const wchar_t* BLINK_SET = L"\e[5m"; | ||||
| static const wchar_t* BLINK_RESET = L"\e[25m"; | ||||
|  | ||||
| static const wchar_t* INVERTED_SET = L"\e[7m"; | ||||
| static const wchar_t* INVERTED_RESET = L"\e[27m"; | ||||
|  | ||||
| static const char* MOVE_LEFT = "\r"; | ||||
| static const char* MOVE_UP = "\e[1A"; | ||||
| static const char* CLEAR_LINE = "\e[2K"; | ||||
|  | ||||
| bool In(const Box& stencil, int x, int y) { | ||||
|   return stencil.x_min <= x && x <= stencil.x_max &&  // | ||||
|          stencil.y_min <= y && y <= stencil.y_max; | ||||
| } | ||||
|  | ||||
| Pixel dev_null_pixel; | ||||
|  | ||||
| } // namespace | ||||
|  | ||||
| Dimension Dimension::Fixed(int v) { | ||||
|   return Dimension{v, v}; | ||||
| } | ||||
|  | ||||
| Dimension Dimension::Fit(std::unique_ptr<Node>& e) { | ||||
|   e->ComputeRequirement(); | ||||
|   Terminal::Dimensions size = Terminal::Size(); | ||||
|   return Dimension{std::min(e->requirement().min.x, size.dimx), | ||||
|                    std::min(e->requirement().min.y, size.dimy)}; | ||||
| } | ||||
|  | ||||
| Dimension Dimension::Full() { | ||||
|   Terminal::Dimensions size = Terminal::Size(); | ||||
|   return Dimension{size.dimx, size.dimy}; | ||||
| } | ||||
|  | ||||
| // static | ||||
| Screen Screen::Create(Dimension width, Dimension height) { | ||||
|   return Screen(width.dimx, height.dimy); | ||||
| } | ||||
|  | ||||
| // static | ||||
| Screen Screen::Create(Dimension dimension) { | ||||
|   return Screen(dimension.dimx, dimension.dimy); | ||||
| } | ||||
|  | ||||
| Screen::Screen(int dimx, int dimy) | ||||
|     : stencil({0, dimx - 1, 0, dimy - 1}), | ||||
|       dimx_(dimx), | ||||
|       dimy_(dimy), | ||||
|       pixels_(dimy, std::vector<Pixel>(dimx)) {} | ||||
|  | ||||
| void UpdatePixelStyle(std::wstringstream& ss, Pixel& previous, Pixel& next) { | ||||
|   if (next.bold != previous.bold) | ||||
|     ss << (next.bold ? BOLD_SET : BOLD_RESET); | ||||
|  | ||||
|   if (next.dim != previous.dim) | ||||
|     ss << (next.dim ? DIM_SET : DIM_RESET); | ||||
|  | ||||
|   if (next.underlined != previous.underlined) | ||||
|     ss << (next.underlined ? UNDERLINED_SET : UNDERLINED_RESET); | ||||
|  | ||||
|   if (next.blink != previous.blink) | ||||
|     ss << (next.blink ? BLINK_SET : BLINK_RESET); | ||||
|  | ||||
|   if (next.inverted != previous.inverted) | ||||
|     ss << (next.inverted ? INVERTED_SET : INVERTED_RESET); | ||||
|  | ||||
|   if (next.foreground_color != previous.foreground_color || | ||||
|       next.background_color != previous.background_color) { | ||||
|     ss << L"\e[" + to_wstring(std::to_string((uint8_t)next.foreground_color)) + L"m"; | ||||
|     ss << L"\e[" + to_wstring(std::to_string(10 + (uint8_t)next.background_color)) + L"m"; | ||||
|   } | ||||
|  | ||||
|   previous = next; | ||||
| } | ||||
|  | ||||
| std::string Screen::ToString() { | ||||
|   std::wstringstream ss; | ||||
|  | ||||
|   Pixel previous_pixel; | ||||
|  | ||||
|   for (int y = 0; y < dimy_; ++y) { | ||||
|     if (y != 0) | ||||
|       ss << '\n'; | ||||
|     for (int x = 0; x < dimx_; ++x) { | ||||
|       UpdatePixelStyle(ss, previous_pixel, pixels_[y][x]); | ||||
|       ss << pixels_[y][x].character; | ||||
|     } | ||||
|  | ||||
|   } | ||||
|  | ||||
|   Pixel final_pixel; | ||||
|   UpdatePixelStyle(ss, previous_pixel, final_pixel); | ||||
|  | ||||
|   return to_string(ss.str()); | ||||
| } | ||||
|  | ||||
| wchar_t& Screen::at(int x, int y) { | ||||
|   return PixelAt(x,y).character; | ||||
| } | ||||
|  | ||||
| Pixel& Screen::PixelAt(int x, int y) { | ||||
|   return In(stencil, x, y) ? pixels_[y][x] : dev_null_pixel; | ||||
| } | ||||
|  | ||||
| std::string Screen::ResetPosition() { | ||||
|   std::stringstream ss; | ||||
|   ss << MOVE_LEFT << CLEAR_LINE; | ||||
|   for (int y = 1; y < dimy_; ++y) { | ||||
|     ss << MOVE_UP << CLEAR_LINE; | ||||
|   } | ||||
|   return ss.str(); | ||||
| } | ||||
|  | ||||
| void Screen::Clear() { | ||||
|   pixels_ = std::vector<std::vector<Pixel>>(dimy_, | ||||
|                                             std::vector<Pixel>(dimx_, Pixel())); | ||||
| } | ||||
|  | ||||
| void Screen::ApplyShader() { | ||||
|  | ||||
|   // Merge box characters togethers. | ||||
|   for(int y = 1; y<dimy_; ++y) { | ||||
|     for(int x = 1; x<dimx_; ++x) { | ||||
|       wchar_t& left = at(x - 1, y); | ||||
|       wchar_t& top = at(x, y - 1); | ||||
|       wchar_t& cur = at(x, y); | ||||
|  | ||||
|       // Left vs current | ||||
|       if (cur== U'│' && left == U'─') | ||||
|         cur= U'┤'; | ||||
|       if (cur== U'─' && left == U'│') | ||||
|         left = U'├'; | ||||
|       if (cur== U'├' && left == U'─') | ||||
|         cur= U'┼'; | ||||
|       if (cur== U'─' && left == U'┤') | ||||
|         left = U'┼'; | ||||
|  | ||||
|       // Top vs current | ||||
|       if (cur== U'─' && top == U'│') | ||||
|         cur= U'┴'; | ||||
|       if (cur== U'│' && top == U'─') | ||||
|         top = U'┬'; | ||||
|       if (cur== U'┬' && top == U'│') | ||||
|         cur= U'┼'; | ||||
|       if (cur== U'│' && top == U'┴') | ||||
|         top = U'┼'; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| };  // namespace ftxui | ||||
							
								
								
									
										14
									
								
								src/ftxui/screen/string.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/ftxui/screen/string.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| #include "ftxui/screen/string.hpp" | ||||
|  | ||||
| #include <codecvt> | ||||
| #include <locale> | ||||
|  | ||||
| std::string to_string(const std::wstring& s) { | ||||
|   std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; | ||||
|   return converter.to_bytes(s); | ||||
| } | ||||
|  | ||||
| std::wstring to_wstring(const std::string& s) { | ||||
|   std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; | ||||
|   return converter.from_bytes(s); | ||||
| } | ||||
							
								
								
									
										21
									
								
								src/ftxui/screen/terminal.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/ftxui/screen/terminal.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| #include <iostream> | ||||
| #include <sys/ioctl.h> | ||||
| #include <stdio.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #include "ftxui/screen/terminal.hpp" | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| Terminal::Dimensions Terminal::Size() { | ||||
| #ifdef __EMSCRIPTEN__ | ||||
|   return Dimensions{80,43}; | ||||
| #else | ||||
|   winsize w; | ||||
|   ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); | ||||
|   std::cerr << w.ws_col << "," << w.ws_row << std::endl; | ||||
|   return Dimensions{w.ws_col, w.ws_row}; | ||||
| #endif | ||||
| } | ||||
|  | ||||
| } // namespace ftxui | ||||
							
								
								
									
										18
									
								
								src/ftxui/screen/terminal.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/ftxui/screen/terminal.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| #ifndef FTXUI_CORE_TERMINAL_HPP | ||||
| #define FTXUI_CORE_TERMINAL_HPP | ||||
|  | ||||
| namespace ftxui { | ||||
|  | ||||
| class Terminal { | ||||
|  public: | ||||
|   struct Dimensions { | ||||
|     int dimx; | ||||
|     int dimy; | ||||
|   }; | ||||
|  | ||||
|   static Dimensions Size(); | ||||
| }; | ||||
|  | ||||
| }  // namespace ftxui | ||||
|  | ||||
| #endif /* end of include guard: FTXUI_CORE_TERMINAL_HPP */ | ||||
		Reference in New Issue
	
	Block a user
	 ArthurSonzogni
					ArthurSonzogni