Prefer std::string over std::wstring. (#179)

In the past, FTXUI switched from std::string to std::wstring to support
fullwidth characters. The reasons was that fullwidth characters can be
stored inside a single wchar_t.

Then FTXUI added support for combining characters. A single glygh
doesn't even fit a wchar_t. Instead, a glyph can be arbitrary large.

The usage of wstring doesn't really fit the new model and have several
drawbacks:
1. It doesn't simplify the implementation of FTXUI, because of combining
   characters.
2. It reduces drawing performance by 2x.
3. It increase Screen's memory allocation by 2x.

This patch converts FTXUI to use std::string internally. It now exposes
std::string based API. The std::wstring API remains, but is now
deprecated.

Tests and examples haven't been update to show the breakage is limited.
They will be updated in a second set of patches.

Bug: https://github.com/ArthurSonzogni/FTXUI/issues/153
Co-authored-by: Tushar Maheshwari <tushar27192@gmail.com>
This commit is contained in:
Arthur Sonzogni 2021-08-08 23:25:20 +02:00 committed by GitHub
parent 1ff894f6f5
commit 3b4ab618a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
84 changed files with 1234 additions and 996 deletions

View File

@ -4,7 +4,7 @@ include(cmake/ftxui_git_version.cmake)
project(ftxui project(ftxui
LANGUAGES CXX LANGUAGES CXX
VERSION 0.7.${git_version} VERSION 0.8.${git_version}
) )
option(FTXUI_BUILD_DOCS "Set to ON to build tests" ON) option(FTXUI_BUILD_DOCS "Set to ON to build tests" ON)
@ -31,7 +31,6 @@ add_library(screen STATIC
src/ftxui/screen/screen.cpp src/ftxui/screen/screen.cpp
src/ftxui/screen/string.cpp src/ftxui/screen/string.cpp
src/ftxui/screen/terminal.cpp src/ftxui/screen/terminal.cpp
src/ftxui/screen/wcwidth.cpp
include/ftxui/screen/box.hpp include/ftxui/screen/box.hpp
include/ftxui/screen/color.hpp include/ftxui/screen/color.hpp
include/ftxui/screen/color_info.hpp include/ftxui/screen/color_info.hpp

View File

@ -23,6 +23,7 @@ add_executable(tests
src/ftxui/dom/hbox_test.cpp src/ftxui/dom/hbox_test.cpp
src/ftxui/dom/text_test.cpp src/ftxui/dom/text_test.cpp
src/ftxui/dom/vbox_test.cpp src/ftxui/dom/vbox_test.cpp
src/ftxui/screen/string_test.cpp
) )
target_link_libraries(tests target_link_libraries(tests

View File

@ -6,7 +6,8 @@
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/component_options.hpp" // for ButtonOption #include "ftxui/component/component_options.hpp" // for ButtonOption
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for separator, gauge, text, Element, operator|, vbox, border #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for separator, gauge, Element, operator|, vbox, border
using namespace ftxui; using namespace ftxui;

View File

@ -6,7 +6,8 @@
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/component_options.hpp" // for ButtonOption #include "ftxui/component/component_options.hpp" // for ButtonOption
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for text, separator, Element, operator|, vbox, border #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for separator, Element, operator|, vbox, border
using namespace ftxui; using namespace ftxui;

View File

@ -4,10 +4,12 @@
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Slider, Checkbox, Vertical, Renderer, Button, Input, Menu, Radiobox, Toggle #include "ftxui/component/component.hpp" // for Slider, Checkbox, Vertical, Renderer, Button, Menu, Radiobox, Toggle
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/deprecated.hpp" // for Input
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for separator, Element, operator|, size, xflex, text, WIDTH, hbox, vbox, EQUAL, border, GREATER_THAN #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for separator, operator|, Element, size, xflex, WIDTH, hbox, vbox, EQUAL, border, GREATER_THAN
using namespace ftxui; using namespace ftxui;

View File

@ -9,12 +9,14 @@
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Input, Menu, Radiobox, Tab, Toggle #include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Menu, Radiobox, Tab, Toggle
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/component_options.hpp" // for InputOption #include "ftxui/component/component_options.hpp" // for InputOption
#include "ftxui/component/deprecated.hpp" // for Input
#include "ftxui/component/event.hpp" // for Event, Event::Custom #include "ftxui/component/event.hpp" // for Event, Event::Custom
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for text, operator|, color, bgcolor, filler, Element, size, vbox, flex, hbox, graph, separator, EQUAL, WIDTH, hcenter, bold, border, window, HEIGHT, Elements, hflow, flex_grow, frame, gauge, LESS_THAN, spinner, dim, GREATER_THAN #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for operator|, color, bgcolor, filler, Element, size, vbox, flex, hbox, graph, separator, EQUAL, WIDTH, hcenter, bold, border, window, HEIGHT, Elements, hflow, flex_grow, frame, gauge, LESS_THAN, spinner, dim, GREATER_THAN
#include "ftxui/screen/color.hpp" // for Color, Color::BlueLight, Color::RedLight, Color::Black, Color::Blue, Color::Cyan, Color::CyanLight, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::White, Color::Yellow, Color::YellowLight, Color::Default #include "ftxui/screen/color.hpp" // for Color, Color::BlueLight, Color::RedLight, Color::Black, Color::Blue, Color::Cyan, Color::CyanLight, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::White, Color::Yellow, Color::YellowLight, Color::Default
using namespace ftxui; using namespace ftxui;

View File

@ -2,11 +2,13 @@
#include <string> // for char_traits, operator+, wstring, basic_string #include <string> // for char_traits, operator+, wstring, basic_string
#include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Input, Renderer, Vertical #include "ftxui/component/component.hpp" // for Renderer, Vertical
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/component_options.hpp" // for InputOption #include "ftxui/component/component_options.hpp" // for InputOption
#include "ftxui/component/deprecated.hpp" // for Input
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for text, hbox, separator, Element, operator|, vbox, border #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for hbox, separator, Element, operator|, vbox, border
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -8,7 +8,8 @@
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/component_options.hpp" // for MenuOption #include "ftxui/component/component_options.hpp" // for MenuOption
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for text, separator, bold, hcenter, vbox, hbox, gauge, Element, operator|, border #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for separator, bold, hcenter, vbox, hbox, gauge, Element, operator|, border
#include "ftxui/screen/string.hpp" // for to_wstring #include "ftxui/screen/string.hpp" // for to_wstring
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {

View File

@ -1,13 +1,14 @@
#include <stdlib.h> // for EXIT_SUCCESS #include <stdlib.h> // for EXIT_SUCCESS
#include <memory> // for __shared_ptr_access #include <memory> // for allocator, __shared_ptr_access
#include <string> // for wstring, allocator, operator+, basic_string, char_traits #include <string> // for wstring, operator+, basic_string, char_traits
#include <vector> // for vector, __alloc_traits<>::value_type #include <vector> // for vector, __alloc_traits<>::value_type
#include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Menu, Renderer, Horizontal, Vertical #include "ftxui/component/component.hpp" // for Menu, Renderer, Horizontal, Vertical
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for text, Element, operator|, window, flex, vbox #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for Element, operator|, window, flex, vbox
#include "ftxui/screen/string.hpp" // for to_wstring #include "ftxui/screen/string.hpp" // for to_wstring
using namespace ftxui; using namespace ftxui;

View File

@ -1,12 +1,13 @@
#include <memory> // for allocator, __shared_ptr_access, shared_ptr #include <memory> // for allocator, shared_ptr, __shared_ptr_access
#include <string> // for wstring, operator+, basic_string, char_traits #include <string> // for wstring, basic_string, char_traits, operator+
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Button, Renderer, Horizontal, Tab #include "ftxui/component/component.hpp" // for Button, Renderer, Horizontal, Tab
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for Element, operator|, filler, text, hbox, separator, center, vbox, bold, border, clear_under, dbox, size, GREATER_THAN, HEIGHT #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for operator|, Element, filler, hbox, separator, center, vbox, bold, border, clear_under, dbox, size, GREATER_THAN, HEIGHT
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -4,8 +4,8 @@
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <algorithm> // for max #include <algorithm> // for max
#include <memory> // for shared_ptr #include <memory> // for allocator, shared_ptr
#include <string> // for allocator, char_traits, operator+, wstring, basic_string, to_wstring, string #include <string> // for char_traits, operator+, string, basic_string, to_string
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector #include <vector> // for vector
@ -18,56 +18,56 @@
using namespace ftxui; using namespace ftxui;
std::wstring Stringify(Event event) { std::string Stringify(Event event) {
std::wstring out; std::string out;
for (auto& it : event.input()) for (auto& it : event.input())
out += L" " + std::to_wstring((unsigned int)it); out += " " + std::to_string((unsigned int)it);
out = L"(" + out + L" ) -> "; out = "(" + out + " ) -> ";
if (event.is_character()) { if (event.is_character()) {
out += std::wstring(L"character(") + event.character() + L")"; out += "character(" + event.character() + ")";
} else if (event.is_mouse()) { } else if (event.is_mouse()) {
out += L"mouse"; out += "mouse";
switch (event.mouse().button) { switch (event.mouse().button) {
case Mouse::Left: case Mouse::Left:
out += L"_left"; out += "_left";
break; break;
case Mouse::Middle: case Mouse::Middle:
out += L"_middle"; out += "_middle";
break; break;
case Mouse::Right: case Mouse::Right:
out += L"_right"; out += "_right";
break; break;
case Mouse::None: case Mouse::None:
out += L"_none"; out += "_none";
break; break;
case Mouse::WheelUp: case Mouse::WheelUp:
out += L"_wheel_up"; out += "_wheel_up";
break; break;
case Mouse::WheelDown: case Mouse::WheelDown:
out += L"_wheel_down"; out += "_wheel_down";
break; break;
} }
switch (event.mouse().motion) { switch (event.mouse().motion) {
case Mouse::Pressed: case Mouse::Pressed:
out += L"_pressed"; out += "_pressed";
break; break;
case Mouse::Released: case Mouse::Released:
out += L"_released"; out += "_released";
break; break;
} }
if (event.mouse().control) if (event.mouse().control)
out += L"_control"; out += "_control";
if (event.mouse().shift) if (event.mouse().shift)
out += L"_shift"; out += "_shift";
if (event.mouse().meta) if (event.mouse().meta)
out += L"_meta"; out += "_meta";
out += L"(" + // out += "(" + //
std::to_wstring(event.mouse().x) + L"," + std::to_string(event.mouse().x) + "," +
std::to_wstring(event.mouse().y) + L")"; std::to_string(event.mouse().y) + ")";
} else { } else {
out += L"(special)"; out += "(special)";
} }
return out; return out;
} }
@ -81,7 +81,7 @@ int main(int argc, const char* argv[]) {
Elements children; Elements children;
for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i) for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i)
children.push_back(text(Stringify(keys[i]))); children.push_back(text(Stringify(keys[i])));
return window(text(L"keys"), vbox(std::move(children))); return window(text("keys"), vbox(std::move(children)));
}); });
component = CatchEvent(component, [&](Event event) { component = CatchEvent(component, [&](Event event) {

View File

@ -4,7 +4,8 @@
#include "ftxui/component/component.hpp" // for Renderer, Button, Vertical #include "ftxui/component/component.hpp" // for Renderer, Button, Vertical
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for operator|, Element, text, bold, border, center, color #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for operator|, Element, bold, border, center, color
#include "ftxui/screen/color.hpp" // for Color, Color::Red #include "ftxui/screen/color.hpp" // for Color, Color::Red
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {

View File

@ -4,7 +4,8 @@
#include "ftxui/component/component.hpp" // for Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop #include "ftxui/component/component.hpp" // for Renderer, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for Element, operator|, text, center, border #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for Element, operator|, center, border
using namespace ftxui; using namespace ftxui;

View File

@ -1,11 +1,12 @@
#include <memory> // for allocator, __shared_ptr_access, shared_ptr #include <memory> // for allocator, shared_ptr, __shared_ptr_access
#include <string> // for operator+, to_wstring, char_traits #include <string> // for char_traits, operator+, to_wstring
#include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Slider, Renderer, Vertical #include "ftxui/component/component.hpp" // for Slider, Renderer, Vertical
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for separator, Element, operator|, size, text, vbox, xflex, bgcolor, hbox, GREATER_THAN, WIDTH, border, HEIGHT, LESS_THAN #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for separator, operator|, Element, size, vbox, xflex, bgcolor, hbox, GREATER_THAN, WIDTH, border, HEIGHT, LESS_THAN
#include "ftxui/screen/color.hpp" // for Color #include "ftxui/screen/color.hpp" // for Color
using namespace ftxui; using namespace ftxui;

View File

@ -6,7 +6,8 @@
#include "ftxui/component/component.hpp" // for Toggle, Renderer, Vertical #include "ftxui/component/component.hpp" // for Toggle, Renderer, Vertical
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for text, hbox, vbox, Element #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for hbox, vbox, Element
using namespace ftxui; using namespace ftxui;

View File

@ -1,9 +1,10 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, vbox, border, Element, hbox
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -7,7 +7,8 @@
using namespace ftxui; using namespace ftxui;
#include "./color_info_sorted_2d.ipp" // for ColorInfoSorted2D #include "./color_info_sorted_2d.ipp" // for ColorInfoSorted2D
#include "ftxui/dom/elements.hpp" // for text, bgcolor, color, vbox, hbox, separator, operator|, Elements, Element, border #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for bgcolor, color, vbox, hbox, separator, operator|, Elements, Element, border
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/color.hpp" // for Color, Color::Black, Color::Blue, Color::BlueLight, Color::Cyan, Color::CyanLight, Color::Default, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::RedLight, Color::White, Color::Yellow, Color::YellowLight, Color::Palette256, ftxui #include "ftxui/screen/color.hpp" // for Color, Color::Black, Color::Blue, Color::BlueLight, Color::Cyan, Color::CyanLight, Color::Default, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::RedLight, Color::White, Color::Yellow, Color::YellowLight, Color::Palette256, ftxui

View File

@ -1,17 +1,18 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for bgcolor, hbox, operator|, Elements, vbox, Element
#include <ftxui/screen/color_info.hpp> #include <ftxui/screen/color_info.hpp> // for ColorInfo
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <string> #include <string> // for allocator, string
#include <utility> #include <utility> // for move
#include <vector> #include <vector> // for vector
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/color.hpp" #include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/string.hpp" #include "ftxui/screen/color.hpp" // for Color, Color::Palette256
#include "ftxui/screen/string.hpp" // for to_wstring
using namespace ftxui; using namespace ftxui;
#include "./color_info_sorted_2d.ipp" // ColorInfoSorted2D. #include "./color_info_sorted_2d.ipp" // for ColorInfoSorted2D
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
std::vector<std::vector<ColorInfo>> info_columns = ColorInfoSorted2D(); std::vector<std::vector<ColorInfo>> info_columns = ColorInfoSorted2D();

View File

@ -1,11 +1,12 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, Elements, bgcolor, color, hbox, vbox, Element
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include <utility> #include <utility> // for move
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/color.hpp" #include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,11 +1,12 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for hbox, bgcolor, operator|, vbox, Elements, window, Element
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include <utility> #include <utility> // for move
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/color.hpp" #include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,9 +1,10 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, border, Element, vbox, center, dbox
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,12 +1,13 @@
#include <chrono> #include <chrono> // for operator""s, chrono_literals
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for gauge, operator|, flex, hbox, Element
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Screen
#include <iostream> #include <iostream> // for cout, endl, ostream
#include <string> #include <string> // for allocator, operator+, char_traits, operator<<, to_wstring, basic_string, string, wstring
#include <thread> #include <thread> // for sleep_for
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,10 +1,11 @@
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <ftxui/dom/elements.hpp> // for operator|, size, Element, text, hcenter, Decorator, WIDTH, hflow, window, EQUAL, GREATER_THAN, HEIGHT, bold, border, dim, LESS_THAN #include <ftxui/dom/elements.hpp> // for operator|, size, Element, hcenter, Decorator, WIDTH, hflow, window, EQUAL, GREATER_THAN, HEIGHT, bold, border, dim, LESS_THAN
#include <ftxui/screen/screen.hpp> // for Dimension, Screen #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <ftxui/screen/string.hpp> // for to_wstring #include <ftxui/screen/string.hpp> // for to_wstring
#include <memory> // for shared_ptr #include <memory> // for allocator, shared_ptr
#include <string> // for allocator, operator+, char_traits, wstring #include <string> // for operator+, char_traits, wstring
#include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/box.hpp" // for ftxui

View File

@ -5,7 +5,8 @@
#include <string> // for operator<<, string #include <string> // for operator<<, string
#include <thread> // for sleep_for #include <thread> // for sleep_for
#include "ftxui/dom/elements.hpp" // for paragraph, text, operator|, Element, border, color, hflow, spinner, vbox, bold, dim, underlined #include "ftxui/dom/deprecated.hpp" // for paragraph, text
#include "ftxui/dom/elements.hpp" // for operator|, Element, border, color, hflow, spinner, vbox, bold, dim, underlined
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color, Color::Red #include "ftxui/screen/color.hpp" // for Color, Color::Red

View File

@ -1,18 +1,19 @@
#include <chrono> #include <chrono> // for operator""s, chrono_literals
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, Element, hbox, bold, color, filler, separator, vbox, window, gauge, size, dim, EQUAL, WIDTH
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Screen, Dimension
#include <ftxui/screen/string.hpp> #include <ftxui/screen/string.hpp> // for to_wstring
#include <iostream> #include <iostream> // for cout, endl, ostream
#include <list> #include <list> // for list, operator!=, _List_iterator, _List_iterator<>::_Self
#include <memory> #include <memory> // for allocator, shared_ptr, allocator_traits<>::value_type
#include <string> #include <string> // for wstring, operator<<, string
#include <thread> #include <thread> // for sleep_for
#include <utility> #include <utility> // for move
#include <vector> #include <vector> // for vector
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/color.hpp" #include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color, Color::Green, Color::Red, Color::RedLight
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,10 +1,11 @@
#include <stdio.h> #include <stdio.h> // for getchar
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, hflow, border, Element, hbox, flex, vbox
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <string> #include <string> // for allocator, wstring
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for paragraph
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,9 +1,10 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for center, separator, operator|, flex, Element, vbox, hbox, border
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,12 +1,13 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, Element, hcenter, hbox, size, window, Elements, bold, dim, EQUAL, WIDTH
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Screen, Dimension
#include <ftxui/screen/string.hpp> #include <ftxui/screen/string.hpp> // for to_wstring
#include <memory> #include <memory> // for allocator, shared_ptr
#include <string> #include <string> // for wstring
#include <utility> #include <utility> // for move
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,15 +1,16 @@
#include <chrono> #include <chrono> // for operator""s, chrono_literals
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for Element, operator|, separator, filler, hbox, size, spinner, vbox, bold, border, EQUAL, WIDTH
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Screen, Dimension
#include <ftxui/screen/string.hpp> #include <ftxui/screen/string.hpp> // for to_wstring
#include <iostream> #include <iostream> // for cout, endl, ostream
#include <string> #include <string> // for operator<<, string
#include <thread> #include <thread> // for sleep_for
#include <utility> #include <utility> // for move
#include <vector> #include <vector> // for vector
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,9 +1,10 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, blink, hbox, Element
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,9 +1,10 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, bold, hbox, Element
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,7 +1,8 @@
#include <ftxui/screen/screen.hpp> // for Dimension, Screen #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/elements.hpp" // for text, bgcolor, color, vbox, filler, hbox #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for bgcolor, color, vbox, filler, hbox
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color, Color::Black, Color::Blue, Color::BlueLight, Color::Cyan, Color::CyanLight, Color::Default, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::RedLight, Color::White, Color::Yellow, Color::YellowLight #include "ftxui/screen/color.hpp" // for Color, Color::Black, Color::Blue, Color::BlueLight, Color::Cyan, Color::CyanLight, Color::Default, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::RedLight, Color::White, Color::Yellow, Color::YellowLight

View File

@ -1,9 +1,10 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, dim, hbox, Element
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,10 +1,11 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, Element, bgcolor, color, blink, bold, dim, inverted, underlined, hbox
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/color.hpp" #include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color, Color::Blue
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,9 +1,10 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, inverted, hbox, Element
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,9 +1,10 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, underlined, hbox, Element
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Dimension, Screen
#include <memory> #include <memory> // for allocator
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,10 +1,11 @@
#include <stdio.h> #include <stdio.h> // for getchar
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for filler, hbox, vbox
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Screen, Dimension
#include <memory> #include <memory> // for allocator
#include "ftxui/dom/node.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -9,7 +9,7 @@
#include "ftxui/component/component_base.hpp" // for Component, Components #include "ftxui/component/component_base.hpp" // for Component, Components
#include "ftxui/component/component_options.hpp" // for ButtonOption, CheckboxOption, InputOption, MenuOption, RadioboxOption, ToggleOption #include "ftxui/component/component_options.hpp" // for ButtonOption, CheckboxOption, InputOption, MenuOption, RadioboxOption, ToggleOption
#include "ftxui/dom/elements.hpp" // for Element #include "ftxui/dom/elements.hpp" // for Element
#include "ftxui/util/ref.hpp" // for Ref, ConstStringRef, StringRef #include "ftxui/util/ref.hpp" // for Ref, ConstStringRef, ConstStringListRef, StringRef
namespace ftxui { namespace ftxui {
struct ButtonOption; struct ButtonOption;
@ -34,17 +34,17 @@ Component Checkbox(ConstStringRef label,
Component Input(StringRef content, Component Input(StringRef content,
ConstStringRef placeholder, ConstStringRef placeholder,
Ref<InputOption> option = {}); Ref<InputOption> option = {});
Component Menu(const std::vector<std::wstring>* entries, Component Menu(ConstStringListRef entries,
int* selected_, int* selected_,
Ref<MenuOption> = {}); Ref<MenuOption> = {});
Component Radiobox(const std::vector<std::wstring>* entries, Component Radiobox(ConstStringListRef entries,
int* selected_, int* selected_,
Ref<RadioboxOption> option = {}); Ref<RadioboxOption> option = {});
Component Toggle(const std::vector<std::wstring>* entries, Component Toggle(ConstStringListRef entries,
int* selected, int* selected,
Ref<ToggleOption> option = {}); Ref<ToggleOption> option = {});
template <class T> // T = {int, float, long} template <class T> // T = {int, float, long}
Component Slider(StringRef label, T* value, T min, T max, T increment); Component Slider(ConstStringRef label, T* value, T min, T max, T increment);
Component ResizableSplitLeft(Component main, Component back, int* main_size); Component ResizableSplitLeft(Component main, Component back, int* main_size);
Component ResizableSplitRight(Component main, Component back, int* main_size); Component ResizableSplitRight(Component main, Component back, int* main_size);
Component ResizableSplitTop(Component main, Component back, int* main_size); Component ResizableSplitTop(Component main, Component back, int* main_size);
@ -65,6 +65,9 @@ Component Tab(Components children, int* selector);
} // namespace ftxui } // namespace ftxui
// Include component using the old deprecated wstring.
#include "ftxui/component/deprecated.hpp"
#endif /* end of include guard: FTXUI_COMPONENT_HPP */ #endif /* end of include guard: FTXUI_COMPONENT_HPP */
// Copyright 2021 Arthur Sonzogni. All rights reserved. // Copyright 2021 Arthur Sonzogni. All rights reserved.

View File

@ -33,8 +33,8 @@ struct ButtonOption {
/// @brief Option for the Checkbox component. /// @brief Option for the Checkbox component.
/// @ingroup component /// @ingroup component
struct CheckboxOption { struct CheckboxOption {
std::wstring style_checked = L""; ///< Prefix for a "checked" state. std::string style_checked = ""; ///< Prefix for a "checked" state.
std::wstring style_unchecked = L""; ///< Prefix for a "unchecked" state. std::string style_unchecked = ""; ///< Prefix for a "unchecked" state.
Decorator style_focused = inverted; ///< Decorator used when focused. Decorator style_focused = inverted; ///< Decorator used when focused.
Decorator style_unfocused = nothing; ///< Decorator used when unfocused. Decorator style_unfocused = nothing; ///< Decorator used when unfocused.
@ -59,8 +59,8 @@ struct InputOption {
/// @brief Option for the Radiobox component. /// @brief Option for the Radiobox component.
/// @ingroup component /// @ingroup component
struct RadioboxOption { struct RadioboxOption {
std::wstring style_checked = L""; ///< Prefix for a "checked" state. std::string style_checked = ""; ///< Prefix for a "checked" state.
std::wstring style_unchecked = L""; ///< Prefix for a "unchecked" state. std::string style_unchecked = ""; ///< Prefix for a "unchecked" state.
Decorator style_focused = inverted; ///< Decorator used when focused. Decorator style_focused = inverted; ///< Decorator used when focused.
Decorator style_unfocused = nothing; ///< Decorator used when unfocused. Decorator style_unfocused = nothing; ///< Decorator used when unfocused.

View File

@ -0,0 +1,17 @@
#ifndef FTXUI_COMPONENT_DEPRECATED_HPP
#define FTXUI_COMPONENT_DEPRECATED_HPP
#include "ftxui/component/component.hpp"
namespace ftxui {
Component Input(WideStringRef content,
ConstStringRef placeholder,
Ref<InputOption> option = {});
} // namespace ftxui
#endif /* FTXUI_COMPONENT_DEPRECATED_HPP */
// Copyright 2021 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -24,10 +24,9 @@ class ComponentBase;
/// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html /// https://invisible-island.net/xterm/ctlseqs/ctlseqs.html
struct Event { struct Event {
// --- Constructor section --------------------------------------------------- // --- Constructor section ---------------------------------------------------
static Event Character(std::string);
static Event Character(char); static Event Character(char);
static Event Character(wchar_t); static Event Character(wchar_t);
static Event Character(std::string);
static Event Special(std::string); static Event Special(std::string);
static Event Mouse(std::string, Mouse mouse); static Event Mouse(std::string, Mouse mouse);
static Event CursorReporting(std::string, int x, int y); static Event CursorReporting(std::string, int x, int y);
@ -58,7 +57,7 @@ struct Event {
//--- Method section --------------------------------------------------------- //--- Method section ---------------------------------------------------------
bool is_character() const { return type_ == Type::Character; } bool is_character() const { return type_ == Type::Character; }
wchar_t character() const { return character_; } std::string character() const { return input_; }
bool is_mouse() const { return type_ == Type::Mouse; } bool is_mouse() const { return type_ == Type::Mouse; }
struct Mouse& mouse() { struct Mouse& mouse() {
@ -92,7 +91,6 @@ struct Event {
}; };
union { union {
wchar_t character_ = U'?';
struct Mouse mouse_; struct Mouse mouse_;
struct Cursor cursor_; struct Cursor cursor_;
}; };

View File

@ -0,0 +1,16 @@
#ifndef FTXUI_DOM_DEPRECRATED_HPP
#define FTXUI_DOM_DEPRECRATED_HPP
#include "ftxui/dom/elements.hpp"
namespace ftxui {
Element text(std::wstring text);
Element vtext(std::wstring text);
Elements paragraph(std::wstring text);
} // namespace ftxui
#endif /* end of include guard: FTXUI_DOM_DEPRECRATED_HPP */
// Copyright 2021 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -26,8 +26,8 @@ Elements operator|(Elements, Decorator);
Decorator operator|(Decorator, Decorator); Decorator operator|(Decorator, Decorator);
// --- Widget --- // --- Widget ---
Element text(std::wstring text); Element text(std::string text);
Element vtext(std::wstring text); Element vtext(std::string text);
Element separator(void); Element separator(void);
Element separator(Pixel); Element separator(Pixel);
Element gauge(float ratio); Element gauge(float ratio);
@ -35,7 +35,7 @@ Element border(Element);
Decorator borderWith(Pixel); Decorator borderWith(Pixel);
Element window(Element title, Element content); Element window(Element title, Element content);
Element spinner(int charset_index, size_t image_index); Element spinner(int charset_index, size_t image_index);
Elements paragraph(std::wstring text); // Use inside hflow(). Split by space. Elements paragraph(std::string text); // Use inside hflow(). Split by space.
Element graph(GraphFunction); Element graph(GraphFunction);
// -- Decorator --- // -- Decorator ---
@ -112,6 +112,8 @@ Dimensions Fit(Element&);
// Make container able to take any number of children as input. // Make container able to take any number of children as input.
#include "ftxui/dom/take_any_args.hpp" #include "ftxui/dom/take_any_args.hpp"
// Include old definitions using wstring.
#include "ftxui/dom/deprecated.hpp"
#endif /* end of include guard: FTXUI_DOM_ELEMENTS_HPP */ #endif /* end of include guard: FTXUI_DOM_ELEMENTS_HPP */
// Copyright 2020 Arthur Sonzogni. All rights reserved. // Copyright 2020 Arthur Sonzogni. All rights reserved.

View File

@ -303,7 +303,7 @@ class Color {
bool operator==(const Color& rhs) const; bool operator==(const Color& rhs) const;
bool operator!=(const Color& rhs) const; bool operator!=(const Color& rhs) const;
std::wstring Print(bool is_background_color) const; std::string Print(bool is_background_color) const;
private: private:
enum class ColorType : uint8_t { enum class ColorType : uint8_t {

View File

@ -2,7 +2,7 @@
#define FTXUI_SCREEN_SCREEN #define FTXUI_SCREEN_SCREEN
#include <memory> #include <memory>
#include <string> // for allocator, wstring, string, basic_string #include <string> // for string, allocator, basic_string
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
@ -16,8 +16,7 @@ namespace ftxui {
struct Pixel { struct Pixel {
// The graphemes stored into the pixel. To support combining characters, // The graphemes stored into the pixel. To support combining characters,
// like: a⃦, this can potentially contains multiple codepoitns. // like: a⃦, this can potentially contains multiple codepoitns.
// Required: character.size() >= 1; std::string character = " ";
std::wstring character = L" ";
// Colors: // Colors:
Color background_color = Color::Default; Color background_color = Color::Default;
@ -55,7 +54,7 @@ class Screen {
static Screen Create(Dimensions width, Dimensions height); static Screen Create(Dimensions width, Dimensions height);
// Node write into the screen using Screen::at. // Node write into the screen using Screen::at.
wchar_t& at(int x, int y); std::string& at(int x, int y);
Pixel& PixelAt(int x, int y); Pixel& PixelAt(int x, int y);
// Convert the screen into a printable string in the terminal. // Convert the screen into a printable string in the terminal.

View File

@ -2,6 +2,7 @@
#define FTXUI_SCREEN_STRING_HPP #define FTXUI_SCREEN_STRING_HPP
#include <string> #include <string>
#include <vector>
namespace ftxui { namespace ftxui {
std::string to_string(const std::wstring& s); std::string to_string(const std::wstring& s);
@ -12,12 +13,10 @@ std::wstring to_wstring(T s) {
return to_wstring(std::to_string(s)); return to_wstring(std::to_string(s));
} }
int wchar_width(char32_t);
int wchar_width(wchar_t); int wchar_width(wchar_t);
int wchar_width_cjk(char32_t);
int wchar_width_cjk(wchar_t);
int wstring_width(const std::wstring&); int wstring_width(const std::wstring&);
int wstring_width_cjk(const std::wstring&); int string_width(const std::string&);
std::vector<std::string> Utf8ToGlyphs(const std::string& input);
} // namespace ftxui } // namespace ftxui

View File

@ -42,11 +42,27 @@ class Ref {
/// class convert multiple mutable string toward a shared representation. /// class convert multiple mutable string toward a shared representation.
class StringRef { class StringRef {
public: public:
StringRef(std::wstring* ref) : address_(ref) {} StringRef(std::string* ref) : address_(ref) {}
StringRef(std::wstring ref) : owned_(std::move(ref)) {} StringRef(std::string ref) : owned_(std::move(ref)) {}
StringRef(const wchar_t* ref) : StringRef(std::wstring(ref)) {} StringRef(const wchar_t* ref) : StringRef(to_string(std::wstring(ref))) {}
StringRef(const char* ref) : StringRef(to_wstring(std::string(ref))) {} StringRef(const char* ref) : StringRef(std::string(ref)) {}
StringRef(std::string ref) : StringRef(to_wstring(std::move(ref))) {} std::string& operator*() { return address_ ? *address_ : owned_; }
std::string* operator->() { return address_ ? address_ : &owned_; }
private:
std::string owned_;
std::string* address_ = nullptr;
};
/// @brief An adapter. Own or reference a constant string. For convenience, this
/// class convert multiple mutable string toward a shared representation.
class WideStringRef {
public:
WideStringRef(std::wstring* ref) : address_(ref) {}
WideStringRef(std::wstring ref) : owned_(std::move(ref)) {}
WideStringRef(const wchar_t* ref) : WideStringRef(std::wstring(ref)) {}
WideStringRef(const char* ref)
: WideStringRef(to_wstring(std::string(ref))) {}
std::wstring& operator*() { return address_ ? *address_ : owned_; } std::wstring& operator*() { return address_ ? *address_ : owned_; }
std::wstring* operator->() { return address_ ? address_ : &owned_; } std::wstring* operator->() { return address_ ? address_ : &owned_; }
@ -59,19 +75,35 @@ class StringRef {
/// class convert multiple immutable string toward a shared representation. /// class convert multiple immutable string toward a shared representation.
class ConstStringRef { class ConstStringRef {
public: public:
ConstStringRef(const std::wstring* ref) : address_(ref) {} ConstStringRef(const std::string* ref) : address_(ref) {}
ConstStringRef(std::wstring ref) : owned_(std::move(ref)) {} ConstStringRef(const std::wstring* ref) : ConstStringRef(to_string(*ref)) {}
ConstStringRef(std::string ref) : owned_(std::move(ref)) {}
ConstStringRef(std::wstring ref) : ConstStringRef(to_string(ref)) {}
ConstStringRef(const wchar_t* ref) : ConstStringRef(std::wstring(ref)) {} ConstStringRef(const wchar_t* ref) : ConstStringRef(std::wstring(ref)) {}
ConstStringRef(const char* ref) ConstStringRef(const char* ref)
: ConstStringRef(to_wstring(std::string(ref))) {} : ConstStringRef(to_wstring(std::string(ref))) {}
ConstStringRef(std::string ref) const std::string& operator*() { return address_ ? *address_ : owned_; }
: ConstStringRef(to_wstring(std::move(ref))) {} const std::string* operator->() { return address_ ? address_ : &owned_; }
const std::wstring& operator*() { return address_ ? *address_ : owned_; }
const std::wstring* operator->() { return address_ ? address_ : &owned_; }
private: private:
const std::wstring owned_; const std::string owned_;
const std::wstring* address_ = nullptr; const std::string* address_ = nullptr;
};
/// @brief An adapter. Reference a list of strings.
class ConstStringListRef {
public:
ConstStringListRef(const std::vector<std::string>* ref) : ref_(ref) {}
ConstStringListRef(const std::vector<std::wstring>* ref) : ref_wide_(ref) {}
size_t size() const { return ref_ ? ref_->size() : ref_wide_->size(); }
std::string operator[](size_t i) const {
return ref_ ? (*ref_)[i] : to_string((*ref_wide_)[i]);
}
private:
const std::vector<std::string>* ref_ = nullptr;
const std::vector<std::wstring>* ref_wide_ = nullptr;
}; };
} // namespace ftxui } // namespace ftxui

View File

@ -75,7 +75,7 @@ class ButtonBase : public ComponentBase {
/// ///
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::FitComponent(); /// auto screen = ScreenInteractive::FitComponent();
/// std::wstring label = L"Click to quit"; /// std::string label = "Click to quit";
/// Component button = Button(&label, screen.ExitLoopClosure()); /// Component button = Button(&label, screen.ExitLoopClosure());
/// screen.Loop(button) /// screen.Loop(button)
/// ``` /// ```

View File

@ -37,7 +37,7 @@ class CatchEventBase : public ComponentBase {
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::TerminalOutput(); /// auto screen = ScreenInteractive::TerminalOutput();
/// auto renderer = Renderer([] { /// auto renderer = Renderer([] {
/// return text(L"My interface"); /// return text("My interface");
/// }); /// });
/// screen.Loop(renderer); /// screen.Loop(renderer);
/// ``` /// ```

View File

@ -22,10 +22,10 @@ class CheckboxBase : public ComponentBase {
#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
// Microsoft terminal do not use fonts able to render properly the default // Microsoft terminal do not use fonts able to render properly the default
// radiobox glyph. // radiobox glyph.
if (option_->style_checked == L"") if (option_->style_checked == "")
option_->style_checked = L"[X]"; option_->style_checked = "[X]";
if (option_->style_unchecked == L"") if (option_->style_unchecked == "")
option_->style_unchecked = L"[ ]"; option_->style_unchecked = "[ ]";
#endif #endif
} }
@ -91,7 +91,7 @@ class CheckboxBase : public ComponentBase {
/// ///
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::FitComponent(); /// auto screen = ScreenInteractive::FitComponent();
/// std::wstring label = L"Make a sandwidth"; /// std::string label = "Make a sandwidth";
/// bool checked = false; /// bool checked = false;
/// Component checkbox = Checkbox(&label, &checked); /// Component checkbox = Checkbox(&label, &checked);
/// screen.Loop(checkbox) /// screen.Loop(checkbox)

View File

@ -3,6 +3,7 @@
#include <cassert> // for assert #include <cassert> // for assert
#include <iterator> // for begin, end #include <iterator> // for begin, end
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector, __alloc_traits<>::value_type
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface
#include "ftxui/component/component.hpp" #include "ftxui/component/component.hpp"
@ -82,7 +83,7 @@ Element ComponentBase::Render() {
if (children_.size() == 1) if (children_.size() == 1)
return children_.front()->Render(); return children_.front()->Render();
return text(L"Not implemented component"); return text("Not implemented component");
} }
/// @brief Called in response to an event. /// @brief Called in response to an event.

View File

@ -93,7 +93,7 @@ class VerticalContainer : public ContainerBase {
for (auto& it : children_) for (auto& it : children_)
elements.push_back(it->Render()); elements.push_back(it->Render());
if (elements.size() == 0) if (elements.size() == 0)
return text(L"Empty container"); return text("Empty container");
return vbox(std::move(elements)); return vbox(std::move(elements));
} }
@ -122,7 +122,7 @@ class HorizontalContainer : public ContainerBase {
for (auto& it : children_) for (auto& it : children_)
elements.push_back(it->Render()); elements.push_back(it->Render());
if (elements.size() == 0) if (elements.size() == 0)
return text(L"Empty container"); return text("Empty container");
return hbox(std::move(elements)); return hbox(std::move(elements));
} }
@ -150,7 +150,7 @@ class TabContainer : public ContainerBase {
Component active_child = ActiveChild(); Component active_child = ActiveChild();
if (active_child) if (active_child)
return active_child->Render(); return active_child->Render();
return text(L"Empty container"); return text("Empty container");
} }
bool OnMouseEvent(Event event) override { bool OnMouseEvent(Event event) override {

View File

@ -9,7 +9,6 @@ namespace ftxui {
// static // static
Event Event::Character(std::string input) { Event Event::Character(std::string input) {
Event event; Event event;
event.character_ = to_wstring(input)[0];
event.input_ = std::move(input); event.input_ = std::move(input);
event.type_ = Type::Character; event.type_ = Type::Character;
return event; return event;
@ -17,16 +16,12 @@ Event Event::Character(std::string input) {
// static // static
Event Event::Character(char c) { Event Event::Character(char c) {
return Character(wchar_t(c)); return Event::Character(std::string{c});
} }
// static // static
Event Event::Character(wchar_t c) { Event Event::Character(wchar_t c) {
Event event; return Event::Character(to_string(std::wstring{c}));
event.input_ = {(char)c};
event.type_ = Type::Character;
event.character_ = c;
return event;
} }
// static // static

View File

@ -8,19 +8,22 @@
#include "ftxui/component/component.hpp" // for Make, Input #include "ftxui/component/component.hpp" // for Make, Input
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/component_options.hpp" // for InputOption #include "ftxui/component/component_options.hpp" // for InputOption
#include "ftxui/component/deprecated.hpp" // for Input
#include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Backspace, Event::Custom, Event::Delete, Event::End, Event::Home, Event::Return #include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Backspace, Event::Custom, Event::Delete, Event::End, Event::Home, Event::Return
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed
#include "ftxui/component/screen_interactive.hpp" // for Component #include "ftxui/component/screen_interactive.hpp" // for Component
#include "ftxui/dom/elements.hpp" // for operator|, Element, text, reflect, dim, flex, focus, inverted, hbox, size, frame, select, underlined, Decorator, EQUAL, HEIGHT #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for operator|, Element, reflect, text, dim, flex, focus, inverted, hbox, size, frame, select, underlined, Decorator, EQUAL, HEIGHT
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
#include "ftxui/util/ref.hpp" // for StringRef, Ref, ConstStringRef #include "ftxui/screen/string.hpp" // for to_wstring, to_string
#include "ftxui/util/ref.hpp" // for WideStringRef, Ref, ConstStringRef, StringRef
namespace ftxui { namespace ftxui {
// An input box. The user can type text into it. // An input box. The user can type text into it.
class InputBase : public ComponentBase { class WideInputBase : public ComponentBase {
public: public:
InputBase(StringRef content, WideInputBase(WideStringRef content,
ConstStringRef placeholder, ConstStringRef placeholder,
Ref<InputOption> option) Ref<InputOption> option)
: content_(content), placeholder_(placeholder), option_(option) {} : content_(content), placeholder_(placeholder), option_(option) {}
@ -132,7 +135,7 @@ class InputBase : public ComponentBase {
// Content // Content
if (event.is_character()) { if (event.is_character()) {
content_->insert(cursor_position(), 1, event.character()); content_->insert(cursor_position(), 1, to_wstring(event.character())[0]);
cursor_position()++; cursor_position()++;
option_->on_change(); option_->on_change();
return true; return true;
@ -165,7 +168,7 @@ class InputBase : public ComponentBase {
bool Focusable() const final { return true; } bool Focusable() const final { return true; }
StringRef content_; WideStringRef content_;
ConstStringRef placeholder_; ConstStringRef placeholder_;
Box input_box_; Box input_box_;
@ -173,6 +176,43 @@ class InputBase : public ComponentBase {
Ref<InputOption> option_; Ref<InputOption> option_;
}; };
// An input box. The user can type text into it.
// For convenience, the std::string version of Input simply wrap a
// WideInputBase.
// TODO(arthursonzogni): Provide an implementation handling std::string natively
// and adds better support for combining characters.
class InputBase : public ComponentBase {
public:
InputBase(StringRef content,
ConstStringRef placeholder,
Ref<InputOption> option)
: content_(std::move(content)),
wrapped_content_(to_wstring(*content_)),
wrapped_input_(&wrapped_content_,
std::move(placeholder),
std::move(option)) {}
Element Render() override {
wrapped_content_ = to_wstring(*content_);
return wrapped_input_.Render();
}
bool OnEvent(Event event) override {
wrapped_content_ = to_wstring(*content_);
if (wrapped_input_.OnEvent(event)) {
content_ = to_string(wrapped_content_);
return true;
}
return false;
}
bool Focusable() const final { return true; }
StringRef content_;
std::wstring wrapped_content_;
WideInputBase wrapped_input_;
};
/// @brief An input box for editing text. /// @brief An input box for editing text.
/// @param content The editable content. /// @param content The editable content.
/// @param placeholder The text displayed when content is still empty. /// @param placeholder The text displayed when content is still empty.
@ -184,8 +224,8 @@ class InputBase : public ComponentBase {
/// ///
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::FitComponent(); /// auto screen = ScreenInteractive::FitComponent();
/// std::wstring content= L""; /// std::string content= "";
/// std::wstring placeholder = L"placeholder"; /// std::string placeholder = "placeholder";
/// Component input = Input(&content, &placeholder); /// Component input = Input(&content, &placeholder);
/// screen.Loop(input); /// screen.Loop(input);
/// ``` /// ```
@ -201,6 +241,34 @@ Component Input(StringRef content,
return Make<InputBase>(content, placeholder, std::move(option)); return Make<InputBase>(content, placeholder, std::move(option));
} }
/// @brief . An input box for editing text.
/// @param content The editable content.
/// @param placeholder The text displayed when content is still empty.
/// @param option Additional optional parameters.
/// @ingroup component
/// @see InputBase
///
/// ### Example
///
/// ```cpp
/// auto screen = ScreenInteractive::FitComponent();
/// std::string content= "";
/// std::string placeholder = "placeholder";
/// Component input = Input(&content, &placeholder);
/// screen.Loop(input);
/// ```
///
/// ### Output
///
/// ```bash
/// placeholder
/// ```
Component Input(WideStringRef content,
ConstStringRef placeholder,
Ref<InputOption> option) {
return Make<WideInputBase>(content, placeholder, std::move(option));
}
} // namespace ftxui } // namespace ftxui
// Copyright 2020 Arthur Sonzogni. All rights reserved. // Copyright 2020 Arthur Sonzogni. All rights reserved.

View File

@ -4,9 +4,9 @@
#include <string> // for wstring #include <string> // for wstring
#include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Input
#include "ftxui/component/component_base.hpp" // for ComponentBase, Component #include "ftxui/component/component_base.hpp" // for ComponentBase, Component
#include "ftxui/component/component_options.hpp" // for InputOption #include "ftxui/component/component_options.hpp" // for InputOption
#include "ftxui/component/deprecated.hpp" // for Input
#include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Backspace, Event::Delete, Event::End, Event::Home #include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Backspace, Event::Delete, Event::End, Event::Home
#include "ftxui/dom/elements.hpp" // for Fit #include "ftxui/dom/elements.hpp" // for Fit
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
@ -42,8 +42,8 @@ TEST(InputTest, Type) {
auto document = input->Render(); auto document = input->Render();
auto screen = Screen::Create(Dimension::Fit(document)); auto screen = Screen::Create(Dimension::Fit(document));
Render(screen, document); Render(screen, document);
EXPECT_EQ(screen.PixelAt(0, 0).character, L"a"); EXPECT_EQ(screen.PixelAt(0, 0).character, "a");
EXPECT_EQ(screen.PixelAt(1, 0).character, L"b"); EXPECT_EQ(screen.PixelAt(1, 0).character, "b");
} }
TEST(InputTest, TypePassword) { TEST(InputTest, TypePassword) {
@ -64,8 +64,8 @@ TEST(InputTest, TypePassword) {
auto document = input->Render(); auto document = input->Render();
auto screen = Screen::Create(Dimension::Fit(document)); auto screen = Screen::Create(Dimension::Fit(document));
Render(screen, document); Render(screen, document);
EXPECT_EQ(screen.PixelAt(0, 0).character, L""); EXPECT_EQ(screen.PixelAt(0, 0).character, "");
EXPECT_EQ(screen.PixelAt(1, 0).character, L""); EXPECT_EQ(screen.PixelAt(1, 0).character, "");
} }
TEST(InputTest, Arrow) { TEST(InputTest, Arrow) {

View File

@ -2,7 +2,7 @@
#include <algorithm> // for max, min #include <algorithm> // for max, min
#include <functional> // for function #include <functional> // for function
#include <memory> // for shared_ptr, allocator_traits<>::value_type #include <memory> // for shared_ptr, allocator_traits<>::value_type
#include <string> // for operator+, wstring #include <string> // for operator+, string
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector, __alloc_traits<>::value_type #include <vector> // for vector, __alloc_traits<>::value_type
@ -23,16 +23,14 @@ namespace ftxui {
/// @ingroup component /// @ingroup component
class MenuBase : public ComponentBase { class MenuBase : public ComponentBase {
public: public:
MenuBase(const std::vector<std::wstring>* entries, MenuBase(ConstStringListRef entries, int* selected, Ref<MenuOption> option)
int* selected,
Ref<MenuOption> option)
: entries_(entries), selected_(selected), option_(option) {} : entries_(entries), selected_(selected), option_(option) {}
Element Render() { Element Render() {
Elements elements; Elements elements;
bool is_menu_focused = Focused(); bool is_menu_focused = Focused();
boxes_.resize(entries_->size()); boxes_.resize(entries_.size());
for (size_t i = 0; i < entries_->size(); ++i) { for (size_t i = 0; i < entries_.size(); ++i) {
bool is_focused = (focused_entry() == int(i)) && is_menu_focused; bool is_focused = (focused_entry() == int(i)) && is_menu_focused;
bool is_selected = (*selected_ == int(i)); bool is_selected = (*selected_ == int(i));
@ -43,9 +41,9 @@ class MenuBase : public ComponentBase {
auto focus_management = !is_selected ? nothing auto focus_management = !is_selected ? nothing
: is_menu_focused ? focus : is_menu_focused ? focus
: select; : select;
auto icon = is_selected ? L"> " : L" "; auto icon = is_selected ? "> " : " ";
elements.push_back(text(icon + entries_->at(i)) | style | elements.push_back(text(icon + entries_[i]) | style | focus_management |
focus_management | reflect(boxes_[i])); reflect(boxes_[i]));
} }
return vbox(std::move(elements)); return vbox(std::move(elements));
} }
@ -64,12 +62,12 @@ class MenuBase : public ComponentBase {
(*selected_)--; (*selected_)--;
if (event == Event::ArrowDown || event == Event::Character('j')) if (event == Event::ArrowDown || event == Event::Character('j'))
(*selected_)++; (*selected_)++;
if (event == Event::Tab && entries_->size()) if (event == Event::Tab && entries_.size())
*selected_ = (*selected_ + 1) % entries_->size(); *selected_ = (*selected_ + 1) % entries_.size();
if (event == Event::TabReverse && entries_->size()) if (event == Event::TabReverse && entries_.size())
*selected_ = (*selected_ + entries_->size() - 1) % entries_->size(); *selected_ = (*selected_ + entries_.size() - 1) % entries_.size();
*selected_ = std::max(0, std::min(int(entries_->size()) - 1, *selected_)); *selected_ = std::max(0, std::min(int(entries_.size()) - 1, *selected_));
if (*selected_ != old_selected) { if (*selected_ != old_selected) {
focused_entry() = *selected_; focused_entry() = *selected_;
@ -106,12 +104,11 @@ class MenuBase : public ComponentBase {
return false; return false;
} }
bool Focusable() const final { return entries_->size(); } bool Focusable() const final { return entries_.size(); }
int& focused_entry() { return option_->focused_entry(); } int& focused_entry() { return option_->focused_entry(); }
protected: protected:
const std::vector<std::wstring>* const entries_; ConstStringListRef entries_;
int* selected_ = 0; int* selected_ = 0;
Ref<MenuOption> option_; Ref<MenuOption> option_;
@ -129,10 +126,10 @@ class MenuBase : public ComponentBase {
/// ///
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::TerminalOutput(); /// auto screen = ScreenInteractive::TerminalOutput();
/// std::vector<std::wstring> entries = { /// std::vector<std::string> entries = {
/// L"entry 1", /// "entry 1",
/// L"entry 2", /// "entry 2",
/// L"entry 3", /// "entry 3",
/// }; /// };
/// int selected = 0; /// int selected = 0;
/// auto menu = Menu(&entries, &selected); /// auto menu = Menu(&entries, &selected);
@ -146,7 +143,7 @@ class MenuBase : public ComponentBase {
/// entry 2 /// entry 2
/// entry 3 /// entry 3
/// ``` /// ```
Component Menu(const std::vector<std::wstring>* entries, Component Menu(ConstStringListRef entries,
int* selected, int* selected,
Ref<MenuOption> option) { Ref<MenuOption> option) {
return Make<MenuBase>(entries, selected, std::move(option)); return Make<MenuBase>(entries, selected, std::move(option));

View File

@ -2,7 +2,7 @@
#include <algorithm> // for max, min #include <algorithm> // for max, min
#include <functional> // for function #include <functional> // for function
#include <memory> // for shared_ptr, allocator_traits<>::value_type #include <memory> // for shared_ptr, allocator_traits<>::value_type
#include <string> // for wstring #include <string> // for string
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector #include <vector> // for vector
@ -25,26 +25,26 @@ namespace {
/// @ingroup component /// @ingroup component
class RadioboxBase : public ComponentBase { class RadioboxBase : public ComponentBase {
public: public:
RadioboxBase(const std::vector<std::wstring>* entries, RadioboxBase(ConstStringListRef entries,
int* selected, int* selected,
Ref<RadioboxOption> option) Ref<RadioboxOption> option)
: entries_(entries), selected_(selected), option_(std::move(option)) { : entries_(entries), selected_(selected), option_(std::move(option)) {
#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
// Microsoft terminal do not use fonts able to render properly the default // Microsoft terminal do not use fonts able to render properly the default
// radiobox glyph. // radiobox glyph.
if (option_->style_checked == L"") if (option_->style_checked == "")
option_->style_checked = L"(*)"; option_->style_checked = "(*)";
if (option_->style_unchecked == L"") if (option_->style_unchecked == "")
option_->style_unchecked = L"( )"; option_->style_unchecked = "( )";
#endif #endif
} }
private: private:
Element Render() override { Element Render() override {
std::vector<Element> elements; Elements elements;
bool is_focused = Focused(); bool is_focused = Focused();
boxes_.resize(entries_->size()); boxes_.resize(entries_.size());
for (size_t i = 0; i < entries_->size(); ++i) { for (size_t i = 0; i < entries_.size(); ++i) {
auto style = (focused_entry() == int(i) && is_focused) auto style = (focused_entry() == int(i) && is_focused)
? option_->style_focused ? option_->style_focused
: option_->style_unfocused; : option_->style_unfocused;
@ -52,10 +52,10 @@ class RadioboxBase : public ComponentBase {
: is_focused ? focus : is_focused ? focus
: select; : select;
const std::wstring& symbol = *selected_ == int(i) const std::string& symbol = *selected_ == int(i)
? option_->style_checked ? option_->style_checked
: option_->style_unchecked; : option_->style_unchecked;
elements.push_back(hbox(text(symbol), text(entries_->at(i)) | style) | elements.push_back(hbox(text(symbol), text(entries_[i]) | style) |
focus_management | reflect(boxes_[i])); focus_management | reflect(boxes_[i]));
} }
return vbox(std::move(elements)); return vbox(std::move(elements));
@ -75,12 +75,12 @@ class RadioboxBase : public ComponentBase {
new_focused--; new_focused--;
if (event == Event::ArrowDown || event == Event::Character('j')) if (event == Event::ArrowDown || event == Event::Character('j'))
new_focused++; new_focused++;
if (event == Event::Tab && entries_->size()) if (event == Event::Tab && entries_.size())
new_focused = (new_focused + 1) % entries_->size(); new_focused = (new_focused + 1) % entries_.size();
if (event == Event::TabReverse && entries_->size()) if (event == Event::TabReverse && entries_.size())
new_focused = (new_focused + entries_->size() - 1) % entries_->size(); new_focused = (new_focused + entries_.size() - 1) % entries_.size();
new_focused = std::max(0, std::min(int(entries_->size()) - 1, new_focused)); new_focused = std::max(0, std::min(int(entries_.size()) - 1, new_focused));
if (focused_entry() != new_focused) { if (focused_entry() != new_focused) {
focused_entry() = new_focused; focused_entry() = new_focused;
@ -119,11 +119,10 @@ class RadioboxBase : public ComponentBase {
return false; return false;
} }
bool Focusable() const final { return entries_->size(); } bool Focusable() const final { return entries_.size(); }
int& focused_entry() { return option_->focused_entry(); } int& focused_entry() { return option_->focused_entry(); }
const std::vector<std::wstring>* const entries_; ConstStringListRef entries_;
int* const selected_; int* const selected_;
int cursor_position = 0; int cursor_position = 0;
@ -144,10 +143,10 @@ class RadioboxBase : public ComponentBase {
/// ///
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::TerminalOutput(); /// auto screen = ScreenInteractive::TerminalOutput();
/// std::vector<std::wstring> entries = { /// std::vector<std::string> entries = {
/// L"entry 1", /// "entry 1",
/// L"entry 2", /// "entry 2",
/// L"entry 3", /// "entry 3",
/// }; /// };
/// int selected = 0; /// int selected = 0;
/// auto menu = Radiobox(&entries, &selected); /// auto menu = Radiobox(&entries, &selected);
@ -161,7 +160,7 @@ class RadioboxBase : public ComponentBase {
/// ○ entry 2 /// ○ entry 2
/// ○ entry 3 /// ○ entry 3
/// ``` /// ```
Component Radiobox(const std::vector<std::wstring>* entries, Component Radiobox(ConstStringListRef entries,
int* selected, int* selected,
Ref<RadioboxOption> option) { Ref<RadioboxOption> option) {
return Make<RadioboxBase>(entries, selected, std::move(option)); return Make<RadioboxBase>(entries, selected, std::move(option));

View File

@ -21,7 +21,7 @@ namespace ftxui {
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::TerminalOutput(); /// auto screen = ScreenInteractive::TerminalOutput();
/// auto renderer = Renderer([] { /// auto renderer = Renderer([] {
/// return text(L"My interface"); /// return text("My interface");
/// }); /// });
/// screen.Loop(renderer); /// screen.Loop(renderer);
/// ``` /// ```
@ -46,7 +46,7 @@ Component Renderer(std::function<Element()> render) {
/// ///
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::TerminalOutput(); /// auto screen = ScreenInteractive::TerminalOutput();
/// std::wstring label = "Click to quit"; /// std::string label = "Click to quit";
/// auto button = Button(&label, screen.ExitLoopClosure()); /// auto button = Button(&label, screen.ExitLoopClosure());
/// auto renderer = Renderer(button, [&] { /// auto renderer = Renderer(button, [&] {
/// return hbox({ /// return hbox({

View File

@ -250,8 +250,8 @@ class ResizableSplitBottomBase : public ComponentBase {
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::Fullscreen(); /// auto screen = ScreenInteractive::Fullscreen();
/// int left_size = 10; /// int left_size = 10;
/// auto left = Renderer([] { return text(L"Left") | center;}); /// auto left = Renderer([] { return text("Left") | center;});
/// auto right = Renderer([] { return text(L"right") | center;}); /// auto right = Renderer([] { return text("right") | center;});
/// auto split = ResizableSplitLeft(left, right, &left_size); /// auto split = ResizableSplitLeft(left, right, &left_size);
/// screen.Loop(split); /// screen.Loop(split);
/// ``` /// ```
@ -280,8 +280,8 @@ Component ResizableSplitLeft(Component main, Component back, int* main_size) {
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::Fullscreen(); /// auto screen = ScreenInteractive::Fullscreen();
/// int right_size = 10; /// int right_size = 10;
/// auto left = Renderer([] { return text(L"Left") | center;}); /// auto left = Renderer([] { return text("Left") | center;});
/// auto right = Renderer([] { return text(L"right") | center;}); /// auto right = Renderer([] { return text("right") | center;});
/// auto split = ResizableSplitRight(right, left, &right_size); /// auto split = ResizableSplitRight(right, left, &right_size);
/// screen.Loop(split); /// screen.Loop(split);
/// ``` /// ```
@ -310,8 +310,8 @@ Component ResizableSplitRight(Component main, Component back, int* main_size) {
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::Fullscreen(); /// auto screen = ScreenInteractive::Fullscreen();
/// int top_size = 1; /// int top_size = 1;
/// auto top = Renderer([] { return text(L"Top") | center;}); /// auto top = Renderer([] { return text("Top") | center;});
/// auto bottom = Renderer([] { return text(L"Bottom") | center;}); /// auto bottom = Renderer([] { return text("Bottom") | center;});
/// auto split = ResizableSplitTop(top, bottom, &top_size); /// auto split = ResizableSplitTop(top, bottom, &top_size);
/// screen.Loop(split); /// screen.Loop(split);
/// ``` /// ```
@ -340,8 +340,8 @@ Component ResizableSplitTop(Component main, Component back, int* main_size) {
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::Fullscreen(); /// auto screen = ScreenInteractive::Fullscreen();
/// int bottom_size = 1; /// int bottom_size = 1;
/// auto top = Renderer([] { return text(L"Top") | center;}); /// auto top = Renderer([] { return text("Top") | center;});
/// auto bottom = Renderer([] { return text(L"Bottom") | center;}); /// auto bottom = Renderer([] { return text("Bottom") | center;});
/// auto split = ResizableSplit::Bottom(bottom, top, &bottom_size); /// auto split = ResizableSplit::Bottom(bottom, top, &bottom_size);
/// screen.Loop(split); /// screen.Loop(split);
/// ``` /// ```

View File

@ -1,11 +1,12 @@
#include <gtest/gtest-message.h> // for Message #include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for TestPartResult #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl, TestPartResult
#include <csignal> #include <csignal> // for raise, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM
#include "ftxui/component/component.hpp" #include "ftxui/component/component.hpp" // for Renderer
#include "ftxui/component/screen_interactive.hpp" #include "ftxui/component/screen_interactive.hpp"
#include "ftxui/dom/elements.hpp" #include "ftxui/dom/deprecated.hpp" // for text
#include "gtest/gtest_pred_impl.h" // for AssertionResult, Test, EXPECT_EQ #include "ftxui/dom/elements.hpp" // for Element
#include "gtest/gtest_pred_impl.h" // for Test, TEST, EXPECT_EQ
using namespace ftxui; using namespace ftxui;

View File

@ -17,7 +17,7 @@ namespace ftxui {
template <class T> template <class T>
class SliderBase : public ComponentBase { class SliderBase : public ComponentBase {
public: public:
SliderBase(StringRef label, T* value, T min, T max, T increment) SliderBase(ConstStringRef label, T* value, T min, T max, T increment)
: label_(label), : label_(label),
value_(value), value_(value),
min_(min), min_(min),
@ -31,9 +31,9 @@ class SliderBase : public ComponentBase {
return hbox({ return hbox({
text(*label_) | dim | vcenter, text(*label_) | dim | vcenter,
hbox({ hbox({
text(L"["), text("["),
gauge(percent) | underlined | xflex | reflect(gauge_box_), gauge(percent) | underlined | xflex | reflect(gauge_box_),
text(L"]"), text("]"),
}) | xflex, }) | xflex,
}) | }) |
gauge_color | xflex | reflect(box_); gauge_color | xflex | reflect(box_);
@ -87,7 +87,7 @@ class SliderBase : public ComponentBase {
bool Focusable() const final { return true; } bool Focusable() const final { return true; }
private: private:
StringRef label_; ConstStringRef label_;
T* value_; T* value_;
T min_; T min_;
T max_; T max_;
@ -110,7 +110,7 @@ class SliderBase : public ComponentBase {
/// ```cpp /// ```cpp
/// auto screen = ScreenInteractive::TerminalOutput(); /// auto screen = ScreenInteractive::TerminalOutput();
/// int value = 50; /// int value = 50;
/// auto slider = Slider(L"Value:", &value, 0, 100, 1); /// auto slider = Slider("Value:", &value, 0, 100, 1);
/// screen.Loop(slider); /// screen.Loop(slider);
/// ``` /// ```
/// ///
@ -120,23 +120,23 @@ class SliderBase : public ComponentBase {
/// Value:[██████████████████████████ ] /// Value:[██████████████████████████ ]
/// ``` /// ```
template <class T> template <class T>
Component Slider(StringRef label, T* value, T min, T max, T increment) { Component Slider(ConstStringRef label, T* value, T min, T max, T increment) {
return Make<SliderBase<T>>(std::move(label), value, min, max, increment); return Make<SliderBase<T>>(std::move(label), value, min, max, increment);
} }
template Component Slider(StringRef label, template Component Slider(ConstStringRef label,
int* value, int* value,
int min, int min,
int max, int max,
int increment); int increment);
template Component Slider(StringRef label, template Component Slider(ConstStringRef label,
float* value, float* value,
float min, float min,
float max, float max,
float increment); float increment);
template Component Slider(StringRef label, template Component Slider(ConstStringRef label,
long* value, long* value,
long min, long min,
long max, long max,

View File

@ -29,7 +29,7 @@ TEST(Event, Character) {
for (char c : basic_char) { for (char c : basic_char) {
EXPECT_TRUE(event_receiver->Receive(&received)); EXPECT_TRUE(event_receiver->Receive(&received));
EXPECT_TRUE(received.is_character()); EXPECT_TRUE(received.is_character());
EXPECT_EQ(c, received.character()); EXPECT_EQ(c, received.character()[0]);
} }
EXPECT_FALSE(event_receiver->Receive(&received)); EXPECT_FALSE(event_receiver->Receive(&received));
} }

View File

@ -2,19 +2,18 @@
#include <algorithm> // for max, min #include <algorithm> // for max, min
#include <functional> // for function #include <functional> // for function
#include <memory> // for shared_ptr, allocator_traits<>::value_type #include <memory> // for shared_ptr, allocator_traits<>::value_type
#include <string> // for wstring
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
#include "ftxui/component/component.hpp" // for Make, Component, Toggle #include "ftxui/component/component.hpp" // for Make, Toggle
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for Component, ComponentBase
#include "ftxui/component/component_options.hpp" // for ToggleOption #include "ftxui/component/component_options.hpp" // for ToggleOption
#include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Return, Event::Tab, Event::TabReverse #include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Return, Event::Tab, Event::TabReverse
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed
#include "ftxui/dom/elements.hpp" // for operator|, Element, Elements, hbox, reflect, separator, text, focus, nothing, select #include "ftxui/dom/elements.hpp" // for operator|, Element, Elements, hbox, reflect, separator, text, focus, nothing, select
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
#include "ftxui/util/ref.hpp" // for Ref #include "ftxui/util/ref.hpp" // for ConstStringListRef, Ref
namespace ftxui { namespace ftxui {
@ -24,7 +23,7 @@ namespace {
/// @ingroup component /// @ingroup component
class ToggleBase : public ComponentBase { class ToggleBase : public ComponentBase {
public: public:
ToggleBase(const std::vector<std::wstring>* entries, ToggleBase(ConstStringListRef entries,
int* selected, int* selected,
Ref<ToggleOption> option) Ref<ToggleOption> option)
: entries_(entries), selected_(selected), option_(std::move(option)) {} : entries_(entries), selected_(selected), option_(std::move(option)) {}
@ -33,8 +32,8 @@ class ToggleBase : public ComponentBase {
Element Render() override { Element Render() override {
Elements children; Elements children;
bool is_toggle_focused = Focused(); bool is_toggle_focused = Focused();
boxes_.resize(entries_->size()); boxes_.resize(entries_.size());
for (size_t i = 0; i < entries_->size(); ++i) { for (size_t i = 0; i < entries_.size(); ++i) {
// Separator. // Separator.
if (i != 0) if (i != 0)
children.push_back(separator()); children.push_back(separator());
@ -49,7 +48,7 @@ class ToggleBase : public ComponentBase {
auto focus_management = !is_selected ? nothing auto focus_management = !is_selected ? nothing
: is_toggle_focused ? focus : is_toggle_focused ? focus
: select; : select;
children.push_back(text(entries_->at(i)) | style | focus_management | children.push_back(text(entries_[i]) | style | focus_management |
reflect(boxes_[i])); reflect(boxes_[i]));
} }
return hbox(std::move(children)); return hbox(std::move(children));
@ -64,12 +63,12 @@ class ToggleBase : public ComponentBase {
(*selected_)--; (*selected_)--;
if (event == Event::ArrowRight || event == Event::Character('l')) if (event == Event::ArrowRight || event == Event::Character('l'))
(*selected_)++; (*selected_)++;
if (event == Event::Tab && entries_->size()) if (event == Event::Tab && entries_.size())
*selected_ = (*selected_ + 1) % entries_->size(); *selected_ = (*selected_ + 1) % entries_.size();
if (event == Event::TabReverse && entries_->size()) if (event == Event::TabReverse && entries_.size())
*selected_ = (*selected_ + entries_->size() - 1) % entries_->size(); *selected_ = (*selected_ + entries_.size() - 1) % entries_.size();
*selected_ = std::max(0, std::min(int(entries_->size()) - 1, *selected_)); *selected_ = std::max(0, std::min(int(entries_.size()) - 1, *selected_));
if (old_selected != *selected_) { if (old_selected != *selected_) {
focused_entry() = *selected_; focused_entry() = *selected_;
@ -107,11 +106,10 @@ class ToggleBase : public ComponentBase {
return false; return false;
} }
bool Focusable() const final { return entries_->size(); } bool Focusable() const final { return entries_.size(); }
int& focused_entry() { return option_->focused_entry(); } int& focused_entry() { return option_->focused_entry(); }
const std::vector<std::wstring>* const entries_; ConstStringListRef entries_;
int* selected_ = 0; int* selected_ = 0;
std::vector<Box> boxes_; std::vector<Box> boxes_;
@ -125,7 +123,7 @@ class ToggleBase : public ComponentBase {
/// @param selected Reference the selected entry. /// @param selected Reference the selected entry.
/// @param option Additional optional parameters. /// @param option Additional optional parameters.
/// @ingroup component /// @ingroup component
Component Toggle(const std::vector<std::wstring>* entries, Component Toggle(ConstStringListRef entries,
int* selected, int* selected,
Ref<ToggleOption> option) { Ref<ToggleOption> option) {
return Make<ToggleBase>(entries, selected, std::move(option)); return Make<ToggleBase>(entries, selected, std::move(option));

View File

@ -10,7 +10,7 @@ using namespace ftxui;
static void BencharkBasic(benchmark::State& state) { static void BencharkBasic(benchmark::State& state) {
while (state.KeepRunning()) { while (state.KeepRunning()) {
auto document = vbox({ auto document = vbox({
text(L"Test"), text("Test"),
separator(), separator(),
hbox({ hbox({
gauge(0.9), gauge(0.9),
@ -20,7 +20,7 @@ static void BencharkBasic(benchmark::State& state) {
gauge(0.1), gauge(0.1),
separator(), separator(),
}), }),
text(L"Test"), text("Test"),
}) | }) |
border; border;
auto root = gauge(1.0); auto root = gauge(1.0);

View File

@ -1,6 +1,7 @@
#include <algorithm> // for max #include <algorithm> // for max
#include <iterator> // for begin, end #include <iterator> // for begin, end
#include <memory> // for make_shared, __shared_ptr_access #include <memory> // for allocator, make_shared, __shared_ptr_access
#include <string> // for basic_string, string
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector, __alloc_traits<>::value_type #include <vector> // for vector, __alloc_traits<>::value_type
@ -12,10 +13,11 @@
namespace ftxui { namespace ftxui {
static wchar_t simple_border_charset[] = L"╭╮╰╯─│┬┴┤├"; static std::string simple_border_charset[] = {"", "", "", "", "",
"", "", "", "", ""};
// For reference, here is the charset for normal border: // For reference, here is the charset for normal border:
// L"┌┐└┘─│┬┴┤├"; // {"┌", "┐", "└", "┘", "─", "│", "┬", "┴", "┤", "├"};
// TODO(arthursonzogni): Consider adding options to choose the kind of borders // TODO(arthursonzogni): Consider adding options to choose the kind of borders
// to use. // to use.
@ -29,7 +31,7 @@ class Border : public Node {
: Node(std::move(children)), charset_pixel(10, pixel) {} : Node(std::move(children)), charset_pixel(10, pixel) {}
std::vector<Pixel> charset_pixel; std::vector<Pixel> charset_pixel;
std::vector<wchar_t> charset; std::vector<std::string> charset;
void ComputeRequirement() override { void ComputeRequirement() override {
Node::ComputeRequirement(); Node::ComputeRequirement();
@ -120,10 +122,10 @@ class Border : public Node {
/// ///
/// ```cpp /// ```cpp
/// // Use 'border' as a function... /// // Use 'border' as a function...
/// Element document = border(text(L"The element")); /// Element document = border(text("The element"));
/// ///
/// // ...Or as a 'pipe'. /// // ...Or as a 'pipe'.
/// Element document = text(L"The element") | border; /// Element document = text("The element") | border;
/// ``` /// ```
/// ///
/// ### Output /// ### Output
@ -146,8 +148,8 @@ Element border(Element child) {
/// ### Example /// ### Example
/// ///
/// ```cpp /// ```cpp
/// Element document = window(text(L"Title"), /// Element document = window(text("Title"),
/// text(L"content") /// text("content")
/// ); /// );
/// ``` /// ```
/// ///

View File

@ -52,7 +52,7 @@ class FgColor : public NodeDecorator {
/// ### Example /// ### Example
/// ///
/// ```cpp /// ```cpp
/// Element document = color(Color::Green, text(L"Success")), /// Element document = color(Color::Green, text("Success")),
/// ``` /// ```
Element color(Color color, Element child) { Element color(Color color, Element child) {
return std::make_shared<FgColor>(std::move(child), color); return std::make_shared<FgColor>(std::move(child), color);
@ -67,7 +67,7 @@ Element color(Color color, Element child) {
/// ### Example /// ### Example
/// ///
/// ```cpp /// ```cpp
/// Element document = bgcolor(Color::Green, text(L"Success")), /// Element document = bgcolor(Color::Green, text("Success")),
/// ``` /// ```
Element bgcolor(Color color, Element child) { Element bgcolor(Color color, Element child) {
return std::make_shared<BgColor>(std::move(child), color); return std::make_shared<BgColor>(std::move(child), color);
@ -81,7 +81,7 @@ Element bgcolor(Color color, Element child) {
/// ### Example /// ### Example
/// ///
/// ```cpp /// ```cpp
/// Element document = text(L"red") | color(Color::Red); /// Element document = text("red") | color(Color::Red);
/// ``` /// ```
Decorator color(Color c) { Decorator color(Color c) {
return [c](Element child) { return color(c, std::move(child)); }; return [c](Element child) { return color(c, std::move(child)); };
@ -95,7 +95,7 @@ Decorator color(Color c) {
/// ### Example /// ### Example
/// ///
/// ```cpp /// ```cpp
/// Element document = text(L"red") | bgcolor(Color::Red); /// Element document = text("red") | bgcolor(Color::Red);
/// ``` /// ```
Decorator bgcolor(Color color) { Decorator bgcolor(Color color) {
return [color](Element child) { return bgcolor(color, std::move(child)); }; return [color](Element child) { return bgcolor(color, std::move(child)); };

View File

@ -103,9 +103,9 @@ Element filler() {
/// ///
/// ~~~cpp /// ~~~cpp
/// hbox({ /// hbox({
/// text(L"left") | border , /// text("left") | border ,
/// text(L"middle") | border | flex, /// text("middle") | border | flex,
/// text(L"right") | border, /// text("right") | border,
/// }); /// });
/// ~~~ /// ~~~
/// ///

View File

@ -1,4 +1,5 @@
#include <memory> // for make_shared #include <memory> // for allocator, make_shared
#include <string> // for string
#include "ftxui/dom/elements.hpp" // for Element, gauge #include "ftxui/dom/elements.hpp" // for Element, gauge
#include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/node.hpp" // for Node
@ -8,12 +9,13 @@
namespace ftxui { namespace ftxui {
static std::string charset[] =
#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
// Microsoft's terminals often use fonts not handling the 8 unicode characters // Microsoft's terminals often use fonts not handling the 8 unicode
// for representing the whole gauge. Fallback with less. // characters for representing the whole gauge. Fallback with less.
static wchar_t charset[] = L" ▌▌▌███"; {" ", " ", " ", " ", "", "", "", "", "", ""};
#else #else
static wchar_t charset[] = L" ▏▎▍▌▋▊▉█"; {" ", " ", "", "", "", "", "", "", "", ""};
#endif #endif
class Gauge : public Node { class Gauge : public Node {

View File

@ -1,5 +1,6 @@
#include <functional> // for function #include <functional> // for function
#include <memory> // for make_shared #include <memory> // for allocator, make_shared
#include <string> // for string
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/dom/elements.hpp" // for GraphFunction, Element, graph #include "ftxui/dom/elements.hpp" // for GraphFunction, Element, graph
@ -10,12 +11,13 @@
namespace ftxui { namespace ftxui {
// Microsoft's terminals often use fonts not handling the 8 unicode characters static std::string charset[] =
// for representing the whole gauge. Fallback with less.
#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK) #if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
const wchar_t charset[] = L" █ █████"; // Microsoft's terminals often use fonts not handling the 8 unicode
// characters for representing the whole graph. Fallback with less.
{" ", " ", "", " ", "", "", "", "", ""};
#else #else
const wchar_t charset[] = L" ▗▐▖▄▟▌▙█"; {" ", "", "", "", "", "", "", "", ""};
#endif #endif
class Graph : public Node { class Graph : public Node {
@ -43,8 +45,7 @@ class Graph : public Node {
int yy = 2 * y; int yy = 2 * y;
int i_1 = yy < height_1 ? 0 : yy == height_1 ? 3 : 6; int i_1 = yy < height_1 ? 0 : yy == height_1 ? 3 : 6;
int i_2 = yy < height_2 ? 0 : yy == height_2 ? 1 : 2; int i_2 = yy < height_2 ? 0 : yy == height_2 ? 1 : 2;
wchar_t pix = charset[i_1 + i_2]; screen.at(x, y) = charset[i_1 + i_2];
screen.at(x, y) = pix;
} }
} }
} }

View File

@ -136,8 +136,8 @@ class HBox : public Node {
/// ///
/// ```cpp /// ```cpp
/// hbox({ /// hbox({
/// text(L"Left"), /// text("Left"),
/// text(L"Right"), /// text("Right"),
/// }); /// });
/// ``` /// ```
Element hbox(Elements children) { Element hbox(Elements children) {

View File

@ -1,13 +1,14 @@
#include <gtest/gtest-message.h> // for Message #include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for TestPartResult #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl, TestPartResult
#include <string> // for allocator, basic_string, string #include <string> // for allocator, basic_string, string
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/dom/elements.hpp" // for text, operator|, Element, flex_grow #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for operator|, Element, flex_grow, flex_shrink, hbox
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
#include "gtest/gtest_pred_impl.h" // for Test, SuiteApiResolver, EXPECT_EQ #include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST
using namespace ftxui; using namespace ftxui;
using namespace ftxui; using namespace ftxui;

View File

@ -1,7 +1,8 @@
#include <sstream> #include <sstream> // for basic_istream, wstringstream
#include <string> #include <string> // for allocator, char_traits, getline, operator+, wstring, basic_string
#include "ftxui/dom/elements.hpp" #include "ftxui/dom/deprecated.hpp" // for text, paragraph
#include "ftxui/dom/elements.hpp" // for Elements
namespace ftxui { namespace ftxui {
@ -14,9 +15,22 @@ Elements paragraph(std::wstring the_text) {
Elements output; Elements output;
std::wstringstream ss(the_text); std::wstringstream ss(the_text);
std::wstring word; std::wstring word;
while (std::getline(ss, word, L' ')) { while (std::getline(ss, word, L' '))
output.push_back(text(word + L' ')); output.push_back(text(word + L' '));
} return output;
}
/// @brief Return a vector of ftxui::text for every word of the string. This is
/// useful combined with ftxui::hflow.
/// @param the_text The string to be splitted.
/// @ingroup dom
/// @see hflow.
Elements paragraph(std::string the_text) {
Elements output;
std::stringstream ss(the_text);
std::string word;
while (std::getline(ss, word, ' '))
output.push_back(text(word + ' '));
return output; return output;
} }

View File

@ -1,5 +1,5 @@
#include <memory> // for make_shared #include <memory> // for make_shared
#include <string> // for wstring #include <string> // for string
#include "ftxui/dom/elements.hpp" // for Element, separator #include "ftxui/dom/elements.hpp" // for Element, separator
#include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/node.hpp" // for Node
@ -22,11 +22,11 @@ class Separator : public Node {
bool is_column = (box_.x_max == box_.x_min); bool is_column = (box_.x_max == box_.x_min);
bool is_line = (box_.y_min == box_.y_max); bool is_line = (box_.y_min == box_.y_max);
wchar_t c = U'+'; std::string c = "+";
if (is_line && !is_column) if (is_line && !is_column)
c = U''; c = "";
else else
c = U''; c = "";
for (int y = box_.y_min; y <= box_.y_max; ++y) { for (int y = box_.y_min; y <= box_.y_max; ++y) {
for (int x = box_.x_min; x <= box_.x_max; ++x) { for (int x = box_.x_min; x <= box_.x_max; ++x) {

View File

@ -1,6 +1,6 @@
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <memory> // for allocator, allocator_traits<>::value_type #include <memory> // for allocator, allocator_traits<>::value_type
#include <string> // for basic_string, wstring #include <string> // for string
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector, __alloc_traits<>::value_type #include <vector> // for vector, __alloc_traits<>::value_type
@ -8,242 +8,242 @@
namespace ftxui { namespace ftxui {
static const std::vector<std::vector<std::vector<std::wstring>>> elements = { static const std::vector<std::vector<std::vector<std::string>>> elements = {
{ {
{L"Replaced by the gauge"}, {"Replaced by the gauge"},
}, },
{ {
{L". "}, {". "},
{L".. "}, {".. "},
{L"..."}, {"..."},
}, },
{ {
{L"|"}, {"|"},
{L"/"}, {"/"},
{L"-"}, {"-"},
{L"\\"}, {"\\"},
}, },
{ {
{L"+"}, {"+"},
{L"x"}, {"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 ", " /\\O ",
L" /\\/ ", " /\\/ ",
L" /\\ ", " /\\ ",
L" / \\ ", " / \\ ",
L"LOL LOL", "LOL LOL ",
}, },
{ {
L" _O ", " _O ",
L" //|_ ", " //|_ ",
L" | ", " | ",
L" /| ", " /| ",
L" LLOL ", " LLOL ",
}, },
{ {
L" O ", " O ",
L" /_ ", " /_ ",
L" |\\ ", " |\\ ",
L" / | ", " / | ",
L" LOLLOL ", " LOLLOL ",
}}}; }}};
/// @brief Useful to represent the effect of time and/or events. This display an /// @brief Useful to represent the effect of time and/or events. This display an

View File

@ -1,13 +1,14 @@
#include <algorithm> // for max
#include <memory> // for make_shared #include <memory> // for make_shared
#include <string> // for wstring #include <string> // for string
#include <vector> // for vector
#include "ftxui/dom/deprecated.hpp" // for text, vtext
#include "ftxui/dom/elements.hpp" // for Element, text, vtext #include "ftxui/dom/elements.hpp" // for Element, text, vtext
#include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/node.hpp" // for Node
#include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Pixel, Screen
#include "ftxui/screen/string.hpp" // for wchar_width, wstring_width #include "ftxui/screen/string.hpp" // for string_width, Utf8ToGlyphs, to_string
namespace ftxui { namespace ftxui {
@ -15,10 +16,10 @@ using ftxui::Screen;
class Text : public Node { class Text : public Node {
public: public:
Text(std::wstring text) : text_(text) {} Text(std::string text) : text_(text) {}
void ComputeRequirement() override { void ComputeRequirement() override {
requirement_.min_x = wstring_width(text_); requirement_.min_x = string_width(text_);
requirement_.min_y = 1; requirement_.min_y = 1;
} }
@ -27,33 +28,26 @@ class Text : public Node {
int y = box_.y_min; int y = box_.y_min;
if (y > box_.y_max) if (y > box_.y_max)
return; return;
for (wchar_t c : text_) { for (const auto& cell : Utf8ToGlyphs(text_)) {
const int width = wchar_width(c);
if (width >= 1) {
if (x > box_.x_max) if (x > box_.x_max)
return; return;
screen.PixelAt(x, y).character = c; screen.PixelAt(x, y).character = cell;
} else { ++x;
screen.PixelAt(x - 1, y).character += c;
}
x += std::max(width, 0);
} }
} }
private: private:
std::wstring text_; std::string text_;
}; };
class VText : public Node { class VText : public Node {
public: public:
VText(std::wstring text) : text_(text) { VText(std::string text)
for (auto& c : text_) : text_(text), width_{std::min(string_width(text_), 1)} {}
width_ = std::max(width_, wchar_width(c));
}
void ComputeRequirement() override { void ComputeRequirement() override {
requirement_.min_x = width_; requirement_.min_x = width_;
requirement_.min_y = text_.size(); requirement_.min_y = string_width(text_);
} }
void Render(Screen& screen) override { void Render(Screen& screen) override {
@ -61,20 +55,39 @@ class VText : public Node {
int y = box_.y_min; int y = box_.y_min;
if (x + width_ - 1 > box_.x_max) if (x + width_ - 1 > box_.x_max)
return; return;
for (wchar_t c : text_) { for (const auto& it : Utf8ToGlyphs(text_)) {
if (y > box_.y_max) if (y > box_.y_max)
return; return;
screen.at(x, y) = c; screen.PixelAt(x, y).character = it;
y += 1; y += 1;
} }
} }
private: private:
std::wstring text_; std::string text_;
int width_ = 1; int width_ = 1;
}; };
/// @brief Display a pieve of unicode text. /// @brief Display a piece of UTF8 encoded unicode text.
/// @ingroup dom
/// @see ftxui::to_wstring
///
/// ### Example
///
/// ```cpp
/// Element document = text("Hello world!");
/// ```
///
/// ### Output
///
/// ```bash
/// Hello world!
/// ```
Element text(std::string text) {
return std::make_shared<Text>(text);
}
/// @brief Display a piece of UTF16 encoded unicode text.
/// @ingroup dom /// @ingroup dom
/// @see ftxui::to_wstring /// @see ftxui::to_wstring
/// ///
@ -90,10 +103,40 @@ class VText : public Node {
/// Hello world! /// Hello world!
/// ``` /// ```
Element text(std::wstring text) { Element text(std::wstring text) {
return std::make_shared<Text>(text); return std::make_shared<Text>(to_string(text));
} }
/// @brief Display a pieve of unicode text vertically. /// @brief Display a piece of unicode text vertically.
/// @ingroup dom
/// @see ftxui::to_wstring
///
/// ### Example
///
/// ```cpp
/// Element document = vtext("Hello world!");
/// ```
///
/// ### Output
///
/// ```bash
/// H
/// e
/// l
/// l
/// o
///
/// w
/// o
/// r
/// l
/// d
/// !
/// ```
Element vtext(std::string text) {
return std::make_shared<VText>(text);
}
/// @brief Display a piece of UTF16 encoded unicode text vertically.
/// @ingroup dom /// @ingroup dom
/// @see ftxui::to_wstring /// @see ftxui::to_wstring
/// ///
@ -120,7 +163,7 @@ Element text(std::wstring text) {
/// ! /// !
/// ``` /// ```
Element vtext(std::wstring text) { Element vtext(std::wstring text) {
return std::make_shared<VText>(text); return std::make_shared<VText>(to_string(text));
} }
} // namespace ftxui } // namespace ftxui

View File

@ -2,7 +2,8 @@
#include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl, TestPartResult #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl, TestPartResult
#include <string> // for allocator, wstring #include <string> // for allocator, wstring
#include "ftxui/dom/elements.hpp" // for text, operator|, border, Element #include "ftxui/dom/deprecated.hpp" // for text
#include "ftxui/dom/elements.hpp" // for operator|, border, Element
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen

View File

@ -56,10 +56,10 @@ Elements operator|(Elements elements, Decorator decorator) {
/// ///
/// Both of these are equivalent: /// Both of these are equivalent:
/// ```cpp /// ```cpp
/// bold(text(L"Hello")); /// bold(text("Hello"));
/// ``` /// ```
/// ```cpp /// ```cpp
/// text(L"Hello") | bold; /// text("Hello") | bold;
/// ``` /// ```
Element operator|(Element element, Decorator decorator) { Element operator|(Element element, Decorator decorator) {
return decorator(std::move(element)); return decorator(std::move(element));

View File

@ -137,8 +137,8 @@ class VBox : public Node {
/// ///
/// ```cpp /// ```cpp
/// vbox({ /// vbox({
/// text(L"Up"), /// text("Up"),
/// text(L"Down"), /// text("Down"),
/// }); /// });
/// ``` /// ```
Element vbox(Elements children) { Element vbox(Elements children) {

View File

@ -1,14 +1,15 @@
#include <gtest/gtest-message.h> // for Message #include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for TestPartResult #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl, TestPartResult
#include <algorithm> // for remove #include <algorithm> // for remove
#include <string> // for allocator, basic_string, string #include <string> // for allocator, basic_string, string
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/dom/elements.hpp" // for vtext, operator|, Element, flex_grow #include "ftxui/dom/deprecated.hpp" // for vtext
#include "ftxui/dom/elements.hpp" // for operator|, Element, flex_grow, flex_shrink, vbox
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
#include "gtest/gtest_pred_impl.h" // for Test, SuiteApiResolver, EXPECT_EQ #include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST
using namespace ftxui; using namespace ftxui;
using namespace ftxui; using namespace ftxui;

View File

@ -1,19 +1,16 @@
#include "ftxui/screen/color.hpp" #include "ftxui/screen/color.hpp"
#include "ftxui/screen/color_info.hpp"
#include "ftxui/screen/string.hpp" #include "ftxui/screen/color_info.hpp" // for GetColorInfo, ColorInfo
#include "ftxui/screen/terminal.hpp" #include "ftxui/screen/terminal.hpp" // for Terminal, Terminal::Color, Terminal::Palette256, Terminal::TrueColor
namespace ftxui { namespace ftxui {
namespace { namespace {
const wchar_t* palette16code[16][2] = { const char* palette16code[16][2] = {
{L"30", L"40"}, {L"31", L"41"}, {L"32", L"42"}, {L"33", L"43"}, {"30", "40"}, {"31", "41"}, {"32", "42"}, {"33", "43"},
{L"34", L"44"}, {"34", "44"}, {"35", "45"}, {"36", "46"}, {"37", "47"},
{"90", "100"}, {"91", "101"}, {"92", "102"}, {"93", "103"},
{L"35", L"45"}, {L"36", L"46"}, {L"37", L"47"}, {"94", "104"}, {"95", "105"}, {"96", "106"}, {"97", "107"},
{L"90", L"100"}, {L"91", L"101"}, {L"92", L"102"}, {L"93", L"103"},
{L"94", L"104"}, {L"95", L"105"}, {L"96", L"106"}, {L"97", L"107"},
}; };
} }
@ -26,24 +23,24 @@ bool Color::operator!=(const Color& rhs) const {
return !operator==(rhs); return !operator==(rhs);
} }
std::wstring Color::Print(bool is_background_color) const { std::string Color::Print(bool is_background_color) const {
switch (type_) { switch (type_) {
case ColorType::Palette1: case ColorType::Palette1:
return is_background_color ? L"49" : L"39"; return is_background_color ? "49" : "39";
case ColorType::Palette16: case ColorType::Palette16:
return palette16code[index_][is_background_color]; return palette16code[index_][is_background_color];
case ColorType::Palette256: case ColorType::Palette256:
return (is_background_color ? L"48;5;" : L"38;5;") + to_wstring(index_); return (is_background_color ? "48;5;" : "38;5;") + std::to_string(index_);
case ColorType::TrueColor: case ColorType::TrueColor:
return (is_background_color ? L"48;2;" : L"38;2;") // return (is_background_color ? "48;2;" : "38;2;") //
+ to_wstring(red_) + L";" // + std::to_string(red_) + ";" //
+ to_wstring(green_) + L";" // + std::to_string(green_) + ";" //
+ to_wstring(blue_); // + std::to_string(blue_); //
} }
return L""; return "";
} }
/// @brief Build a transparent color. /// @brief Build a transparent color.

View File

@ -1,10 +1,9 @@
#include <algorithm> // for max #include <iostream> // for operator<<, stringstream, basic_ostream, flush, cout, ostream
#include <iostream> // for operator<<, basic_ostream, wstringstream, stringstream, flush, cout, ostream
#include <memory> // for allocator #include <memory> // for allocator
#include <sstream> // IWYU pragma: keep #include <sstream> // IWYU pragma: keep
#include "ftxui/screen/screen.hpp" #include "ftxui/screen/screen.hpp"
#include "ftxui/screen/string.hpp" // for to_string, wchar_width #include "ftxui/screen/string.hpp" // for string_width
#include "ftxui/screen/terminal.hpp" // for Dimensions, Size #include "ftxui/screen/terminal.hpp" // for Dimensions, Size
#if defined(_WIN32) #if defined(_WIN32)
@ -18,24 +17,24 @@
namespace ftxui { namespace ftxui {
namespace { namespace {
static const wchar_t* BOLD_SET = L"\x1B[1m"; static const char BOLD_SET[] = "\x1B[1m";
static const wchar_t* BOLD_RESET = L"\x1B[22m"; // Can't use 21 here. static const char BOLD_RESET[] = "\x1B[22m"; // Can't use 21 here.
static const wchar_t* DIM_SET = L"\x1B[2m"; static const char DIM_SET[] = "\x1B[2m";
static const wchar_t* DIM_RESET = L"\x1B[22m"; static const char DIM_RESET[] = "\x1B[22m";
static const wchar_t* UNDERLINED_SET = L"\x1B[4m"; static const char UNDERLINED_SET[] = "\x1B[4m";
static const wchar_t* UNDERLINED_RESET = L"\x1B[24m"; static const char UNDERLINED_RESET[] = "\x1B[24m";
static const wchar_t* BLINK_SET = L"\x1B[5m"; static const char BLINK_SET[] = "\x1B[5m";
static const wchar_t* BLINK_RESET = L"\x1B[25m"; static const char BLINK_RESET[] = "\x1B[25m";
static const wchar_t* INVERTED_SET = L"\x1B[7m"; static const char INVERTED_SET[] = "\x1B[7m";
static const wchar_t* INVERTED_RESET = L"\x1B[27m"; static const char INVERTED_RESET[] = "\x1B[27m";
static const char* MOVE_LEFT = "\r"; static const char MOVE_LEFT[] = "\r";
static const char* MOVE_UP = "\x1B[1A"; static const char MOVE_UP[] = "\x1B[1A";
static const char* CLEAR_LINE = "\x1B[2K"; static const char CLEAR_LINE[] = "\x1B[2K";
Pixel dev_null_pixel; Pixel dev_null_pixel;
@ -62,7 +61,9 @@ void WindowsEmulateVT100Terminal() {
} }
#endif #endif
void UpdatePixelStyle(std::wstringstream& ss, Pixel& previous, Pixel& next) { void UpdatePixelStyle(std::stringstream& ss,
Pixel& previous,
const Pixel& next) {
if (next.bold != previous.bold) if (next.bold != previous.bold)
ss << (next.bold ? BOLD_SET : BOLD_RESET); ss << (next.bold ? BOLD_SET : BOLD_RESET);
@ -80,8 +81,8 @@ void UpdatePixelStyle(std::wstringstream& ss, Pixel& previous, Pixel& next) {
if (next.foreground_color != previous.foreground_color || if (next.foreground_color != previous.foreground_color ||
next.background_color != previous.background_color) { next.background_color != previous.background_color) {
ss << L"\x1B[" + next.foreground_color.Print(false) + L"m"; ss << "\x1B[" + next.foreground_color.Print(false) + "m";
ss << L"\x1B[" + next.background_color.Print(true) + L"m"; ss << "\x1B[" + next.background_color.Print(true) + "m";
} }
previous = next; previous = next;
@ -135,7 +136,7 @@ Screen::Screen(int dimx, int dimy)
/// Produce a std::string that can be used to print the Screen on the terminal. /// Produce a std::string that can be used to print the Screen on the terminal.
/// Don't forget to flush stdout. Alternatively, you can use Screen::Print(); /// Don't forget to flush stdout. Alternatively, you can use Screen::Print();
std::string Screen::ToString() { std::string Screen::ToString() {
std::wstringstream ss; std::stringstream ss;
Pixel previous_pixel; Pixel previous_pixel;
Pixel final_pixel; Pixel final_pixel;
@ -143,24 +144,21 @@ std::string Screen::ToString() {
for (int y = 0; y < dimy_; ++y) { for (int y = 0; y < dimy_; ++y) {
if (y != 0) { if (y != 0) {
UpdatePixelStyle(ss, previous_pixel, final_pixel); UpdatePixelStyle(ss, previous_pixel, final_pixel);
ss << L"\r\n"; ss << "\r\n";
} }
for (int x = 0; x < dimx_;) { bool previous_fullwidth = false;
auto& pixel = pixels_[y][x]; for (const auto& pixel : pixels_[y]) {
if (!previous_fullwidth) {
UpdatePixelStyle(ss, previous_pixel, pixel); UpdatePixelStyle(ss, previous_pixel, pixel);
ss << pixel.character;
int x_inc = 0;
for (auto& c : pixel.character) {
ss << c;
x_inc += wchar_width(c);
} }
x += std::max(x_inc, 1); previous_fullwidth = (string_width(pixel.character) == 2);
} }
} }
UpdatePixelStyle(ss, previous_pixel, final_pixel); UpdatePixelStyle(ss, previous_pixel, final_pixel);
return to_string(ss.str()); return ss.str();
} }
void Screen::Print() { void Screen::Print() {
@ -170,8 +168,8 @@ void Screen::Print() {
/// @brief Access a character a given position. /// @brief Access a character a given position.
/// @param x The character position along the x-axis. /// @param x The character position along the x-axis.
/// @param y The character position along the y-axis. /// @param y The character position along the y-axis.
wchar_t& Screen::at(int x, int y) { std::string& Screen::at(int x, int y) {
return PixelAt(x, y).character[0]; return PixelAt(x, y).character;
} }
/// @brief Access a Pixel at a given position. /// @brief Access a Pixel at a given position.
@ -229,21 +227,21 @@ void Screen::ApplyShader() {
// Merge box characters togethers. // Merge box characters togethers.
for (int y = 1; y < dimy_; ++y) { for (int y = 1; y < dimy_; ++y) {
for (int x = 1; x < dimx_; ++x) { for (int x = 1; x < dimx_; ++x) {
wchar_t& left = at(x - 1, y); std::string& left = at(x - 1, y);
wchar_t& top = at(x, y - 1); std::string& top = at(x, y - 1);
wchar_t& cur = at(x, y); std::string& cur = at(x, y);
// Left vs current // Left vs current
if (cur == U'' && left == U'') cur = U''; if (cur == "" && left == "") cur = "";
if (cur == U'' && left == U'') left = U''; if (cur == "" && left == "") left = "";
if (cur == U'' && left == U'') cur = U''; if (cur == "" && left == "") cur = "";
if (cur == U'' && left == U'') left = U''; if (cur == "" && left == "") left = "";
// Top vs current // Top vs current
if (cur == U'' && top == U'') cur = U''; if (cur == "" && top == "") cur = "";
if (cur == U'' && top == U'') top = U''; if (cur == "" && top == "") top = "";
if (cur == U'' && top == U'') cur = U''; if (cur == "" && top == "") cur = "";
if (cur == U'' && top == U'') top = U''; if (cur == "" && top == "") top = "";
} }
} }
} }

View File

@ -1,9 +1,291 @@
// Most of this code is borrowed from:
// Markus Kuhn -- 2007-05-26 (Unicode 5.0)
// Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
// Thanks you!
//
// Modified by Arthur Sonzogni for FTXUI.
#include "ftxui/screen/string.hpp" #include "ftxui/screen/string.hpp"
#include <stddef.h> // for size_t
#include <stdint.h> // for uint32_t, uint8_t
#include <codecvt> // for codecvt_utf8_utf16 #include <codecvt> // for codecvt_utf8_utf16
#include <locale> // for wstring_convert #include <locale> // for wstring_convert
#include <string> // for string, basic_string, wstring, allocator
namespace {
struct Interval {
uint32_t first;
uint32_t last;
};
// Sorted list of non-overlapping intervals of non-spacing characters
// generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c"
static const Interval g_combining_characters[] = {
{0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489},
{0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2},
{0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603},
{0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670},
{0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED},
{0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A},
{0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902},
{0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D},
{0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981},
{0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD},
{0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C},
{0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D},
{0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC},
{0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD},
{0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C},
{0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D},
{0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0},
{0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48},
{0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC},
{0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD},
{0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D},
{0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6},
{0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E},
{0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
{0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35},
{0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E},
{0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97},
{0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030},
{0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039},
{0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F},
{0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753},
{0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD},
{0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD},
{0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922},
{0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B},
{0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34},
{0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42},
{0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF},
{0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063},
{0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F},
{0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B},
{0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F},
{0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB},
{0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F},
{0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169},
{0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
{0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F},
{0xE0100, 0xE01EF},
};
static const Interval g_full_width_characters[] = {
{0x1100, 0x115f}, {0x2329, 0x2329}, {0x232a, 0x232a}, {0x2e80, 0x303e},
{0x3040, 0xa4cf}, {0xac00, 0xd7a3}, {0xf900, 0xfaff}, {0xfe10, 0xfe19},
{0xfe30, 0xfe6f}, {0xff00, 0xff60}, {0xffe0, 0xffe6}, {0x20000, 0x2fffd},
{0x30000, 0x3fffd},
};
// Find a codepoint inside a sorted list of Interval.
int Bisearch(uint32_t ucs, const Interval* table, int max) {
if (ucs < table[0].first || ucs > table[max].last)
return 0;
int min = 0;
while (max >= min) {
int mid = (min + max) / 2;
if (ucs > table[mid].last)
min = mid + 1;
else if (ucs < table[mid].first)
max = mid - 1;
else
return 1;
}
return 0;
}
bool IsCombining(uint32_t ucs) {
return Bisearch(ucs, g_combining_characters,
sizeof(g_combining_characters) / sizeof(Interval) - 1);
}
bool IsFullWidth(uint32_t ucs) {
if (ucs < 0x0300) // Quick path:
return false;
return Bisearch(ucs, g_full_width_characters,
sizeof(g_full_width_characters) / sizeof(Interval) - 1);
}
bool IsControl(uint32_t ucs) {
if (ucs == 0)
return true;
if (ucs < 32)
return true;
if (ucs >= 0x7f && ucs < 0xa0)
return true;
return false;
}
int codepoint_width(uint32_t ucs) {
if (IsControl(ucs))
return -1;
if (IsCombining(ucs))
return 0;
if (IsFullWidth(ucs))
return 2;
return 1;
}
// From UTF8 encoded string |input|, eat in between 1 and 4 byte representing
// one codepoint. Put the codepoint into |ucs|. Start at |start| and update
// |end| to represent the beginning of the next byte to eat for consecutive
// executions.
bool EatCodePoint(const std::string& input,
size_t start,
size_t* end,
uint32_t* ucs) {
if (start >= input.size()) {
*end = start + 1;
return false;
}
uint8_t byte_1 = input[start];
// 1 byte string.
if ((byte_1 & 0b1000'0000) == 0b0000'0000) {
*ucs = byte_1 & 0b0111'1111;
*end = start + 1;
return true;
}
// 2 byte string.
if ((byte_1 & 0b1110'0000) == 0b1100'0000 && start + 1 < input.size()) {
uint8_t byte_2 = input[start + 1];
*ucs = 0;
*ucs += byte_1 & 0b0001'1111;
*ucs <<= 6;
*ucs += byte_2 & 0b0011'1111;
*end = start + 2;
return true;
}
// 3 byte string.
if ((byte_1 & 0b1111'0000) == 0b1110'0000 && start + 2 < input.size()) {
uint8_t byte_2 = input[start + 1];
uint8_t byte_3 = input[start + 2];
*ucs = 0;
*ucs += byte_1 & 0b0000'1111;
*ucs <<= 6;
*ucs += byte_2 & 0b0011'1111;
*ucs <<= 6;
*ucs += byte_3 & 0b0011'1111;
*end = start + 3;
return true;
}
// 4 byte string.
if ((byte_1 & 0b1111'1000) == 0b1111'0000 && start + 3 < input.size()) {
uint8_t byte_2 = input[start + 1];
uint8_t byte_3 = input[start + 2];
uint8_t byte_4 = input[start + 3];
*ucs = 0;
*ucs += byte_1 & 0b0000'0111;
*ucs <<= 6;
*ucs += byte_2 & 0b0011'1111;
*ucs <<= 6;
*ucs += byte_3 & 0b0011'1111;
*ucs <<= 6;
*ucs += byte_4 & 0b0011'1111;
*end = start + 4;
return true;
}
*end = start + 1;
return false;
}
} // namespace
namespace ftxui { namespace ftxui {
int wchar_width(wchar_t ucs) {
return codepoint_width(uint32_t(ucs));
}
int wstring_width(const std::wstring& text) {
int width = 0;
for (const wchar_t& it : text) {
int w = wchar_width(it);
if (w < 0)
return -1;
width += w;
}
return width;
}
int string_width(const std::string& input) {
int width = 0;
size_t start = 0;
while (start < input.size()) {
uint32_t codepoint = 0;
if (!EatCodePoint(input, start, &start, &codepoint))
continue;
if (IsControl(codepoint))
continue;
if (IsCombining(codepoint))
continue;
if (IsFullWidth(codepoint)) {
width += 2;
continue;
}
width += 1;
}
return width;
}
std::vector<std::string> Utf8ToGlyphs(const std::string& input) {
std::vector<std::string> out;
std::string current;
out.reserve(input.size());
size_t start = 0;
size_t end = 0;
while (start < input.size()) {
uint32_t codepoint;
if (!EatCodePoint(input, start, &end, &codepoint)) {
start = end;
continue;
}
std::string append = input.substr(start, end - start);
start = end;
// Ignore control characters.
if (IsControl(codepoint))
continue;
// Combining characters are put with the previous glyph they are modifying.
if (IsCombining(codepoint)) {
if (out.size() != 0)
out.back() += append;
continue;
}
// Fullwidth characters take two cells. The second is made of the empty
// string to reserve the space the first is taking.
if (IsFullWidth(codepoint)) {
out.push_back(append);
out.push_back("");
continue;
}
// Normal characters:
out.push_back(append);
}
return out;
}
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4996) // codecvt_utf8_utf16 is deprecated #pragma warning(disable : 4996) // codecvt_utf8_utf16 is deprecated

View File

@ -0,0 +1,47 @@
#include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApiResolver, TestFactoryImpl
#include <string> // for allocator, string
#include "ftxui/screen/string.hpp"
#include "gtest/gtest_pred_impl.h" // for EXPECT_EQ, Test, TEST
using namespace ftxui;
TEST(StringTest, StringWidth) {
// Basic:
EXPECT_EQ(0, string_width(""));
EXPECT_EQ(1, string_width("a"));
EXPECT_EQ(2, string_width("ab"));
// Fullwidth glyphs:
EXPECT_EQ(2, string_width(""));
EXPECT_EQ(4, string_width("测试"));
// Combining characters:
EXPECT_EQ(1, string_width(""));
EXPECT_EQ(1, string_width("a⃒"));
EXPECT_EQ(1, string_width(""));
// Control characters:
EXPECT_EQ(0, string_width("\1"));
EXPECT_EQ(2, string_width("a\1a"));
}
TEST(StringTest, Utf8ToGlyphs) {
using T = std::vector<std::string>;
// Basic:
EXPECT_EQ(Utf8ToGlyphs(""), T({}));
EXPECT_EQ(Utf8ToGlyphs("a"), T({"a"}));
EXPECT_EQ(Utf8ToGlyphs("ab"), T({"a", "b"}));
// Fullwidth glyphs:
EXPECT_EQ(Utf8ToGlyphs(""), T({"", ""}));
EXPECT_EQ(Utf8ToGlyphs("测试"), T({"", "", "", ""}));
// Combining characters:
EXPECT_EQ(Utf8ToGlyphs(""), T({""}));
EXPECT_EQ(Utf8ToGlyphs("a⃒"), T({"a⃒"}));
EXPECT_EQ(Utf8ToGlyphs(""), T({""}));
// Control characters:
EXPECT_EQ(Utf8ToGlyphs("\1"), T({}));
EXPECT_EQ(Utf8ToGlyphs("a\1a"), T({"a", "a"}));
}
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -1,317 +1,4 @@
/*
* This is an implementation of wcwidth() and wcswidth() (defined in
* IEEE Std 1002.1-2001) for Unicode.
*
* http://www.opengroup.org/onlinepubs/007904975/functions/wcwidth.html
* http://www.opengroup.org/onlinepubs/007904975/functions/wcswidth.html
*
* In fixed-width output devices, Latin characters all occupy a single
* "cell" position of equal width, whereas ideographic CJK characters
* occupy two such cells. Interoperability between terminal-line
* applications and (teletype-style) character terminals using the
* UTF-8 encoding requires agreement on which character should advance
* the cursor by how many cell positions. No established formal
* standards exist at present on which Unicode character shall occupy
* how many cell positions on character terminals. These routines are
* a first attempt of defining such behavior based on simple rules
* applied to data provided by the Unicode Consortium.
*
* For some graphical characters, the Unicode standard explicitly
* defines a character-cell width via the definition of the East Asian
* FullWidth (F), Wide (W), Half-width (H), and Narrow (Na) classes.
* In all these cases, there is no ambiguity about which width a
* terminal shall use. For characters in the East Asian Ambiguous (A)
* class, the width choice depends purely on a preference of backward
* compatibility with either historic CJK or Western practice.
* Choosing single-width for these characters is easy to justify as
* the appropriate long-term solution, as the CJK practice of
* displaying these characters as double-width comes from historic
* implementation simplicity (8-bit encoded characters were displayed
* single-width and 16-bit ones double-width, even for Greek,
* Cyrillic, etc.) and not any typographic considerations.
*
* Much less clear is the choice of width for the Not East Asian
* (Neutral) class. Existing practice does not dictate a width for any
* of these characters. It would nevertheless make sense
* typographically to allocate two character cells to characters such
* as for instance EM SPACE or VOLUME INTEGRAL, which cannot be
* represented adequately with a single-width glyph. The following
* routines at present merely assign a single-cell width to all
* neutral characters, in the interest of simplicity. This is not
* entirely satisfactory and should be reconsidered before
* establishing a formal standard in this area. At the moment, the
* decision which Not East Asian (Neutral) characters should be
* represented by double-width glyphs cannot yet be answered by
* applying a simple rule from the Unicode database content. Setting
* up a proper standard for the behavior of UTF-8 character terminals
* will require a careful analysis not only of each Unicode character,
* but also of each presentation form, something the author of these
* routines has avoided to do so far.
*
* http://www.unicode.org/unicode/reports/tr11/
*
* Markus Kuhn -- 2007-05-26 (Unicode 5.0)
*
* Permission to use, copy, modify, and distribute this software
* for any purpose and without fee is hereby granted. The author
* disclaims all warranties with regard to this software.
*
* Latest version: http://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
*/
#include <string> // Copyright 2021 Arthur Sonzogni. All rights reserved.
#include "ftxui/screen/string.hpp"
namespace ftxui {
namespace {
struct interval {
char32_t first;
char32_t last;
};
/* auxiliary function for binary search in interval table */
int bisearch(char32_t ucs, const struct interval* table, int max) {
int min = 0;
int mid;
if (ucs < table[0].first || ucs > table[max].last)
return 0;
while (max >= min) {
mid = (min + max) / 2;
if (ucs > table[mid].last)
min = mid + 1;
else if (ucs < table[mid].first)
max = mid - 1;
else
return 1;
}
return 0;
}
} // namespace
/* The following two functions define the column width of an ISO 10646
* character as follows:
*
* - The null character (U+0000) has a column width of 0.
*
* - Other C0/C1 control characters and DEL will lead to a return
* value of -1.
*
* - Non-spacing and enclosing combining characters (general
* category code Mn or Me in the Unicode database) have a
* column width of 0.
*
* - SOFT HYPHEN (U+00AD) has a column width of 1.
*
* - Other format characters (general category code Cf in the Unicode
* database) and ZERO WIDTH SPACE (U+200B) have a column width of 0.
*
* - Hangul Jamo medial vowels and final consonants (U+1160-U+11FF)
* have a column width of 0.
*
* - Spacing characters in the East Asian Wide (W) or East Asian
* Full-width (F) category as defined in Unicode Technical
* Report #11 have a column width of 2.
*
* - All remaining characters (including all printable
* ISO 8859-1 and WGL4 characters, Unicode control characters,
* etc.) have a column width of 1.
*
* This implementation assumes that char32_t characters are encoded
* in ISO 10646.
*/
int wchar_width(char32_t ucs) {
/* sorted list of non-overlapping intervals of non-spacing characters */
/* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
static const struct interval combining[] = {
{0x0300, 0x036F}, {0x0483, 0x0486}, {0x0488, 0x0489},
{0x0591, 0x05BD}, {0x05BF, 0x05BF}, {0x05C1, 0x05C2},
{0x05C4, 0x05C5}, {0x05C7, 0x05C7}, {0x0600, 0x0603},
{0x0610, 0x0615}, {0x064B, 0x065E}, {0x0670, 0x0670},
{0x06D6, 0x06E4}, {0x06E7, 0x06E8}, {0x06EA, 0x06ED},
{0x070F, 0x070F}, {0x0711, 0x0711}, {0x0730, 0x074A},
{0x07A6, 0x07B0}, {0x07EB, 0x07F3}, {0x0901, 0x0902},
{0x093C, 0x093C}, {0x0941, 0x0948}, {0x094D, 0x094D},
{0x0951, 0x0954}, {0x0962, 0x0963}, {0x0981, 0x0981},
{0x09BC, 0x09BC}, {0x09C1, 0x09C4}, {0x09CD, 0x09CD},
{0x09E2, 0x09E3}, {0x0A01, 0x0A02}, {0x0A3C, 0x0A3C},
{0x0A41, 0x0A42}, {0x0A47, 0x0A48}, {0x0A4B, 0x0A4D},
{0x0A70, 0x0A71}, {0x0A81, 0x0A82}, {0x0ABC, 0x0ABC},
{0x0AC1, 0x0AC5}, {0x0AC7, 0x0AC8}, {0x0ACD, 0x0ACD},
{0x0AE2, 0x0AE3}, {0x0B01, 0x0B01}, {0x0B3C, 0x0B3C},
{0x0B3F, 0x0B3F}, {0x0B41, 0x0B43}, {0x0B4D, 0x0B4D},
{0x0B56, 0x0B56}, {0x0B82, 0x0B82}, {0x0BC0, 0x0BC0},
{0x0BCD, 0x0BCD}, {0x0C3E, 0x0C40}, {0x0C46, 0x0C48},
{0x0C4A, 0x0C4D}, {0x0C55, 0x0C56}, {0x0CBC, 0x0CBC},
{0x0CBF, 0x0CBF}, {0x0CC6, 0x0CC6}, {0x0CCC, 0x0CCD},
{0x0CE2, 0x0CE3}, {0x0D41, 0x0D43}, {0x0D4D, 0x0D4D},
{0x0DCA, 0x0DCA}, {0x0DD2, 0x0DD4}, {0x0DD6, 0x0DD6},
{0x0E31, 0x0E31}, {0x0E34, 0x0E3A}, {0x0E47, 0x0E4E},
{0x0EB1, 0x0EB1}, {0x0EB4, 0x0EB9}, {0x0EBB, 0x0EBC},
{0x0EC8, 0x0ECD}, {0x0F18, 0x0F19}, {0x0F35, 0x0F35},
{0x0F37, 0x0F37}, {0x0F39, 0x0F39}, {0x0F71, 0x0F7E},
{0x0F80, 0x0F84}, {0x0F86, 0x0F87}, {0x0F90, 0x0F97},
{0x0F99, 0x0FBC}, {0x0FC6, 0x0FC6}, {0x102D, 0x1030},
{0x1032, 0x1032}, {0x1036, 0x1037}, {0x1039, 0x1039},
{0x1058, 0x1059}, {0x1160, 0x11FF}, {0x135F, 0x135F},
{0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753},
{0x1772, 0x1773}, {0x17B4, 0x17B5}, {0x17B7, 0x17BD},
{0x17C6, 0x17C6}, {0x17C9, 0x17D3}, {0x17DD, 0x17DD},
{0x180B, 0x180D}, {0x18A9, 0x18A9}, {0x1920, 0x1922},
{0x1927, 0x1928}, {0x1932, 0x1932}, {0x1939, 0x193B},
{0x1A17, 0x1A18}, {0x1B00, 0x1B03}, {0x1B34, 0x1B34},
{0x1B36, 0x1B3A}, {0x1B3C, 0x1B3C}, {0x1B42, 0x1B42},
{0x1B6B, 0x1B73}, {0x1DC0, 0x1DCA}, {0x1DFE, 0x1DFF},
{0x200B, 0x200F}, {0x202A, 0x202E}, {0x2060, 0x2063},
{0x206A, 0x206F}, {0x20D0, 0x20EF}, {0x302A, 0x302F},
{0x3099, 0x309A}, {0xA806, 0xA806}, {0xA80B, 0xA80B},
{0xA825, 0xA826}, {0xFB1E, 0xFB1E}, {0xFE00, 0xFE0F},
{0xFE20, 0xFE23}, {0xFEFF, 0xFEFF}, {0xFFF9, 0xFFFB},
{0x10A01, 0x10A03}, {0x10A05, 0x10A06}, {0x10A0C, 0x10A0F},
{0x10A38, 0x10A3A}, {0x10A3F, 0x10A3F}, {0x1D167, 0x1D169},
{0x1D173, 0x1D182}, {0x1D185, 0x1D18B}, {0x1D1AA, 0x1D1AD},
{0x1D242, 0x1D244}, {0xE0001, 0xE0001}, {0xE0020, 0xE007F},
{0xE0100, 0xE01EF}};
/* test for 8-bit control characters */
if (ucs == 0)
return 0;
if (ucs < 32 || (ucs >= 0x7f && ucs < 0xa0))
return -1;
/* binary search in table of non-spacing characters */
if (bisearch(ucs, combining, sizeof(combining) / sizeof(struct interval) - 1))
return 0;
/* if we arrive here, ucs is not a combining or C0/C1 control character */
return 1 +
(ucs >= 0x1100 &&
(ucs <= 0x115f || /* Hangul Jamo init. consonants */
ucs == 0x2329 || ucs == 0x232a ||
(ucs >= 0x2e80 && ucs <= 0xa4cf && ucs != 0x303f) || /* CJK ... Yi */
(ucs >= 0xac00 && ucs <= 0xd7a3) || /* Hangul Syllables */
(ucs >= 0xf900 &&
ucs <= 0xfaff) || /* CJK Compatibility Ideographs */
(ucs >= 0xfe10 && ucs <= 0xfe19) || /* Vertical forms */
(ucs >= 0xfe30 && ucs <= 0xfe6f) || /* CJK Compatibility Forms */
(ucs >= 0xff00 && ucs <= 0xff60) || /* Fullwidth Forms */
(ucs >= 0xffe0 && ucs <= 0xffe6) ||
(ucs >= 0x20000 && ucs <= 0x2fffd) ||
(ucs >= 0x30000 && ucs <= 0x3fffd)));
}
/*
* The following functions are the same as mk_wcwidth() and
* mk_wcswidth(), except that spacing characters in the East Asian
* Ambiguous (A) category as defined in Unicode Technical Report #11
* have a column width of 2. This variant might be useful for users of
* CJK legacy encodings who want to migrate to UCS without changing
* the traditional terminal character-width behaviour. It is not
* otherwise recommended for general use.
*/
int wchar_width_cjk(char32_t ucs) {
/* sorted list of non-overlapping intervals of East Asian Ambiguous
* characters, generated by "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
static const struct interval ambiguous[] = {
{0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8},
{0x00AA, 0x00AA}, {0x00AE, 0x00AE}, {0x00B0, 0x00B4},
{0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6},
{0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1},
{0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED},
{0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA},
{0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101},
{0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B},
{0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133},
{0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144},
{0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153},
{0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE},
{0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4},
{0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA},
{0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261},
{0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB},
{0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB},
{0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0391, 0x03A1},
{0x03A3, 0x03A9}, {0x03B1, 0x03C1}, {0x03C3, 0x03C9},
{0x0401, 0x0401}, {0x0410, 0x044F}, {0x0451, 0x0451},
{0x2010, 0x2010}, {0x2013, 0x2016}, {0x2018, 0x2019},
{0x201C, 0x201D}, {0x2020, 0x2022}, {0x2024, 0x2027},
{0x2030, 0x2030}, {0x2032, 0x2033}, {0x2035, 0x2035},
{0x203B, 0x203B}, {0x203E, 0x203E}, {0x2074, 0x2074},
{0x207F, 0x207F}, {0x2081, 0x2084}, {0x20AC, 0x20AC},
{0x2103, 0x2103}, {0x2105, 0x2105}, {0x2109, 0x2109},
{0x2113, 0x2113}, {0x2116, 0x2116}, {0x2121, 0x2122},
{0x2126, 0x2126}, {0x212B, 0x212B}, {0x2153, 0x2154},
{0x215B, 0x215E}, {0x2160, 0x216B}, {0x2170, 0x2179},
{0x2190, 0x2199}, {0x21B8, 0x21B9}, {0x21D2, 0x21D2},
{0x21D4, 0x21D4}, {0x21E7, 0x21E7}, {0x2200, 0x2200},
{0x2202, 0x2203}, {0x2207, 0x2208}, {0x220B, 0x220B},
{0x220F, 0x220F}, {0x2211, 0x2211}, {0x2215, 0x2215},
{0x221A, 0x221A}, {0x221D, 0x2220}, {0x2223, 0x2223},
{0x2225, 0x2225}, {0x2227, 0x222C}, {0x222E, 0x222E},
{0x2234, 0x2237}, {0x223C, 0x223D}, {0x2248, 0x2248},
{0x224C, 0x224C}, {0x2252, 0x2252}, {0x2260, 0x2261},
{0x2264, 0x2267}, {0x226A, 0x226B}, {0x226E, 0x226F},
{0x2282, 0x2283}, {0x2286, 0x2287}, {0x2295, 0x2295},
{0x2299, 0x2299}, {0x22A5, 0x22A5}, {0x22BF, 0x22BF},
{0x2312, 0x2312}, {0x2460, 0x24E9}, {0x24EB, 0x254B},
{0x2550, 0x2573}, {0x2580, 0x258F}, {0x2592, 0x2595},
{0x25A0, 0x25A1}, {0x25A3, 0x25A9}, {0x25B2, 0x25B3},
{0x25B6, 0x25B7}, {0x25BC, 0x25BD}, {0x25C0, 0x25C1},
{0x25C6, 0x25C8}, {0x25CB, 0x25CB}, {0x25CE, 0x25D1},
{0x25E2, 0x25E5}, {0x25EF, 0x25EF}, {0x2605, 0x2606},
{0x2609, 0x2609}, {0x260E, 0x260F}, {0x2614, 0x2615},
{0x261C, 0x261C}, {0x261E, 0x261E}, {0x2640, 0x2640},
{0x2642, 0x2642}, {0x2660, 0x2661}, {0x2663, 0x2665},
{0x2667, 0x266A}, {0x266C, 0x266D}, {0x266F, 0x266F},
{0x273D, 0x273D}, {0x2776, 0x277F}, {0xE000, 0xF8FF},
{0xFFFD, 0xFFFD}, {0xF0000, 0xFFFFD}, {0x100000, 0x10FFFD}};
/* binary search in table of non-spacing characters */
if (bisearch(ucs, ambiguous, sizeof(ambiguous) / sizeof(struct interval) - 1))
return 2;
return wchar_width(ucs);
}
int wchar_width(wchar_t ucs) {
return wchar_width(char32_t(ucs));
}
int wchar_width_cjk(wchar_t ucs) {
return wchar_width_cjk(char32_t(ucs));
}
int wstring_width(const std::wstring& text) {
int width = 0;
for (const wchar_t& it : text) {
int w = wchar_width(it);
if (w < 0)
return -1;
width += w;
}
return width;
}
int wstring_width_cjk(const std::wstring& text) {
int width = 0;
for (const wchar_t& it : text) {
int w = wchar_width_cjk(it);
if (w < 0)
return -1;
width += w;
}
return width;
}
} // namespace ftxui
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in // Use of this source code is governed by the MIT license that can be found in
// the LICENSE file. // the LICENSE file.