FTXUI 6.1.9
C++ functional terminal UI.
Loading...
Searching...
No Matches
homescreen.cpp
Go to the documentation of this file.
1// Copyright 2020 Arthur Sonzogni. All rights reserved.
2// Use of this source code is governed by the MIT license that can be found in
3// the LICENSE file.
4#include <stddef.h> // for size_t
5#include <array> // for array
6#include <atomic> // for atomic
7#include <chrono> // for operator""s, chrono_literals
8#include <cmath> // for sin
9#include <functional> // for ref, reference_wrapper, function
10#include <memory> // for allocator, shared_ptr, __shared_ptr_access
11#include <string> // for string, basic_string, char_traits, operator+, to_string
12#include <thread> // for sleep_for, thread
13#include <utility> // for move
14#include <vector> // for vector
15
16#include "../dom/color_info_sorted_2d.ipp" // for ColorInfoSorted2D
17#include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Input, Menu, Radiobox, ResizableSplitLeft, Tab
18#include "ftxui/component/component_base.hpp" // for ComponentBase, Component
19#include "ftxui/component/component_options.hpp" // for MenuOption, InputOption
20#include "ftxui/component/event.hpp" // for Event, Event::Custom
21#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
22#include "ftxui/dom/elements.hpp" // for text, color, operator|, bgcolor, filler, Element, vbox, size, hbox, separator, flex, window, graph, EQUAL, paragraph, WIDTH, hcenter, Elements, bold, vscroll_indicator, HEIGHT, flexbox, hflow, border, frame, flex_grow, gauge, paragraphAlignCenter, paragraphAlignJustify, paragraphAlignLeft, paragraphAlignRight, dim, spinner, LESS_THAN, center, yframe, GREATER_THAN
23#include "ftxui/dom/flexbox_config.hpp" // for FlexboxConfig
24#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, Color::Palette256, ftxui
25#include "ftxui/screen/color_info.hpp" // for ColorInfo
26#include "ftxui/screen/terminal.hpp" // for Size, Dimensions
27
28using namespace ftxui;
29
30int main() {
31 auto screen = ScreenInteractive::Fullscreen();
32
33 // ---------------------------------------------------------------------------
34 // HTOP
35 // ---------------------------------------------------------------------------
36 int shift = 0;
37
38 auto my_graph = [&shift](int width, int height) {
39 std::vector<int> output(width);
40 for (int i = 0; i < width; ++i) {
41 float v = 0.5f;
42 v += 0.1f * sin((i + shift) * 0.1f);
43 v += 0.2f * sin((i + shift + 10) * 0.15f);
44 v += 0.1f * sin((i + shift) * 0.03f);
45 v *= height;
46 output[i] = (int)v;
47 }
48 return output;
49 };
50
51 auto htop = Renderer([&] {
52 auto frequency = vbox({
53 text("Frequency [Mhz]") | hcenter,
54 hbox({
55 vbox({
56 text("2400 "),
57 filler(),
58 text("1200 "),
59 filler(),
60 text("0 "),
61 }),
62 graph(std::ref(my_graph)) | flex,
63 }) | flex,
64 });
65
66 auto utilization = vbox({
67 text("Utilization [%]") | hcenter,
68 hbox({
69 vbox({
70 text("100 "),
71 filler(),
72 text("50 "),
73 filler(),
74 text("0 "),
75 }),
76 graph(std::ref(my_graph)) | color(Color::RedLight),
77 }) | flex,
78 });
79
80 auto ram = vbox({
81 text("Ram [Mo]") | hcenter,
82 hbox({
83 vbox({
84 text("8192"),
85 filler(),
86 text("4096 "),
87 filler(),
88 text("0 "),
89 }),
90 graph(std::ref(my_graph)) | color(Color::BlueLight),
91 }) | flex,
92 });
93
94 return hbox({
95 vbox({
96 frequency | flex,
97 separator(),
98 utilization | flex,
99 }) | flex,
100 separator(),
101 ram | flex,
102 }) |
103 flex;
104 });
105
106 // ---------------------------------------------------------------------------
107 // Compiler
108 // ---------------------------------------------------------------------------
109
110 const std::vector<std::string> compiler_entries = {
111 "gcc",
112 "clang",
113 "emcc",
114 "game_maker",
115 "Ada compilers",
116 "ALGOL 60 compilers",
117 "ALGOL 68 compilers",
118 "Assemblers (Intel *86)",
119 "Assemblers (Motorola 68*)",
120 "Assemblers (Zilog Z80)",
121 "Assemblers (other)",
122 "BASIC Compilers",
123 "BASIC interpreters",
124 "Batch compilers",
125 "C compilers",
126 "Source-to-source compilers",
127 "C++ compilers",
128 "C# compilers",
129 "COBOL compilers",
130 "Common Lisp compilers",
131 "D compilers",
132 "DIBOL/DBL compilers",
133 "ECMAScript interpreters",
134 "Eiffel compilers",
135 "Fortran compilers",
136 "Go compilers",
137 "Haskell compilers",
138 "Java compilers",
139 "Pascal compilers",
140 "Perl Interpreters",
141 "PHP compilers",
142 "PL/I compilers",
143 "Python compilers",
144 "Scheme compilers and interpreters",
145 "Smalltalk compilers",
146 "Tcl Interpreters",
147 "VMS Interpreters",
148 "Rexx Interpreters",
149 "CLI compilers",
150 };
151
152 int compiler_selected = 0;
153 Component compiler = Radiobox(&compiler_entries, &compiler_selected);
154
155 std::array<std::string, 8> options_label = {
156 "-Wall",
157 "-Werror",
158 "-lpthread",
159 "-O3",
160 "-Wabi-tag",
161 "-Wno-class-conversion",
162 "-Wcomma-subscript",
163 "-Wno-conversion-null",
164 };
165 std::array<bool, 8> options_state = {
166 false, false, false, false, false, false, false, false,
167 };
168
169 std::vector<std::string> input_entries;
170 int input_selected = 0;
171 Component input = Menu(&input_entries, &input_selected);
172
173 auto input_option = InputOption();
174 std::string input_add_content;
175 input_option.on_enter = [&] {
176 input_entries.push_back(input_add_content);
177 input_add_content = "";
178 };
179 Component input_add = Input(&input_add_content, "input files", input_option);
180
181 std::string executable_content_ = "";
182 Component executable_ = Input(&executable_content_, "executable");
183
185 Checkbox(&options_label[0], &options_state[0]),
186 Checkbox(&options_label[1], &options_state[1]),
187 Checkbox(&options_label[2], &options_state[2]),
188 Checkbox(&options_label[3], &options_state[3]),
189 Checkbox(&options_label[4], &options_state[4]),
190 Checkbox(&options_label[5], &options_state[5]),
191 Checkbox(&options_label[6], &options_state[6]),
192 Checkbox(&options_label[7], &options_state[7]),
193 });
194
195 auto compiler_component = Container::Horizontal({
196 compiler,
197 flags,
199 executable_,
201 input_add,
202 input,
203 }),
204 }),
205 });
206
207 auto render_command = [&] {
208 Elements line;
209 // Compiler
210 line.push_back(text(compiler_entries[compiler_selected]) | bold);
211 // flags
212 for (int i = 0; i < 8; ++i) {
213 if (options_state[i]) {
214 line.push_back(text(" "));
215 line.push_back(text(options_label[i]) | dim);
216 }
217 }
218 // Executable
219 if (!executable_content_.empty()) {
220 line.push_back(text(" -o ") | bold);
221 line.push_back(text(executable_content_) | color(Color::BlueLight) |
222 bold);
223 }
224 // Input
225 for (auto& it : input_entries) {
226 line.push_back(text(" " + it) | color(Color::RedLight));
227 }
228 return line;
229 };
230
231 auto compiler_renderer = Renderer(compiler_component, [&] {
232 auto compiler_win = window(text("Compiler"),
233 compiler->Render() | vscroll_indicator | frame);
234 auto flags_win =
235 window(text("Flags"), flags->Render() | vscroll_indicator | frame);
236 auto executable_win = window(text("Executable:"), executable_->Render());
237 auto input_win =
238 window(text("Input"), hbox({
239 vbox({
240 hbox({
241 text("Add: "),
242 input_add->Render(),
243 }) | size(WIDTH, EQUAL, 20) |
244 size(HEIGHT, EQUAL, 1),
245 filler(),
246 }),
247 separator(),
248 input->Render() | vscroll_indicator | frame |
249 size(HEIGHT, EQUAL, 3) | flex,
250 }));
251 return vbox({
252 hbox({
253 compiler_win,
254 flags_win,
255 vbox({
256 executable_win | size(WIDTH, EQUAL, 20),
257 input_win | size(WIDTH, EQUAL, 60),
258 }),
259 filler(),
260 }) | size(HEIGHT, LESS_THAN, 8),
261 hflow(render_command()) | flex_grow,
262 }) |
263 flex_grow;
264 });
265
266 // ---------------------------------------------------------------------------
267 // Spinner
268 // ---------------------------------------------------------------------------
269 auto spinner_tab_renderer = Renderer([&] {
270 Elements entries;
271 for (int i = 0; i < 22; ++i) {
272 entries.push_back(spinner(i, shift / 2) | bold |
273 size(WIDTH, GREATER_THAN, 2) | border);
274 }
275 return hflow(std::move(entries));
276 });
277
278 // ---------------------------------------------------------------------------
279 // Colors
280 // ---------------------------------------------------------------------------
281 auto color_tab_renderer = Renderer([] {
282 auto basic_color_display =
283 vbox({
284 text("16 color palette:"),
285 separator(),
286 hbox({
287 vbox({
288 color(Color::Default, text("Default")),
289 color(Color::Black, text("Black")),
290 color(Color::GrayDark, text("GrayDark")),
291 color(Color::GrayLight, text("GrayLight")),
292 color(Color::White, text("White")),
293 color(Color::Blue, text("Blue")),
294 color(Color::BlueLight, text("BlueLight")),
295 color(Color::Cyan, text("Cyan")),
296 color(Color::CyanLight, text("CyanLight")),
297 color(Color::Green, text("Green")),
298 color(Color::GreenLight, text("GreenLight")),
299 color(Color::Magenta, text("Magenta")),
300 color(Color::MagentaLight, text("MagentaLight")),
301 color(Color::Red, text("Red")),
302 color(Color::RedLight, text("RedLight")),
303 color(Color::Yellow, text("Yellow")),
304 color(Color::YellowLight, text("YellowLight")),
305 }),
306 vbox({
307 bgcolor(Color::Default, text("Default")),
308 bgcolor(Color::Black, text("Black")),
309 bgcolor(Color::GrayDark, text("GrayDark")),
310 bgcolor(Color::GrayLight, text("GrayLight")),
311 bgcolor(Color::White, text("White")),
312 bgcolor(Color::Blue, text("Blue")),
313 bgcolor(Color::BlueLight, text("BlueLight")),
314 bgcolor(Color::Cyan, text("Cyan")),
315 bgcolor(Color::CyanLight, text("CyanLight")),
316 bgcolor(Color::Green, text("Green")),
317 bgcolor(Color::GreenLight, text("GreenLight")),
318 bgcolor(Color::Magenta, text("Magenta")),
319 bgcolor(Color::MagentaLight, text("MagentaLight")),
320 bgcolor(Color::Red, text("Red")),
321 bgcolor(Color::RedLight, text("RedLight")),
322 bgcolor(Color::Yellow, text("Yellow")),
323 bgcolor(Color::YellowLight, text("YellowLight")),
324 }),
325 }),
326 }) |
327 border;
328
329 auto palette_256_color_display = text("256 colors palette:");
330 {
331 std::vector<std::vector<ColorInfo>> info_columns = ColorInfoSorted2D();
332 Elements columns;
333 for (auto& column : info_columns) {
334 Elements column_elements;
335 for (auto& it : column) {
336 column_elements.push_back(
337 text(" ") | bgcolor(Color(Color::Palette256(it.index_256))));
338 }
339 columns.push_back(hbox(std::move(column_elements)));
340 }
341 palette_256_color_display = vbox({
342 palette_256_color_display,
343 separator(),
344 vbox(columns),
345 }) |
346 border;
347 }
348
349 // True color display.
350 auto true_color_display = text("TrueColors: 24bits:");
351 {
352 int saturation = 255;
353 Elements array;
354 for (int value = 0; value < 255; value += 16) {
355 Elements line;
356 for (int hue = 0; hue < 255; hue += 6) {
357 line.push_back(text("â–€") //
358 | color(Color::HSV(hue, saturation, value)) //
359 | bgcolor(Color::HSV(hue, saturation, value + 8)));
360 }
361 array.push_back(hbox(std::move(line)));
362 }
363 true_color_display = vbox({
364 true_color_display,
365 separator(),
366 vbox(std::move(array)),
367 }) |
368 border;
369 }
370
371 return flexbox(
372 {
373 basic_color_display,
374 palette_256_color_display,
375 true_color_display,
376 },
377 FlexboxConfig().SetGap(1, 1));
378 });
379
380 // ---------------------------------------------------------------------------
381 // Gauges
382 // ---------------------------------------------------------------------------
383 auto render_gauge = [&shift](int delta) {
384 float progress = (shift + delta) % 500 / 500.f;
385 return hbox({
386 text(std::to_string(int(progress * 100)) + "% ") |
387 size(WIDTH, EQUAL, 5),
388 gauge(progress),
389 });
390 };
391
392 auto gauge_component = Renderer([render_gauge] {
393 return vbox({
394 render_gauge(0) | color(Color::Black),
395 render_gauge(100) | color(Color::GrayDark),
396 render_gauge(50) | color(Color::GrayLight),
397 render_gauge(6894) | color(Color::White),
398 separator(),
399 render_gauge(6841) | color(Color::Blue),
400 render_gauge(9813) | color(Color::BlueLight),
401 render_gauge(98765) | color(Color::Cyan),
402 render_gauge(98) | color(Color::CyanLight),
403 render_gauge(9846) | color(Color::Green),
404 render_gauge(1122) | color(Color::GreenLight),
405 render_gauge(84) | color(Color::Magenta),
406 render_gauge(645) | color(Color::MagentaLight),
407 render_gauge(568) | color(Color::Red),
408 render_gauge(2222) | color(Color::RedLight),
409 render_gauge(220) | color(Color::Yellow),
410 render_gauge(348) | color(Color::YellowLight),
411 });
412 });
413
414 // ---------------------------------------------------------------------------
415 // Paragraph
416 // ---------------------------------------------------------------------------
417 auto make_box = [](size_t dimx, size_t dimy) {
418 std::string title = std::to_string(dimx) + "x" + std::to_string(dimy);
419 return window(text(title) | hcenter | bold,
420 text("content") | hcenter | dim) |
421 size(WIDTH, EQUAL, dimx) | size(HEIGHT, EQUAL, dimy);
422 };
423
424 auto paragraph_renderer_left = Renderer([&] {
425 std::string str =
426 "Lorem Ipsum is simply dummy text of the printing and typesetting "
427 "industry.\nLorem Ipsum has been the industry's standard dummy text "
428 "ever since the 1500s, when an unknown printer took a galley of type "
429 "and scrambled it to make a type specimen book.";
430 return vbox({
431 window(text("Align left:"), paragraphAlignLeft(str)),
432 window(text("Align center:"), paragraphAlignCenter(str)),
433 window(text("Align right:"), paragraphAlignRight(str)),
434 window(text("Align justify:"), paragraphAlignJustify(str)),
435 window(text("Side by side"), hbox({
436 paragraph(str),
437 separator(),
438 paragraph(str),
439 })),
440 window(text("Elements with different size:"),
441 flexbox({
442 make_box(10, 5),
443 make_box(9, 4),
444 make_box(8, 4),
445 make_box(6, 3),
446 make_box(10, 5),
447 make_box(9, 4),
448 make_box(8, 4),
449 make_box(6, 3),
450 make_box(10, 5),
451 make_box(9, 4),
452 make_box(8, 4),
453 make_box(6, 3),
454 })),
455 }) |
456 vscroll_indicator | yframe | flex;
457 });
458
459 auto paragraph_renderer_right = Renderer([] {
460 return paragraph("<--- This vertical bar is resizable using the mouse") |
461 center;
462 });
463
464 int paragraph_renderer_split_position = Terminal::Size().dimx / 2;
465 auto paragraph_renderer_group =
466 ResizableSplitLeft(paragraph_renderer_left, paragraph_renderer_right,
467 &paragraph_renderer_split_position);
468 auto paragraph_renderer_group_renderer =
469 Renderer(paragraph_renderer_group,
470 [&] { return paragraph_renderer_group->Render(); });
471
472 // ---------------------------------------------------------------------------
473 // Tabs
474 // ---------------------------------------------------------------------------
475
476 int tab_index = 0;
477 std::vector<std::string> tab_entries = {
478 "htop", "color", "spinner", "gauge", "compiler", "paragraph",
479 };
480 auto tab_selection =
481 Menu(&tab_entries, &tab_index, MenuOption::HorizontalAnimated());
482 auto tab_content = Container::Tab(
483 {
484 htop,
485 color_tab_renderer,
486 spinner_tab_renderer,
487 gauge_component,
488 compiler_renderer,
489 paragraph_renderer_group_renderer,
490 },
491 &tab_index);
492
493 auto exit_button =
494 Button("Exit", [&] { screen.Exit(); }, ButtonOption::Animated());
495
496 auto main_container = Container::Vertical({
498 tab_selection,
499 exit_button,
500 }),
501 tab_content,
502 });
503
504 auto main_renderer = Renderer(main_container, [&] {
505 return vbox({
506 text("FTXUI Demo") | bold | hcenter,
507 hbox({
508 tab_selection->Render() | flex,
509 exit_button->Render(),
510 }),
511 tab_content->Render() | flex,
512 });
513 });
514
515 std::atomic<bool> refresh_ui_continue = true;
516 std::thread refresh_ui([&] {
517 while (refresh_ui_continue) {
518 using namespace std::chrono_literals;
519 std::this_thread::sleep_for(0.05s);
520 // The |shift| variable belong to the main thread. `screen.Post(task)`
521 // will execute the update on the thread where |screen| lives (e.g. the
522 // main thread). Using `screen.Post(task)` is threadsafe.
523 screen.Post([&] { shift++; });
524 // After updating the state, request a new frame to be drawn. This is done
525 // by simulating a new "custom" event to be handled.
526 screen.Post(Event::Custom);
527 }
528 });
529
530 screen.Loop(main_renderer);
531 refresh_ui_continue = false;
532 refresh_ui.join();
533
534 return 0;
535}
std::vector< std::vector< ftxui::ColorInfo > > ColorInfoSorted2D()
Element make_box(int x, int y)
static ButtonOption Animated()
Create a ButtonOption, using animated colors.
Element Render()
Draw the component. Build a ftxui::Element to be drawn on the ftxui::Screen representing this ftxui::...
static ScreenInteractive Fullscreen()
static const Event Custom
Definition event.hpp:97
static MenuOption HorizontalAnimated()
Standard options for an animated horizontal menu. This can be useful to implement a tab bar.
Component Horizontal(Components children)
A list of components, drawn one by one horizontally and navigated horizontally using left/right arrow...
Component Menu(MenuOption options)
A list of text. The focused element is selected.
Component Radiobox(RadioboxOption options)
A list of element, where only one can be selected.
Component Button(ButtonOption options)
Draw a button. Execute a function when clicked.
Component Renderer(Component child, std::function< Element()>)
Return a new Component, similar to |child|, but using |render| as the Component::Render() event.
Component Vertical(Components children)
A list of components, drawn one by one vertically and navigated vertically using up/down arrow key or...
Component Input(InputOption options={})
An input box for editing text.
Component Checkbox(CheckboxOption options)
Draw checkable element.
Component ResizableSplitLeft(Component main, Component back, int *main_size)
An horizontal split in between two components, configurable using the mouse.
Component Tab(Components children, int *selector)
A list of components, where only one is drawn and interacted with at a time. The |selector| gives the...
Option for the Input component.
virtual void Render(Screen &screen)
Display an element on a ftxui::Screen.
Definition node.cpp:59
FlexboxConfig & SetGap(int gap_x, int gap_y)
Set the flexbox flex direction.
Decorator bgcolor(Color)
Decorate using a background color.
Element window(Element title, Element content, BorderStyle border=ROUNDED)
Draw window with a title and a border around the element.
Decorator size(WidthOrHeight, Constraint, int value)
Apply a constraint on the size of an element.
Element flex(Element)
Make a child element to expand proportionally to the space left in a container.
Definition flex.cpp:123
Element paragraphAlignRight(const std::string &text)
Return an element drawing the paragraph on multiple lines, aligned on the right.
Element spinner(int charset_index, size_t image_index)
Useful to represent the effect of time and/or events. This displays an ASCII art "video".
Element center(Element)
Center an element horizontally and vertically.
Element paragraphAlignCenter(const std::string &text)
Return an element drawing the paragraph on multiple lines, aligned on the center.
Element text(std::wstring text)
Display a piece of unicode text.
Definition text.cpp:160
Element flex_grow(Element)
Expand if possible.
Definition flex.cpp:141
Element paragraphAlignLeft(const std::string &text)
Return an element drawing the paragraph on multiple lines, aligned on the left.
Element separator()
Draw a vertical or horizontal separation in between two other elements.
Element filler()
An element that will take expand proportionally to the space left in a container.
Definition flex.cpp:98
Element gauge(float progress)
Draw a high definition progress bar.
Element paragraphAlignJustify(const std::string &text)
Return an element drawing the paragraph on multiple lines, aligned using a justified alignment....
Decorator color(Color)
Decorate using a foreground color.
Element hcenter(Element)
Center an element horizontally.
Element vbox(Elements)
A container displaying elements vertically one by one.
Definition vbox.cpp:96
FlexboxConfig is a configuration structure that defines the layout properties for a flexbox container...
static Color HSV(uint8_t hue, uint8_t saturation, uint8_t value)
Build a Color from its HSV representation. https://en.wikipedia.org/wiki/HSL_and_HSV.
Color is a class that represents a color in the terminal user interface.
Definition color.hpp:22
Dimensions Size()
Get the terminal size.
Definition terminal.cpp:94
int main()
The FTXUI ftxui:: namespace.
Definition animation.hpp:10
Element flexbox(Elements, FlexboxConfig config=FlexboxConfig())
A container displaying elements on row/columns and capable of wrapping on the next column/row when fu...
Definition flexbox.cpp:251
Element hflow(Elements)
A container displaying elements in rows from left to right. When filled, it starts on a new row below...
Definition flexbox.cpp:269
Element hbox(Elements)
A container displaying elements horizontally one by one.
Definition hbox.cpp:94
std::vector< Element > Elements
Definition elements.hpp:23
Elements paragraph(std::wstring text)
@ LESS_THAN
Definition elements.hpp:162
@ GREATER_THAN
Definition elements.hpp:162
Element graph(GraphFunction)
Draw a graph using a GraphFunction.
std::shared_ptr< ComponentBase > Component