mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-05-06 07:33:07 +08:00

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>
379 lines
13 KiB
C++
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.
|