FTXUI/examples/component/homescreen.cpp
Arthur Sonzogni 3b4ab618a3
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>
2021-08-08 23:25:20 +02:00

379 lines
13 KiB
C++

#include <array> // for array
#include <chrono> // for operator""s, chrono_literals
#include <cmath> // for sin
#include <functional> // for ref, reference_wrapper, function
#include <memory> // for allocator, shared_ptr, __shared_ptr_access
#include <string> // for wstring, basic_string, operator+, char_traits, to_wstring
#include <thread> // for sleep_for, thread
#include <utility> // for move
#include <vector> // for vector
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#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_options.hpp" // for InputOption
#include "ftxui/component/deprecated.hpp" // for Input
#include "ftxui/component/event.hpp" // for Event, Event::Custom
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#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
using namespace ftxui;
int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::Fullscreen();
int shift = 0;
auto my_graph = [&shift](int width, int height) {
std::vector<int> output(width);
for (int i = 0; i < width; ++i) {
float v = 0.5f;
v += 0.1f * sin((i + shift) * 0.1f);
v += 0.2f * sin((i + shift + 10) * 0.15f);
v += 0.1f * sin((i + shift) * 0.03f);
v *= height;
output[i] = (int)v;
}
return output;
};
auto htop = Renderer([&] {
auto frequency = vbox({
text(L"Frequency [Mhz]") | hcenter,
hbox({
vbox({
text(L"2400 "),
filler(),
text(L"1200 "),
filler(),
text(L"0 "),
}),
graph(std::ref(my_graph)) | flex,
}) | flex,
});
auto utilization = vbox({
text(L"Utilization [%]") | hcenter,
hbox({
vbox({
text(L"100 "),
filler(),
text(L"50 "),
filler(),
text(L"0 "),
}),
graph(std::ref(my_graph)) | color(Color::RedLight),
}) | flex,
});
auto ram = vbox({
text(L"Ram [Mo]") | hcenter,
hbox({
vbox({
text(L"8192"),
filler(),
text(L"4096 "),
filler(),
text(L"0 "),
}),
graph(std::ref(my_graph)) | color(Color::BlueLight),
}) | flex,
});
return hbox({
vbox({
frequency | flex,
separator(),
utilization | flex,
}) | flex,
separator(),
ram | flex,
}) |
flex | border;
});
const std::vector<std::wstring> compiler_entries = {
L"gcc",
L"clang",
L"emcc",
L"game_maker",
L"Ada compilers",
L"ALGOL 60 compilers",
L"ALGOL 68 compilers",
L"Assemblers (Intel *86)",
L"Assemblers (Motorola 68*)",
L"Assemblers (Zilog Z80)",
L"Assemblers (other)",
L"BASIC Compilers",
L"BASIC interpreters",
L"Batch compilers",
L"C compilers",
L"Source-to-source compilers",
L"C++ compilers",
L"C# compilers",
L"COBOL compilers",
L"Common Lisp compilers",
L"D compilers",
L"DIBOL/DBL compilers",
L"ECMAScript interpreters",
L"Eiffel compilers",
L"Fortran compilers",
L"Go compilers",
L"Haskell compilers",
L"Java compilers",
L"Pascal compilers",
L"Perl Interpreters",
L"PHP compilers",
L"PL/I compilers",
L"Python compilers",
L"Scheme compilers and interpreters",
L"Smalltalk compilers",
L"Tcl Interpreters",
L"VMS Interpreters",
L"Rexx Interpreters",
L"CLI compilers",
};
int compiler_selected = 0;
Component compiler = Radiobox(&compiler_entries, &compiler_selected);
std::array<std::wstring, 4> options_label = {
L"-Wall",
L"-Werror",
L"-lpthread",
L"-O3",
};
std::array<bool, 4> options_state = {
false,
false,
false,
false,
};
std::vector<std::wstring> input_entries;
int input_selected = 0;
Component input = Menu(&input_entries, &input_selected);
auto input_option = InputOption();
std::wstring input_add_content;
input_option.on_enter = [&] {
input_entries.push_back(input_add_content);
input_add_content = L"";
};
Component input_add = Input(&input_add_content, "input files", input_option);
std::wstring executable_content_ = L"";
Component executable_ = Input(&executable_content_, "executable");
Component flags = Container::Vertical({
Checkbox(&options_label[0], &options_state[0]),
Checkbox(&options_label[1], &options_state[1]),
Checkbox(&options_label[2], &options_state[2]),
Checkbox(&options_label[3], &options_state[3]),
});
auto compiler_component = Container::Horizontal({
compiler,
flags,
Container::Vertical({
executable_,
Container::Horizontal({
input_add,
input,
}),
}),
});
auto render_command = [&] {
Elements line;
// Compiler
line.push_back(text(compiler_entries[compiler_selected]) | bold);
// flags
for (int i = 0; i < 4; ++i) {
if (options_state[i]) {
line.push_back(text(L" "));
line.push_back(text(options_label[i]) | dim);
}
}
// Executable
if (!executable_content_.empty()) {
line.push_back(text(L" -o ") | bold);
line.push_back(text(executable_content_) | color(Color::BlueLight) |
bold);
}
// Input
for (auto& it : input_entries) {
line.push_back(text(L" " + it) | color(Color::RedLight));
}
return line;
};
auto compiler_renderer = Renderer(compiler_component, [&] {
auto compiler_win = window(text(L"Compiler"), compiler->Render() | frame);
auto flags_win = window(text(L"Flags"), flags->Render());
auto executable_win = window(text(L"Executable:"), executable_->Render());
auto input_win =
window(text(L"Input"),
hbox({
vbox({
hbox({
text(L"Add: "),
input_add->Render(),
}) | size(WIDTH, EQUAL, 20) |
size(HEIGHT, EQUAL, 1),
filler(),
}),
separator(),
input->Render() | frame | size(HEIGHT, EQUAL, 3) | flex,
}));
return vbox({
hbox({
compiler_win | size(HEIGHT, LESS_THAN, 6),
flags_win,
vbox({
executable_win | size(WIDTH, EQUAL, 20),
input_win | size(WIDTH, EQUAL, 60),
}),
filler(),
}),
hflow(render_command()) | flex_grow,
}) |
flex_grow | border;
});
auto spinner_tab_renderer = Renderer([&] {
Elements entries;
for (int i = 0; i < 22; ++i) {
entries.push_back(spinner(i, shift / 2) | bold |
size(WIDTH, GREATER_THAN, 2) | border);
}
return hflow(std::move(entries)) | border;
});
auto color_tab_renderer = Renderer([] {
return hbox({
vbox({
color(Color::Default, text(L"Default")),
color(Color::Black, text(L"Black")),
color(Color::GrayDark, text(L"GrayDark")),
color(Color::GrayLight, text(L"GrayLight")),
color(Color::White, text(L"White")),
color(Color::Blue, text(L"Blue")),
color(Color::BlueLight, text(L"BlueLight")),
color(Color::Cyan, text(L"Cyan")),
color(Color::CyanLight, text(L"CyanLight")),
color(Color::Green, text(L"Green")),
color(Color::GreenLight, text(L"GreenLight")),
color(Color::Magenta, text(L"Magenta")),
color(Color::MagentaLight, text(L"MagentaLight")),
color(Color::Red, text(L"Red")),
color(Color::RedLight, text(L"RedLight")),
color(Color::Yellow, text(L"Yellow")),
color(Color::YellowLight, text(L"YellowLight")),
}),
vbox({
bgcolor(Color::Default, text(L"Default")),
bgcolor(Color::Black, text(L"Black")),
bgcolor(Color::GrayDark, text(L"GrayDark")),
bgcolor(Color::GrayLight, text(L"GrayLight")),
bgcolor(Color::White, text(L"White")),
bgcolor(Color::Blue, text(L"Blue")),
bgcolor(Color::BlueLight, text(L"BlueLight")),
bgcolor(Color::Cyan, text(L"Cyan")),
bgcolor(Color::CyanLight, text(L"CyanLight")),
bgcolor(Color::Green, text(L"Green")),
bgcolor(Color::GreenLight, text(L"GreenLight")),
bgcolor(Color::Magenta, text(L"Magenta")),
bgcolor(Color::MagentaLight, text(L"MagentaLight")),
bgcolor(Color::Red, text(L"Red")),
bgcolor(Color::RedLight, text(L"RedLight")),
bgcolor(Color::Yellow, text(L"Yellow")),
bgcolor(Color::YellowLight, text(L"YellowLight")),
}),
}) |
hcenter | border;
});
auto render_gauge = [&shift](int delta) {
float progress = (shift + delta) % 1000 / 1000.f;
return hbox({
text(std::to_wstring(int(progress * 100)) + L"% ") |
size(WIDTH, EQUAL, 5),
gauge(progress),
});
};
auto gauge_component = Renderer([render_gauge] {
return vbox({
render_gauge(0) | color(Color::Black),
render_gauge(100) | color(Color::GrayDark),
render_gauge(50) | color(Color::GrayLight),
render_gauge(6894) | color(Color::White),
separator(),
render_gauge(6841) | color(Color::Blue),
render_gauge(9813) | color(Color::BlueLight),
render_gauge(98765) | color(Color::Cyan),
render_gauge(98) | color(Color::CyanLight),
render_gauge(9846) | color(Color::Green),
render_gauge(1122) | color(Color::GreenLight),
render_gauge(84) | color(Color::Magenta),
render_gauge(645) | color(Color::MagentaLight),
render_gauge(568) | color(Color::Red),
render_gauge(2222) | color(Color::RedLight),
render_gauge(220) | color(Color::Yellow),
render_gauge(348) | color(Color::YellowLight),
}) |
border;
});
int tab_index = 0;
std::vector<std::wstring> tab_entries = {
L"htop", L"color", L"spinner", L"gauge", L"compiler",
};
auto tab_selection = Toggle(&tab_entries, &tab_index);
auto tab_content = Container::Tab(
{
htop,
color_tab_renderer,
spinner_tab_renderer,
gauge_component,
compiler_renderer,
},
&tab_index);
auto main_container = Container::Vertical({
tab_selection,
tab_content,
});
auto main_renderer = Renderer(main_container, [&] {
return vbox({
text(L"FTXUI Demo") | bold | hcenter,
tab_selection->Render() | hcenter,
tab_content->Render() | flex,
});
});
bool refresh_ui_continue = true;
std::thread refresh_ui([&] {
while (refresh_ui_continue) {
using namespace std::chrono_literals;
std::this_thread::sleep_for(0.05s);
shift++;
screen.PostEvent(Event::Custom);
}
});
screen.Loop(main_renderer);
refresh_ui_continue = false;
refresh_ui.join();
return 0;
}
// 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.