:computer: C++ Functional Terminal User Interface. :heart:

Overview

FTXUI

travis issues license contributors

Functional Terminal (X) User interface

A simple C++ library for terminal based user interface.

Demo:

Demo image

Feature

  • Functional style. Inspired by [1] and React
  • Simple and elegant syntax (in my opinion).
  • Support for UTF8 and fullwidth chars (→ 测试)
  • No dependencies.
  • Cross platform (mostly). Linux (main target), Windows (experimental), Mac.

Example:

  vbox({
    hbox({
      text(L"left") | border,
      text(L"middle") | border | flex,
      text(L"right") | border,
    }),
    gauge(0.5) | border,
  });
┌────┐┌───────────────────────────────────────────────────────────────┐┌─────┐
│left││middle                                                         ││right│
└────┘└───────────────────────────────────────────────────────────────┘└─────┘
┌────────────────────────────────────────────────────────────────────────────┐
│██████████████████████████████████████                                      │
└────────────────────────────────────────────────────────────────────────────┘

Documentation:

Project using FTXUI

Feel free to add your projects here:

Hosted on:

Issues
  • [BUG] Input fields get random symbols like

    [BUG] Input fields get random symbols like "[B[AA1" or "B" and others pasted in on every action

    Input fields get random symbols like "[B[AA1" or "B" and others pasted in on every action like typing, using the arrow keys and moving the mouse

    opened by Creapermann 28
  • WIP: Port to Win32 and MSVC

    WIP: Port to Win32 and MSVC

    Hi,

    I really like your library, however I would like to use it for a project which currently requires windows support. So here is a quick WIP-version of a windows port.

    I am planning to do some more cleanup before this is ready to merge but sofar it looks good, however before I spend too much time cleaning up my branch I first wanted to check if you are willing to accept a windows port.

    The blocker for merging (IMHO) is that focus handling seems broken in the sense that I cannot move between checkboxes (or list items) in any of the examples. I ran the print_key_press example and pressed ⬅⬆➡⬇, this was the output I got for that:

    ( 27 91 68 ) -> (special)
    ( 27 91 65 ) -> (special)
    ( 27 91 67 ) -> (special)
    ( 27 91 66 ) -> (special)
    
    • [x] Refactor: event translation into separate file
      • currently the Console API event mapping is living inside the read_char thread lambda in screen_interactive.cpp, as this code is a bit longer than the original (which is just a oneliner) my plan is to move it to a separate function in a separate file or ifdef guarded inside event.cpp
    • [x] Bug: Focus handling not working
      • in the examples (e.g. checkbox.cpp) I can toggle the individual checkboxes but I cannot move between items, I tried to understand the focus implementation but am I unsure which keypresses would move focus between different components
    • [ ] Annoyance: Flickering
      • screen_interactive.cpp redraws the screen which causes the output to flicker (on Windows at least), I was thinking about only redrawing the screen if it has changed (i.e. dirty tracking)

    Screenshot:

    image

    opened by mauve 26
  • Feature request: Support multi-paragraph text layout

    Feature request: Support multi-paragraph text layout

    I was enjoying the amazing library when I got crazy to find out that...

    There is no proper way I can make two paragraphs (with word wrap) adjacent!

    I've tried... this:
    	auto si = ScreenInteractive::Fullscreen();
    	
    	auto ui = Renderer([]() {
    		return vbox({
    			text("... title goes here ..."),
    			hflow(paragraph("    To celebrate Dragon Boat Festival, an underwater dance performance titled Pray was aired on Henan TV last Saturday night, the first day of the holiday.")),
    			hflow(paragraph("    Featuring the goddess of Luo River – a mysterious beauty best known in the poetry of Cao Zhi during the Three Kingdoms period, the dancer Haohao He, a former synchronized swimmer, recreated the elegance of this ancient Chinese goddess.")),
    		});
    	});
    
    	si.Loop(ui);
    

    ... which spares the vertical space evenly for the two paragraphs, and this:

    	auto ui = Container::Vertical({
    		Renderer([]() { return text("... title goes here ..."); }),
    		Renderer([]() {
    			return vbox({
    				hflow(paragraph("    To celebrate Dragon Boat Festival, an underwater dance performance titled Pray was aired on Henan TV last Saturday night, the first day of the holiday.")),
    				hflow(paragraph("    Featuring the goddess of Luo River – a mysterious beauty best known in the poetry of Cao Zhi during the Three Kingdoms period, the dancer Haohao He, a former synchronized swimmer, recreated the elegance of this ancient Chinese goddess.")),
    			});
    		})
    	});
    

    ... where paragraphs collapse and only one line is visible, with a weird g at the top left corner:

    g.. title goes here ...                                                         
        To celebrate Dragon Boat Festival, an underwater dance performance titled   
        Featuring the goddess of Luo River – a mysterious beauty best known in the  
    

    And I notices this: https://github.com/ArthurSonzogni/FTXUI/issues/68#issuecomment-762807087

    So FTXUI is missing an important and very basic feature for displaying longer texts, and the solution seems not clear.

    I think a discussion about solution is needed here.

    enhancement help wanted 
    opened by Zjl37 24
  • Arrow keys not working they way they should on Microsoft terminal

    Arrow keys not working they way they should on Microsoft terminal

    When switching between input fields the arrow key sometimes paste in symbols (text doesnt anymore and mouse movement either, thats fixed). When switching between checkboxes and pressing ENTER while switching between them, the arrow keys dont work anymore either (or the switching functionallity doesnt work anymore)

    EDIT: When mouse selecting is enabled (When you can select stuff with your mouse e.g. buttons), symbols also get copied in. Just the text part was fixed in the previous fix

    opened by Creapermann 20
  • Window doesn't update on adding a element to Elements

    Window doesn't update on adding a element to Elements

    I am adding data to Elements output from a separate thread, data is added correctly, but the screen isn't updated on adding a new element, i need to move the focus area with arrow keys for the UI to update, how can i make it update everytime a new element is added to Elements output

    opened by VedantParanjape 20
  • Is it possible to have on_enter method for Toggle component?

    Is it possible to have on_enter method for Toggle component?

    Hey, is it possible to add on_enter() for toggle component? Since, this framework doesn't have buttons. Toggle is a pretty good way to emulate buttons.

    I am more than happy to contribute for this feature.

    good first issue 
    opened by VedantParanjape 13
  • on_enter callback doesn't work

    on_enter callback doesn't work

    Normally, it works well。 in ubuntu, when I use bind command to start my program based on FTXUI. the on_enter callback of input doesn,t work. like this. add "bind -x '"\C-g":<my_program>" to ~/.bashrc. so I can use 'ctrl+g' to start my program.

    opened by brokensword2018 12
  • Customize menu items

    Customize menu items

    Hello, and thanks for the lib again) Is there any built-in way to customize (i.e. change color ) particular item in menu ?

    First approach on my mind is to add MenuOptions for each entry, but it implies some changes in MenuBase. If it is a necessary feature I can later send code for review, of course if it is not already implemented.

    Thanks!

    enhancement 
    opened by MattBystrin 12
  • Errors when trying to build the lib

    Errors when trying to build the lib

    Hey, i m trying to build ftxui in a project(vs19) and then link the lib. Im getting unresolved external errors on the color class tho, saying smth like this: LNK2001 unresolved external symbol "class std::function<class std::shared_ptr __cdecl(class std::shared_ptr)> __cdecl ftxui::color(class ftxui::Color)" ([email protected]@@[email protected][email protected]@[email protected]@@[email protected]@[email protected]@[email protected]@@[email protected]@@Z) Could this be due to the 2 files which are both named "color.cpp"?

    opened by Creapermann 11
  • Crash on exit

    Crash on exit

    Often, when exiting from main, I get this crash:

    AdminConsole.exe!std::_Iterator_base12::_Adopt_unlocked(std::_Container_proxy * _Parent_proxy=0xdddddddddddddddd) Line 1190 C++ Symbols loaded. AdminConsole.exe!std::_Iterator_base12::_Adopt_locked(std::_Container_proxy * _Parent_proxy=0xdddddddddddddddd) Line 1198 C++ Symbols loaded. AdminConsole.exe!std::_Iterator_base12::_Adopt(const std::_Container_base12 * _Parent=0x000002f48d016108) Line 1147 C++ Symbols loaded. AdminConsole.exe!std::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::shared_ptrftxui::ComponentBase>>>::_Vector_const_iterator<std::_Vector_val<std::_Simple_types<std::shared_ptrftxui::ComponentBase>>>(std::shared_ptrftxui::ComponentBase * _Parg=0xdddddddddddddddd, const std::_Container_base12 * _Pvector=0x000002f48d016108) Line 44 C++ Symbols loaded. AdminConsole.exe!std::_Vector_iterator<std::_Vector_val<std::_Simple_types<std::shared_ptrftxui::ComponentBase>>>::_Vector_iterator<std::_Vector_val<std::_Simple_types<std::shared_ptrftxui::ComponentBase>>>(std::shared_ptrftxui::ComponentBase *) C++ Symbols loaded. AdminConsole.exe!std::vector<std::shared_ptrftxui::ComponentBase,std::allocator<std::shared_ptrftxui::ComponentBase>>::end() Line 1486 C++ Symbols loaded. AdminConsole.exe!std::end<std::vector<std::shared_ptrftxui::ComponentBase,std::allocator<std::shared_ptrftxui::ComponentBase>>>(std::vector<std::shared_ptrftxui::ComponentBase,std::allocator<std::shared_ptrftxui::ComponentBase>> & _Cont={...}) Line 1927 C++ Symbols loaded. AdminConsole.exe!ftxui::ComponentBase::Detach() Line 139 C++ Symbols loaded. AdminConsole.exe!ftxui::ComponentBase::~ComponentBase() Line 23 C++ Symbols loaded. AdminConsole.exe!ftxui::ContainerBase::~ContainerBase() Line 23 C++ Symbols loaded. AdminConsole.exe!ftxui::ContainerBase::`scalar deleting destructor'(unsigned int) C++ Symbols loaded. AdminConsole.exe!std::_Destroy_in_placeftxui::ContainerBase(ftxui::ContainerBase & _Obj={...}) Line 313 C++ Symbols loaded. AdminConsole.exe!std::_Ref_count_obj2ftxui::ContainerBase::_Destroy() Line 2048 C++ Symbols loaded. AdminConsole.exe!std::_Ref_count_base::_Decref() Line 1110 C++ Symbols loaded. AdminConsole.exe!std::_Ptr_baseftxui::ComponentBase::_Decref() Line 1341 C++ Symbols loaded. AdminConsole.exe!std::shared_ptrftxui::ComponentBase::~shared_ptrftxui::ComponentBase() Line 1629 C++ Symbols loaded.

    opened by MichaelGoulding 11
  • Question : Rendering different UI states : colored buttons on click,

    Question : Rendering different UI states : colored buttons on click,

    Hi @ArthurSonzogni,

    Here is more of a question than any kind of bug report while working with your library with @Lambourl for it's integration at the CLI UI for tipi.build.

    What is supposed to be the way that you've foreseen to have for instance colored components that are updated on events (custom or click) ?

    We went for something where we delete from the Component children_ list and from the Element list before rerendering.

    I feel we are missing the big picture, how it supposed to be done. I was wondering, why aren't all Components also Elements ?

    Is it a design choice or a lack of time ? Because in the solution we have found it seems to require some manual synchronization between Elements and Components vectors.

    My use case is : I want to change the color state of the button when I click on it.

    The follow works but I don't think it's the way it is supposed to be done ? Or is it ? image

    #include <memory>  // for allocator, __shared_ptr_access, shared_ptr
    #include <string>  // for wstring, basic_string
    #include <vector>  // for vector
    
    #include "ftxui/component/captured_mouse.hpp"  // for ftxui
    #include "ftxui/component/component.hpp"  // for Radiobox, Renderer, Tab, Toggle, Vertical
    #include "ftxui/component/component_base.hpp"      // for ComponentBase
    #include "ftxui/component/screen_interactive.hpp"  // for ScreenInteractive
    #include "ftxui/dom/elements.hpp"  // for Element, separator, operator|, vbox, border
    
    using namespace ftxui;
    
    int main(int argc, const char* argv[]) {
    
      struct AppMainWindow : public ComponentBase {
    
          int tab_selected = 0;
          std::vector<std::wstring> tab_1_entries{
              L"Forest",
              L"Water",
              L"I don't know",
          };
          int tab_1_selected = 0;
    
          std::vector<std::wstring> tab_2_entries{
              L"Hello",
              L"Hi",
              L"Hay",
          };
          int tab_2_selected = 0;
    
          std::vector<std::wstring> tab_3_entries{
              L"Table",
              L"Nothing",
              L"Is",
              L"Empty",
          };
          int tab_3_selected = 0;
    
          Component tab_container = Container::Tab(
          {
              Radiobox(&tab_1_entries, &tab_1_selected),
              Radiobox(&tab_2_entries, &tab_2_selected),
              Radiobox(&tab_3_entries, &tab_3_selected),
          },
          &tab_selected);
    
          Components buttons;
          Elements button_line;
          
          void updateButtonModel() {
              button_line.clear();
              for (auto& button : buttons) {
                  auto found = std::find(children_.begin(), children_.end(), button);
                  if (found != children_.end()) {
                      children_.erase(found);
                  }
    
              }
              buttons.clear();
    
              for (int i = 0; i < 3; ++i) {
                auto button = Button( std::wstring(L" [ ⚈ Hey ") + std::to_wstring(i) + std::wstring(L"] "), 
                [this, i] () mutable { 
                    tab_selected = i;
                    updateButtonModel();
                 }, false);
                this->Add(button);
                button_line.push_back(hbox(button->Render()) | color(((tab_selected == i) ? Color::Red1 : Color::Green1)));
                button_line.push_back(separator());
              }
          }
    
          AppMainWindow() : ComponentBase() {
    
              this->Add(tab_container);            
              this->updateButtonModel();
          }
    
          virtual Element Render() override {
            return 
            vbox({
                    hbox(
                        button_line
                    ),
                    hbox({
                       tab_container->Render(),
                        }),
            }) ;
          }
        
      };
    
      auto screen = ScreenInteractive::TerminalOutput();
      screen.Loop(std::make_shared<AppMainWindow>());
    }
    
    opened by daminetreg 10
  • Focus does not account for the extra height when using longer paragraphs in yframe

    Focus does not account for the extra height when using longer paragraphs in yframe

    I am hoping to use ftxui in a console app I have been working on, but scrolling (yframe) behaves unexpectedly. If you try the code below, I would expect the focussed element in paragraph_renderer_left to always be visible, but instead as I scroll down, the focussed element goes one step down. I believe this might be due to the fact that my paragraph text takes two lines, while it expects one line of text? Am I misunderstanding something here?

    Note that if you try the code below and you only see one line of text per element (because you have a wide screen), then you might need to resize your terminal and cause it to use multiple lines.

    #include <chrono>
    #include <iostream>
    #include <thread>
    
    #include "ftxui/component/component.hpp"
    #include "ftxui/component/screen_interactive.hpp"
    #include "ftxui/dom/elements.hpp"
    #include "ftxui/dom/flexbox_config.hpp"
    
    std::vector<std::string> messages;
    
    int main(void) {
      auto screen = ftxui::ScreenInteractive::Fullscreen();
    
      size_t focus_id = 0;
    
      auto paragraph_renderer_left = ftxui::Renderer([&] {
        using namespace ftxui;
    
        std::string str =
            "Lorem Ipsum is simply dummy text of the printing and typesetting "
            "industry. Lorem Ipsum has been the industry's standard dummy text "
            "ever since the 1500s, when an unknown printer took a galley of type "
            "and scrambled it to make a type specimen book. 😁";
        Elements elements;
        size_t i = 0;
        for (; i < 50; ++i) {
          if (i == focus_id) {
            elements.push_back(border(paragraphAlignLeft(str)) | focus | bold);
          } else {
            elements.push_back(border(paragraphAlignLeft(str)));
          }
        }
    
        messages.push_back("Focus id: " + std::to_string(focus_id) + " " +
                           std::to_string(i));
    
        return vbox(elements) | yframe | flex;
      });
    
      // Do I really need a renderer?
      // TODO: Use maybe to only render this when needed!
      auto messages_renderer = ftxui::Renderer([&] {
        using namespace ftxui;
    
        Elements elements{};
        for (size_t i = 0; i < messages.size(); ++i) {
          std::string pre = std::to_string(i) + ". ";
          if (i + 1 == messages.size()) {
            elements.push_back(paragraphAlignLeft(pre + messages[i]) | focus | bold);
          } else {
            elements.push_back(paragraphAlignLeft(pre + messages[i]));
          }
        }
    
        return vbox({text("Messages: " + std::to_string(messages.size())) | bold,
                     vbox(elements) | yframe | size(HEIGHT, EQUAL, 8)});
      });
    
      auto main_container =
          ftxui::Container::Vertical({paragraph_renderer_left, messages_renderer});
    
      auto main_renderer = Renderer(main_container, [&] {
        return ftxui::vbox(
            {ftxui::text("FTXUI Demo") | ftxui::bold | ftxui::hcenter,
             paragraph_renderer_left->Render(), messages_renderer->Render()});
      });
    
      auto component = CatchEvent(main_renderer, [&](ftxui::Event event) {
        if (event == ftxui::Event::Character('q')) {
          screen.ExitLoopClosure()();
          return true;
        } else if (event == ftxui::Event::Character('j')) {
          ++focus_id;
          return true;
        } else if (event == ftxui::Event::Character('k')) {
          if (focus_id > 0)
            --focus_id;
          return true;
        }
        return false;
      });
    
      bool refresh_ui_continue = true;
      std::thread refresh_ui([&] {
        while (refresh_ui_continue) {
          using namespace std::chrono_literals;
          std::this_thread::sleep_for(0.05s);
        }
      });
    
      // screen.Loop(paragraph_renderer_left);
      screen.Loop(component);
      refresh_ui_continue = false;
      refresh_ui.join();
    
      return EXIT_SUCCESS;
    }
    
    
    opened by BlackEdder 0
  • [Question] Is it possible to disable SIGTSTP handling?

    [Question] Is it possible to disable SIGTSTP handling?

    image

    I saw that started to happen when I updated ftxui to your master branch with SIGTSTP handling support

    For example: I want to execute bash interactively, and after exit back to ftxui context without suspending the parent program it self

    opened by vnepogodin 6
  • Text layout honoring whitespace from string constant for ASCII art

    Text layout honoring whitespace from string constant for ASCII art

    Looking to render a piece of ASCII Art in a box but the library seems to be stripping white space when using the paragraph element (understandable), or text component seems to be only single line.

    Is there some formatting I am missing, or do I need to stack a bunch of text objects on top of each other to force compliance with the styling?

    enhancement 
    opened by EliSchleifer 7
  • Group by functionality in table

    Group by functionality in table

    Hey, I'd like to implement group by functionality for Table. Where you could do something like this:

    vector<vector<string> data { 
      {"Id", "Name", "Surname"}, 
      {"0", "Aleksandar", "Brakmic"}, 
      {"1", "Arthur", "Sonzogni"}, 
      {"2", "Bosiljka", "Brakmic" } 
    };
    auto tbl = Table(data) | group_by("Surname");
    

    Rendered output would look something like this

    
    Id       Name
    
    Surname: Brakmic
    -----------------------------
    0        Aleksandar
    2        Bosiljka
    
    Surname: Sonzogni
    ----------------------------
    1        Arthur
    

    It would consider first data element a header row. Order by functionality like this would be nice aswell. :)

    Is that something that would fit into this library or is it out of scope of it?

    opened by brakmic-aleksandar 5
  • Line break in East Asian paragraphs

    Line break in East Asian paragraphs

    Hi @ArthurSonzogni , you might not be aware that some scripts doesn't use space as word separator. Currently, there's no line break in a paragraph of Chinese text. It is always displayed in one line.

    图片

    According to my knowledge, the rules of line breaking for Chinese is: Line break can be inserted anywhere in text, except before some punctuations and after some (other) punctuations. For example, we don't want to see a comma U+FF0C FULLWIDTH COMMA at the start of a line, nor do we want to see an opening bracket U+FF08 FULLWIDTH LEFT PARENTHESIS at the end of a line.

    I think the rules are simmilar for Japanese and Korean, with some slightly different preferences over prohibited punctuations for line start/end.

    enhancement help wanted 
    opened by Zjl37 5
Releases(v3.0.0)
Owner
Arthur Sonzogni
Love C++. - Image rendering / analysis. - Ascii art / TUI. - Games
Arthur Sonzogni
Spitfire is a basic terminal language that can exicute code via the terminal.

Spitfire is a basic terminal language that can exicute code via the terminal. It is easy to learn and runs fast, considering that its just a 300 line c++ file.

jhomas tefferson 0 Nov 18, 2021
Collection of human friendly terminal interface for git.

A collection of human friendly terminal user interface for git.

Arthur Sonzogni 60 May 5, 2022
ImTui: Immediate Mode Text-based User Interface

imtui ImTui is an immediate mode text-based user interface library. Supports 256 ANSI colors and mouse/keyboard input. Live demo in the browser Eventh

Georgi Gerganov 1.8k May 10, 2022
Fire for C++: Create fully functional CLIs using function signatures

Fire for C++ Fire for C++, inspired by python-fire, is a single header library that creates a command line interface from a function signature. Here's

Kristjan Kongas 434 May 9, 2022
A wrapper of C++ std::vector for functional programming

Say hello to functional C++ vectors A wrapper for C++ std::vector geared towards functional programming and fluent APIs. The primary focus is readabil

null 17 Feb 18, 2022
Small header only C++ library for writing multiplatform terminal applications

Terminal Terminal is small header only library for writing terminal applications. It works on Linux, macOS and Windows (in the native cmd.exe console)

Jupyter Xeus 198 May 14, 2022
A little UNIX-inspired terminal application for the Numworks Calculator (not using escher).

L.E. Terminal (let for short) is a little UNIX-inspired terminal for the Numworks Calculator.

Cacahuète Sans Sel 18 Apr 27, 2022
Draw sequence diagram in text from terminal.

sequence-diagram-cli Draw seqence diagram from terminal.

null 42 Feb 28, 2022
Terminal calculator made for programmers working with multiple number representations, sizes, and overall close to the bits

Programmer calculator The programmer calculator is a simple terminal tool designed to give maximum efficiency and flexibility to the programmer workin

romes 164 May 8, 2022
X terminal emulator rendering through OpenGL ES Compute Shaders

Zutty is a terminal emulator for the X Window System, functionally similar to several other X terminal emulators such as xterm, rxvt and countless others

Tom Szilagyi 207 May 12, 2022
The new Windows Terminal and the original Windows console host, all in the same place!

The new Windows Terminal and the original Windows console host, all in the same place!

Microsoft 83.1k May 16, 2022
n³ The unorthodox terminal file manager

n³ The unorthodox terminal file manager

Mischievous Meerkat 14.1k May 17, 2022
Graphs the activity of a chia harvester in a linux terminal.

Chia Harvest Graph Monitor for Chia Harvesting Introduction The chiaharvestgraph tool will graph Chia Harvesting activity in a linux terminal. Use a 2

Bram Stolk 219 May 2, 2022
a simple to use linux terminal

a simple to use linux terminal

notaweeb 7 Feb 17, 2022
Simple benchmark for terminal output

TermBench This is a simple timing utility you can use to see how slow your terminal program is at parsing escape-sequence-coded color output. It can b

Casey Muratori 169 May 9, 2022
tinytetris - 80x23 terminal tetris

tinytetris - 80x23 terminal tetris

Conor Taylor 1.6k May 9, 2022
Contour - A modern C++ Terminal Emulator

contour is a modern terminal emulator, for everyday use. It is aiming for power users with a modern feature mindset.

Contour Terminal Emulator 805 May 10, 2022
A C, C++ and Rust library to draw graphics with pixels in the terminal

A library to draw graphics with pixels in the terminal Who needs a GUI when you have a terminal ? Building To generate libpluto.a, run: $ make To ins

null 67 Apr 9, 2022
📺🗿 Terminal graphics for the 21st century.

???? Chafa is a command-line utility that converts all kinds of images, including animated GIFs, into sixel or ANSI/Unicode character output that can be displayed in a terminal.

Hans Petter Jansson 1.3k May 16, 2022