button
Demo
screen.Loop(testComponent);
return 0;
}
Component Renderer(Component child, std::function< Element()>)
Return a new Component, similar to |child|, but using |render| as the Component::Render() event.
static ScreenInteractive Fullscreen()
Element text(std::wstring text)
Display a piece of unicode text.
button_animated
Demo
#include <memory>
#include <string>
int value = 50;
auto buttons = Container::Horizontal({
Button(
"Decrease", [&] { value--; }, ButtonOption::Animated(Color::Red)),
Button(
"Reset", [&] { value = 50; }, ButtonOption::Animated(Color::Green)),
Button(
"Increase", [&] { value++; }, ButtonOption::Animated(Color::Blue)),
});
auto component =
Renderer(buttons, [&] {
text(
"value = " + std::to_string(value)),
}) | border,
buttons->Render(),
});
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(component);
return 0;
}
Element separator()
Draw a vertical or horizontal separation in between two other elements.
Element gauge(float progress)
Draw a high definition progress bar.
Element vbox(Elements)
A container displaying elements vertically one by one.
button_in_frame
Demo
#include <memory>
#include <string>
int counter = 0;
auto on_click = [&] { counter++; };
auto style = ButtonOption::Animated(Color::Default, Color::GrayDark,
Color::Default, Color::White);
auto container = Container::Vertical({});
for (int i = 0; i < 30; ++i) {
auto button = Button("Button " + std::to_string(i), on_click, style);
container->Add(button);
}
auto renderer =
Renderer(container, [&] {
text(std::to_string(counter)),
}),
size(HEIGHT, LESS_THAN, 20),
}) |
border;
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(renderer);
return 0;
}
Element vscroll_indicator(Element)
Display a vertical scrollbar to the right. colors.
Decorator size(WidthOrHeight, Constraint, int value)
Apply a constraint on the size of an element.
Element hbox(Elements)
A container displaying elements horizontally one by one.
Element frame(Element)
Allow an element to be displayed inside a 'virtual' area. It size can be larger than its container....
button_style
Demo
#include <string>
int value = 0;
auto action = [&] { value++; };
auto action_renderer =
Renderer([&] { return text("count = " + std::to_string(value)); });
auto buttons =
Container::Vertical({
action_renderer,
Renderer([] { return separator(); }),
Container::Horizontal({
Container::Vertical({
Button(
"Ascii 1", action, ButtonOption::Ascii()),
Button(
"Ascii 2", action, ButtonOption::Ascii()),
Button(
"Ascii 3", action, ButtonOption::Ascii()),
}),
Container::Vertical({
Button(
"Simple 1", action, ButtonOption::Simple()),
Button(
"Simple 2", action, ButtonOption::Simple()),
Button(
"Simple 3", action, ButtonOption::Simple()),
}),
Container::Vertical({
Button(
"Animated 1", action, ButtonOption::Animated()),
Button(
"Animated 2", action, ButtonOption::Animated()),
Button(
"Animated 3", action, ButtonOption::Animated()),
}),
Container::Vertical({
ButtonOption::Animated(Color::Red)),
ButtonOption::Animated(Color::Green)),
ButtonOption::Animated(Color::Blue)),
}),
}),
}) |
border;
auto screen = ScreenInteractive::FitComponent();
screen.Loop(buttons);
return 0;
}
Component Button(ButtonOption options)
Draw a button. Execute a function when clicked.
canvas_animated
Demo
#include <cmath>
#include <memory>
#include <string>
#include <utility>
#include <vector>
int mouse_x = 0;
int mouse_y = 0;
auto renderer_line_braille = Renderer([&] {
c.DrawText(0, 0, "Several lines (braille)");
c.DrawPointLine(mouse_x, mouse_y, 80, 10, Color::Red);
c.DrawPointLine(80, 10, 80, 40, Color::Blue);
c.DrawPointLine(80, 40, mouse_x, mouse_y, Color::Green);
return canvas(std::move(c));
});
auto renderer_line_block = Renderer([&] {
c.DrawText(0, 0, "Several lines (block)");
c.DrawBlockLine(mouse_x, mouse_y, 80, 10, Color::Red);
c.DrawBlockLine(80, 10, 80, 40, Color::Blue);
c.DrawBlockLine(80, 40, mouse_x, mouse_y, Color::Green);
return canvas(std::move(c));
});
auto renderer_circle_braille = Renderer([&] {
c.DrawText(0, 0, "A circle (braille)");
c.DrawPointCircle(mouse_x, mouse_y, 30);
return canvas(std::move(c));
});
auto renderer_circle_block =
Renderer([&] {
c.DrawText(0, 0, "A circle (block)");
c.DrawBlockCircle(mouse_x, mouse_y, 30);
});
auto renderer_circle_filled_braille =
Renderer([&] {
c.DrawText(0, 0, "A circle filled (braille)");
c.DrawPointCircleFilled(mouse_x, mouse_y, 30);
});
auto renderer_circle_filled_block =
Renderer([&] {
c.DrawText(0, 0, "A circle filled (block)");
c.DrawBlockCircleFilled(mouse_x, mouse_y, 30);
});
auto renderer_ellipse_braille =
Renderer([&] {
c.DrawText(0, 0, "An ellipse (braille)");
c.DrawPointEllipse(mouse_x / 2, mouse_y / 2, mouse_x / 2, mouse_y / 2);
});
auto renderer_ellipse_block =
Renderer([&] {
c.DrawText(0, 0, "An ellipse (block)");
c.DrawBlockEllipse(mouse_x / 2, mouse_y / 2, mouse_x / 2, mouse_y / 2);
});
auto renderer_ellipse_filled_braille =
Renderer([&] {
c.DrawText(0, 0, "A filled ellipse (braille)");
c.DrawPointEllipseFilled(mouse_x / 2, mouse_y / 2, mouse_x / 2,
mouse_y / 2);
});
auto renderer_ellipse_filled_block =
Renderer([&] {
c.DrawText(0, 0, "A filled ellipse (block)");
c.DrawBlockEllipseFilled(mouse_x / 2, mouse_y / 2, mouse_x / 2,
mouse_y / 2);
c.DrawBlockEllipse(mouse_x / 2, mouse_y / 2, mouse_x / 2, mouse_y / 2);
});
c.DrawText(0, 0, "A piece of text");
c.DrawText(mouse_x, mouse_y, "This is a piece of text with effects",
});
});
c.DrawText(0, 0, "A graph");
std::vector<int> ys(100);
for (int x = 0; x < 100; x++) {
float dx = float(x - mouse_x);
float dy = 50.f;
ys[x] = int(dy + 20 * cos(dx * 0.14) + 10 * sin(dx * 0.42));
}
for (int x = 1; x < 99; x++)
c.DrawPointLine(x, ys[x], x + 1, ys[x + 1]);
});
c.DrawText(0, 0, "A symmetrical graph filled");
std::vector<int> ys(100);
for (int x = 0; x < 100; x++) {
ys[x] = int(30 +
10 * cos(x * 0.2 - mouse_x * 0.05) +
5 * sin(x * 0.4) +
5 * sin(x * 0.3 - mouse_y * 0.05));
}
for (int x = 0; x < 100; x++) {
c.DrawPointLine(x, 50 + ys[x], x, 50 - ys[x], Color::Red);
}
});
c.DrawText(0, 0, "A 2D gaussian plot");
float my = (mouse_y - 90) / -5.f;
float mx = (mouse_x - 3 * my) / 5.f;
std::vector<std::vector<float>> ys(size, std::vector<float>(size));
for (
int y = 0; y <
size; y++) {
for (
int x = 0; x <
size; x++) {
float dx = x - mx;
float dy = y - my;
ys[y][x] = -1.5 + 3.0 * std::exp(-0.2f * (dx * dx + dy * dy));
}
}
for (
int y = 0; y <
size; y++) {
for (
int x = 0; x <
size; x++) {
if (x != 0) {
c.DrawPointLine(
5 * (x - 1) + 3 * (y - 0), 90 - 5 * (y - 0) - 5 * ys[y][x - 1],
5 * (x - 0) + 3 * (y - 0), 90 - 5 * (y - 0) - 5 * ys[y][x]);
}
if (y != 0) {
c.DrawPointLine(
5 * (x - 0) + 3 * (y - 1), 90 - 5 * (y - 1) - 5 * ys[y - 1][x],
5 * (x - 0) + 3 * (y - 0), 90 - 5 * (y - 0) - 5 * ys[y][x]);
}
}
}
});
int selected_tab = 12;
auto tab = Container::Tab(
{
renderer_line_braille,
renderer_line_block,
renderer_circle_braille,
renderer_circle_block,
renderer_circle_filled_braille,
renderer_circle_filled_block,
renderer_ellipse_braille,
renderer_ellipse_block,
renderer_ellipse_filled_braille,
renderer_ellipse_filled_block,
renderer_plot_1,
renderer_plot_2,
renderer_plot_3,
renderer_text,
},
&selected_tab);
mouse_x = (e.
mouse().x - 1) * 2;
mouse_y = (e.
mouse().y - 1) * 4;
}
return false;
});
std::vector<std::string> tab_titles = {
"line (braille)",
"line (block)",
"circle (braille)",
"circle (block)",
"circle filled (braille)",
"circle filled (block)",
"ellipse (braille)",
"ellipse (block)",
"ellipse filled (braille)",
"ellipse filled (block)",
"plot_1 simple",
"plot_2 filled",
"plot_3 3D",
"text",
};
auto tab_toggle =
Menu(&tab_titles, &selected_tab);
auto component = Container::Horizontal({
tab_with_mouse,
tab_toggle,
});
auto component_renderer =
Renderer(component, [&] {
tab_with_mouse->Render(),
tab_toggle->Render(),
}) |
border;
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(component_renderer);
return 0;
}
Component Menu(MenuOption options)
A list of text. The focused element is selected.
A Unicode character and its associated style.
Element canvas(ConstRef< Canvas >)
Produce an element from a Canvas, or a reference to a Canvas.
Component CatchEvent(Component child, std::function< bool(Event)>)
Represent an event. It can be key press event, a terminal resize, or more ...
checkbox
Demo
#include <array>
#include <iostream>
#include <memory>
#include <string>
bool download = false;
bool upload = false;
bool ping = false;
auto container = Container::Vertical({
Checkbox("Download", &download),
Checkbox("Upload", &upload),
Checkbox("Ping", &ping),
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(container);
std::cout << "---" << std::endl;
std::cout << "Download: " << download << std::endl;
std::cout << "Upload: " << upload << std::endl;
std::cout << "Ping: " << ping << std::endl;
std::cout << "---" << std::endl;
return 0;
}
checkbox_in_frame
Demo
#include <array>
#include <memory>
#include <string>
std::array<bool, 30> states;
auto container = Container::Vertical({});
for (int i = 0; i < 30; ++i) {
states[i] = false;
container->Add(Checkbox("Checkbox" + std::to_string(i), &states[i]));
}
auto renderer = Renderer(container, [&] {
return container->Render() | vscroll_indicator | frame |
size(HEIGHT, LESS_THAN, 10) | border;
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(renderer);
return 0;
}
collapsible
Demo
#include <memory>
#include <utility>
#include <vector>
Component vlist = Container::Vertical(std::move(children));
return Renderer(vlist, [vlist] {
return hbox({
text(" "),
vlist->Render(),
});
});
}
return std::make_shared<ComponentBase>();
}
auto component =
})),
})),
})),
}));
ScreenInteractive::FitComponent().Loop(component);
}
Component Inner(std::vector< Component > children)
Component Collapsible(ConstStringRef label, Component child, Ref< bool > show=false)
A collapsible component. It display a checkbox with an arrow. Once activated, the children is display...
std::shared_ptr< ComponentBase > Component
composition
Demo
#include <memory>
#include <string>
auto left_count = 0;
auto right_count = 0;
auto left_buttons = Container::Horizontal({
Button("Decrease", [&] { left_count--; }),
Button("Increase", [&] { left_count++; }),
});
auto right_buttons = Container::Horizontal({
Button(
"Decrease", [&] { right_count--; }),
Button(
"Increase", [&] { right_count++; }),
});
auto leftpane =
Renderer(left_buttons, [&] {
text(
"This is the left control"),
text(
"Left button count: " + std::to_string(left_count)),
left_buttons->Render(),
}) |
border;
});
auto rightpane =
Renderer(right_buttons, [&] {
text(
"This is the right control"),
text(
"Right button count: " + std::to_string(right_count)),
right_buttons->Render(),
}) |
border;
});
auto composition = Container::Horizontal({leftpane, rightpane});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(composition);
return 0;
}
custom_loop
Demo
#include <stdlib.h>
#include <chrono>
#include <memory>
#include <string>
#include <thread>
auto screen = ScreenInteractive::FitComponent();
int custom_loop_count = 0;
int frame_count = 0;
int event_count = 0;
auto component = Renderer([&] {
frame_count++;
return vbox({
text("This demonstrates using a custom ftxui::Loop. It "),
text("runs at 100 iterations per seconds. The FTXUI events "),
text("are all processed once per iteration and a new frame "),
text("is rendered as needed"),
separator(),
text("ftxui event count: " + std::to_string(event_count)),
text("ftxui frame count: " + std::to_string(frame_count)),
text("Custom loop count: " + std::to_string(custom_loop_count)),
}) |
border;
});
component |= CatchEvent([&](
Event) ->
bool {
event_count++;
return false;
});
Loop loop(&screen, component);
while (!loop.HasQuitted()) {
custom_loop_count++;
loop.RunOnce();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
return EXIT_SUCCESS;
}
dropdown
Demo
#include <string>
#include <vector>
std::vector<std::string> entries = {
"tribute", "clearance", "ally", "bend", "electronics",
"module", "era", "cultural", "sniff", "nationalism",
"negotiation", "deliver", "figure", "east", "tribute",
"clearance", "ally", "bend", "electronics", "module",
"era", "cultural", "sniff", "nationalism", "negotiation",
"deliver", "figure", "east", "tribute", "clearance",
"ally", "bend", "electronics", "module", "era",
"cultural", "sniff", "nationalism", "negotiation", "deliver",
"figure", "east",
};
int selected_1 = 0;
int selected_2 = 0;
int selected_3 = 0;
int selected_4 = 0;
auto layout = Container::Vertical({
Container::Horizontal({
Dropdown(&entries, &selected_1),
Dropdown(&entries, &selected_2),
}),
Container::Horizontal({
Dropdown(&entries, &selected_3),
Dropdown(&entries, &selected_4),
}),
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(layout);
}
dropdown_custom
Demo
#include <string>
#include <vector>
std::vector<std::string> entries = {
"tribute", "clearance", "ally", "bend", "electronics",
"module", "era", "cultural", "sniff", "nationalism",
"negotiation", "deliver", "figure", "east", "tribute",
"clearance", "ally", "bend", "electronics", "module",
"era", "cultural", "sniff", "nationalism", "negotiation",
"deliver", "figure", "east", "tribute", "clearance",
"ally", "bend", "electronics", "module", "era",
"cultural", "sniff", "nationalism", "negotiation", "deliver",
"figure", "east",
};
auto dropdown_1 = Dropdown({
.radiobox = {.entries = &entries},
.transform =
if (open) {
return vbox({
checkbox | inverted,
radiobox | vscroll_indicator | frame |
size(HEIGHT, LESS_THAN, 10),
filler(),
});
}
checkbox,
});
},
});
.radiobox = {.entries = &entries},
.transform =
if (open) {
});
}
});
},
});
.radiobox =
{
.entries = &entries,
.transform =
if (s.active) {
}
if (s.focused) {
}
return t;
},
},
.transform =
if (open) {
});
}
});
},
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(Container::Horizontal({
dropdown_1,
dropdown_2,
dropdown_3,
}));
}
Component Dropdown(ConstStringListRef entries, int *selected)
A dropdown menu.
Decorator bgcolor(Color)
Decorate using a background color.
Element bold(Element)
Use a bold font, for elements with more emphasis.
Element inverted(Element)
Add a filter that will invert the foreground and the background colors.
Element filler()
An element that will take expand proportionally to the space left in a container.
Element borderEmpty(Element)
Draw an empty border around the element.
std::shared_ptr< Node > Element
arguments for transform from |ButtonOption|, |CheckboxOption|, |RadioboxOption|, |MenuEntryOption|,...
flexbox_gallery
Demo
#include <stddef.h>
#include <memory>
#include <string>
#include <vector>
auto screen = ScreenInteractive::Fullscreen();
int direction_index = 0;
int wrap_index = 0;
int justify_content_index = 0;
int align_items_index = 0;
int align_content_index = 0;
std::vector<std::string> directions = {
"Row",
"RowInversed",
"Column",
"ColumnInversed",
};
std::vector<std::string> wraps = {
"NoWrap",
"Wrap",
"WrapInversed",
};
std::vector<std::string> justify_content = {
"FlexStart", "FlexEnd", "Center", "Stretch",
"SpaceBetween", "SpaceAround", "SpaceEvenly",
};
std::vector<std::string> align_items = {
"FlexStart",
"FlexEnd",
"Center",
"Stretch",
};
std::vector<std::string> align_content = {
"FlexStart", "FlexEnd", "Center", "Stretch",
"SpaceBetween", "SpaceAround", "SpaceEvenly",
};
auto radiobox_direction =
Radiobox(&directions, &direction_index);
auto radiobox_wrap =
Radiobox(&wraps, &wrap_index);
auto radiobox_justify_content =
Radiobox(&justify_content, &justify_content_index);
auto radiobox_align_items =
Radiobox(&align_items, &align_items_index);
auto radiobox_align_content =
Radiobox(&align_content, &align_content_index);
bool element_xflex_grow = false;
bool element_yflex_grow = false;
bool group_xflex_grow = true;
bool group_yflex_grow = true;
auto checkbox_element_xflex_grow =
Checkbox(
"element |= xflex_grow", &element_xflex_grow);
auto checkbox_element_yflex_grow =
Checkbox(
"element |= yflex_grow", &element_yflex_grow);
auto checkbox_group_xflex_grow =
Checkbox(
"group |= xflex_grow", &group_xflex_grow);
auto checkbox_group_yflex_grow =
Checkbox(
"group |= yflex_grow", &group_yflex_grow);
auto make_box = [&](
size_t dimx,
size_t dimy,
size_t index) {
std::string title = std::to_string(dimx) + "x" + std::to_string(dimy);
auto element =
window(
text(title) | hcenter | bold,
text(std::to_string(index)) | hcenter | dim) |
size(WIDTH, EQUAL, dimx) |
size(HEIGHT, EQUAL, dimy) |
bgcolor(Color::HSV(index * 25, 255, 255)) |
if (element_xflex_grow)
if (element_yflex_grow)
return element;
};
{
},
config);
group = group |
bgcolor(Color::Black);
if (!group_xflex_grow)
if (!group_yflex_grow)
return group;
});
.
Set(FlexboxConfig::JustifyContent::Center)
.
Set(FlexboxConfig::AlignContent::Center);
int space_right = 10;
int space_bottom = 1;
content_renderer, &space_right);
content_renderer, &space_bottom);
auto main_container = Container::Vertical({
Container::Horizontal({
radiobox_direction,
radiobox_wrap,
Container::Vertical({
checkbox_element_xflex_grow,
checkbox_element_yflex_grow,
checkbox_group_xflex_grow,
checkbox_group_yflex_grow,
}),
}),
Container::Horizontal({
radiobox_justify_content,
radiobox_align_items,
radiobox_align_content,
}),
content_renderer,
});
auto main_renderer =
Renderer(main_container, [&] {
radiobox_direction->Render()),
window(
text(
"FlexboxConfig::Wrap"), radiobox_wrap->Render()),
checkbox_element_xflex_grow->Render(),
checkbox_element_yflex_grow->Render(),
checkbox_group_xflex_grow->Render(),
checkbox_group_yflex_grow->Render(),
})),
}),
radiobox_justify_content->Render()),
radiobox_align_items->Render()),
radiobox_align_content->Render()),
})}),
});
});
screen.Loop(main_renderer);
return 0;
}
Element make_box(int x, int y)
Component Radiobox(RadioboxOption options)
A list of element, where only one can be selected.
Component ResizableSplitRight(Component main, Component back, int *main_size)
An horizontal split in between two components, configurable using the mouse.
Component ResizableSplitBottom(Component main, Component back, int *main_size)
An vertical split in between two components, configurable using the mouse.
Component Checkbox(CheckboxOption options)
Draw checkable element.
Element window(Element title, Element content, BorderStyle border=ROUNDED)
Draw window with a title and a border around the element.
Element xflex_grow(Element)
Expand if possible on the X axis.
Element flex(Element)
Make a child element to expand proportionally to the space left in a container.
Element center(Element)
Center an element horizontally and vertically.
Element yflex_grow(Element)
Expand if possible on the Y axis.
Element notflex(Element)
Make the element not flexible.
FlexboxConfig & Set(FlexboxConfig::Direction)
Set the flexbox direction.
Element border(Element)
Draw a border around the element.
Decorator color(Color)
Decorate using a foreground color.
Element flexbox(Elements, FlexboxConfig config=FlexboxConfig())
A container displaying elements on row/columns and capable of wrapping on the next column/row when fu...
AlignContent align_content
JustifyContent justify_content
focus
Demo
#include <memory>
#include <string>
#include <vector>
std::string title = "(" + std::to_string(x) + ", " + std::to_string(y) + ")";
return text(title) | center | size(WIDTH, EQUAL, 18) |
size(HEIGHT, EQUAL, 9) | border |
bgcolor(Color::HSV(x * 255 / 15, 255, y * 255 / 15));
};
std::vector<Elements> rows;
for (int i = 0; i < 15; i++) {
std::vector<Element> cols;
for (int j = 0; j < 15; j++) {
}
rows.push_back(cols);
}
};
float focus_x = 0.5f;
float focus_y = 0.5f;
auto slider_x =
Slider(
"x", &focus_x, 0.f, 1.f, 0.01f);
auto slider_y =
Slider(
"y", &focus_y, 0.f, 1.f, 0.01f);
Container::Vertical({
slider_x,
slider_y,
}),
[&] {
auto title = "focusPositionRelative(" +
std::to_string(focus_x) + ", " +
std::to_string(focus_y) + ")";
slider_x->Render(),
slider_y->Render(),
}) |
border;
});
auto screen = ScreenInteractive::Fullscreen();
screen.Loop(renderer);
return 0;
}
Decorator focusPositionRelative(float x, float y)
Used inside a frame, this force the view to be scrolled toward a a given position....
Component Slider(SliderOption< T > options)
A slider in any direction.
Element gridbox(std::vector< Elements > lines)
A container displaying a grid of elements.
focus_cursor
Demo
#include <string>
return Renderer([=](bool focused) {
if (focused) {
return hbox({
text("> " + label + " "),
focusCursor(text(" ")),
});
}
return text(" " + label + " ");
});
};
auto screen = ScreenInteractive::Fullscreen();
screen.Loop(Container::Vertical({
Instance(
"focusCursorBlock", focusCursorBlock),
Instance(
"focusCursorBlockBlinking", focusCursorBlockBlinking),
Instance(
"focusCursorBar", focusCursorBar),
Instance(
"focusCursorBarBlinking", focusCursorBarBlinking),
Instance(
"focusCursorUnderline", focusCursorUnderline),
Instance(
"focusCursorUnderlineBlinking", focusCursorUnderlineBlinking),
}));
return 0;
}
Component Instance(std::string label, Decorator focusCursor)
std::function< Element(Element)> Decorator
gallery
Demo
#include <functional>
#include <memory>
#include <string>
#include <vector>
return Renderer(component, [name, component] {
return hbox({
text(name) | size(WIDTH, EQUAL, 8),
separator(),
component->Render() | xflex,
}) |
xflex;
});
}
auto screen = ScreenInteractive::FitComponent();
const std::vector<std::string> menu_entries = {
"Menu 1",
"Menu 2",
"Menu 3",
"Menu 4",
};
int menu_selected = 0;
auto menu =
Menu(&menu_entries, &menu_selected);
menu =
Wrap(
"Menu", menu);
int toggle_selected = 0;
std::vector<std::string> toggle_entries = {
"Toggle_1",
"Toggle_2",
};
auto toggle =
Toggle(&toggle_entries, &toggle_selected);
toggle =
Wrap(
"Toggle", toggle);
bool checkbox_1_selected = false;
bool checkbox_2_selected = false;
bool checkbox_3_selected = false;
bool checkbox_4_selected = false;
auto checkboxes = Container::Vertical({
Checkbox(
"checkbox1", &checkbox_1_selected),
Checkbox(
"checkbox2", &checkbox_2_selected),
Checkbox(
"checkbox3", &checkbox_3_selected),
Checkbox(
"checkbox4", &checkbox_4_selected),
});
checkboxes =
Wrap(
"Checkbox", checkboxes);
int radiobox_selected = 0;
std::vector<std::string> radiobox_entries = {
"Radiobox 1",
"Radiobox 2",
"Radiobox 3",
"Radiobox 4",
};
auto radiobox =
Radiobox(&radiobox_entries, &radiobox_selected);
radiobox =
Wrap(
"Radiobox", radiobox);
std::string input_label;
auto input =
Input(&input_label,
"placeholder");
input =
Wrap(
"Input", input);
std::string button_label = "Quit";
std::function<void()> on_button_clicked_;
auto button =
Button(&button_label, screen.ExitLoopClosure());
button =
Wrap(
"Button", button);
int slider_value_1 = 12;
int slider_value_2 = 56;
int slider_value_3 = 128;
auto sliders = Container::Vertical({
Slider(
"R:", &slider_value_1, 0, 256, 1),
Slider(
"G:", &slider_value_2, 0, 256, 1),
Slider(
"B:", &slider_value_3, 0, 256, 1),
});
sliders =
Wrap(
"Slider", sliders);
text(
"Lorem ipsum dolor sit amet, consectetur adipiscing elit. "),
text(
"Sed do eiusmod tempor incididunt ut labore et dolore magna "
"aliqua. "),
text(
"Ut enim ad minim veniam, quis nostrud exercitation ullamco "
"laboris nisi ut aliquip ex ea commodo consequat. "),
text(
"Duis aute irure dolor in reprehenderit in voluptate velit esse "
"cillum dolore eu fugiat nulla pariatur. "),
text(
"Excepteur sint occaecat cupidatat non proident, sunt in culpa "
"qui officia deserunt mollit anim id est laborum. "),
});
});
lorel_ipsum =
Wrap(
"Lorel Ipsum", lorel_ipsum);
auto layout = Container::Vertical({
menu,
toggle,
checkboxes,
radiobox,
input,
sliders,
button,
lorel_ipsum,
});
menu->Render(),
toggle->Render(),
checkboxes->Render(),
radiobox->Render(),
input->Render(),
sliders->Render(),
button->Render(),
lorel_ipsum->Render(),
}) |
});
screen.Loop(component);
return 0;
}
Component Wrap(std::string name, Component component)
Component Toggle(ConstStringListRef entries, int *selected)
An horizontal list of elements. The user can navigate through them.
Component Input(InputOption options={})
An input box for editing text.
homescreen
Demo
#include <stddef.h>
#include <array>
#include <atomic>
#include <chrono>
#include <cmath>
#include <functional>
#include <memory>
#include <string>
#include <thread>
#include <utility>
#include <vector>
#include "../dom/color_info_sorted_2d.ipp"
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("Frequency [Mhz]") | hcenter,
hbox({
vbox({
text("2400 "),
filler(),
text("1200 "),
filler(),
text("0 "),
}),
}) | flex,
});
auto utilization =
vbox({
}),
graph(std::ref(my_graph)) |
color(Color::RedLight),
}) | flex,
});
}),
graph(std::ref(my_graph)) |
color(Color::BlueLight),
}) | flex,
});
}) | flex,
}) |
flex;
});
const std::vector<std::string> compiler_entries = {
"gcc",
"clang",
"emcc",
"game_maker",
"Ada compilers",
"ALGOL 60 compilers",
"ALGOL 68 compilers",
"Assemblers (Intel *86)",
"Assemblers (Motorola 68*)",
"Assemblers (Zilog Z80)",
"Assemblers (other)",
"BASIC Compilers",
"BASIC interpreters",
"Batch compilers",
"C compilers",
"Source-to-source compilers",
"C++ compilers",
"C# compilers",
"COBOL compilers",
"Common Lisp compilers",
"D compilers",
"DIBOL/DBL compilers",
"ECMAScript interpreters",
"Eiffel compilers",
"Fortran compilers",
"Go compilers",
"Haskell compilers",
"Java compilers",
"Pascal compilers",
"Perl Interpreters",
"PHP compilers",
"PL/I compilers",
"Python compilers",
"Scheme compilers and interpreters",
"Smalltalk compilers",
"Tcl Interpreters",
"VMS Interpreters",
"Rexx Interpreters",
"CLI compilers",
};
int compiler_selected = 0;
std::array<std::string, 8> options_label = {
"-Wall",
"-Werror",
"-lpthread",
"-O3",
"-Wabi-tag",
"-Wno-class-conversion",
"-Wcomma-subscript",
"-Wno-conversion-null",
};
std::array<bool, 8> options_state = {
false, false, false, false, false, false, false, false,
};
std::vector<std::string> input_entries;
int input_selected = 0;
std::string input_add_content;
input_option.on_enter = [&] {
input_entries.push_back(input_add_content);
input_add_content = "";
};
Component input_add =
Input(&input_add_content,
"input files", input_option);
std::string executable_content_ = "";
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]),
Checkbox(&options_label[4], &options_state[4]),
Checkbox(&options_label[5], &options_state[5]),
Checkbox(&options_label[6], &options_state[6]),
Checkbox(&options_label[7], &options_state[7]),
});
auto compiler_component = Container::Horizontal({
compiler,
flags,
Container::Vertical({
executable_,
Container::Horizontal({
input_add,
input,
}),
}),
});
auto render_command = [&] {
line.push_back(
text(compiler_entries[compiler_selected]) | bold);
for (int i = 0; i < 8; ++i) {
if (options_state[i]) {
line.push_back(
text(
" "));
line.push_back(
text(options_label[i]) | dim);
}
}
if (!executable_content_.empty()) {
line.push_back(
text(
" -o ") | bold);
line.push_back(
text(executable_content_) |
color(Color::BlueLight) |
bold);
}
for (auto& it : input_entries) {
line.push_back(
text(
" " + it) |
color(Color::RedLight));
}
return line;
};
auto compiler_renderer =
Renderer(compiler_component, [&] {
compiler->Render() | vscroll_indicator | frame);
auto flags_win =
window(
text(
"Flags"), flags->Render() | vscroll_indicator | frame);
auto executable_win =
window(
text(
"Executable:"), executable_->Render());
auto input_win =
input_add->Render(),
}) |
size(WIDTH, EQUAL, 20) |
}),
}));
compiler_win,
flags_win,
executable_win |
size(WIDTH, EQUAL, 20),
input_win |
size(WIDTH, EQUAL, 60),
}),
}) |
size(HEIGHT, LESS_THAN, 8),
}) |
flex_grow;
});
auto spinner_tab_renderer =
Renderer([&] {
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));
});
auto basic_color_display =
text(
"16 color palette:"),
color(Color::GreenLight,
text(
"GreenLight")),
color(Color::MagentaLight,
text(
"MagentaLight")),
color(Color::YellowLight,
text(
"YellowLight")),
}),
}),
}),
}) |
border;
auto palette_256_color_display =
text(
"256 colors palette:");
{
for (auto& column : info_columns) {
for (auto& it : column) {
column_elements.push_back(
}
columns.push_back(
hbox(std::move(column_elements)));
}
palette_256_color_display =
vbox({
palette_256_color_display,
}) |
border;
}
auto true_color_display =
text(
"TrueColors: 24bits:");
{
int saturation = 255;
for (int value = 0; value < 255; value += 16) {
for (int hue = 0; hue < 255; hue += 6) {
|
color(Color::HSV(hue, saturation, value))
|
bgcolor(Color::HSV(hue, saturation, value + 8)));
}
array.push_back(
hbox(std::move(line)));
}
true_color_display =
vbox({
true_color_display,
}) |
border;
}
{
basic_color_display,
palette_256_color_display,
true_color_display,
},
});
auto render_gauge = [&shift](int delta) {
float progress = (shift + delta) % 500 / 500.f;
text(std::to_string(
int(progress * 100)) +
"% ") |
});
};
auto gauge_component =
Renderer([render_gauge] {
render_gauge(0) |
color(Color::Black),
render_gauge(100) |
color(Color::GrayDark),
render_gauge(50) |
color(Color::GrayLight),
render_gauge(6894) |
color(Color::White),
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),
});
});
auto make_box = [](
size_t dimx,
size_t dimy) {
std::string title = std::to_string(dimx) + "x" + std::to_string(dimy);
text(
"content") | hcenter | dim) |
size(WIDTH, EQUAL, dimx) |
size(HEIGHT, EQUAL, dimy);
};
auto paragraph_renderer_left =
Renderer([&] {
std::string str =
"Lorem Ipsum is simply dummy text of the printing and typesetting "
"industry.\nLorem Ipsum has been the industry's standard dummy text "
"ever since the 1500s, when an unknown printer took a galley of type "
"and scrambled it to make a type specimen book.";
})),
})),
}) |
vscroll_indicator | yframe | flex;
});
auto paragraph_renderer_right =
Renderer([] {
return paragraph(
"<--- This vertical bar is resizable using the mouse") |
});
int paragraph_renderer_split_position = Terminal::Size().dimx / 2;
auto paragraph_renderer_group =
¶graph_renderer_split_position);
auto paragraph_renderer_group_renderer =
[&] { return paragraph_renderer_group->Render(); });
int tab_index = 0;
std::vector<std::string> tab_entries = {
"htop", "color", "spinner", "gauge", "compiler", "paragraph",
};
auto tab_selection =
Menu(&tab_entries, &tab_index, MenuOption::HorizontalAnimated());
auto tab_content = Container::Tab(
{
htop,
color_tab_renderer,
spinner_tab_renderer,
gauge_component,
compiler_renderer,
paragraph_renderer_group_renderer,
},
&tab_index);
auto exit_button =
Button(
"Exit", [&] { screen.Exit(); }, ButtonOption::Animated());
auto main_container = Container::Vertical({
Container::Horizontal({
tab_selection,
exit_button,
}),
tab_content,
});
auto main_renderer =
Renderer(main_container, [&] {
tab_selection->Render() |
flex,
exit_button->Render(),
}),
tab_content->Render() |
flex,
});
});
std::atomic<bool> refresh_ui_continue = true;
std::thread refresh_ui([&] {
while (refresh_ui_continue) {
using namespace std::chrono_literals;
std::this_thread::sleep_for(0.05s);
screen.Post([&] { shift++; });
screen.Post(Event::Custom);
}
});
screen.Loop(main_renderer);
refresh_ui_continue = false;
refresh_ui.join();
return 0;
}
std::vector< std::vector< ftxui::ColorInfo > > ColorInfoSorted2D()
Component ResizableSplitLeft(Component main, Component back, int *main_size)
An horizontal split in between two components, configurable using the mouse.
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 display an ASCII art "video".
Element paragraphAlignCenter(const std::string &text)
Return an element drawing the paragraph on multiple lines, aligned on the center.
Element flex_grow(Element)
Expand if possible.
FlexboxConfig & SetGap(int gap_x, int gap_y)
Set the flexbox flex direction.
Element paragraphAlignLeft(const std::string &text)
Return an element drawing the paragraph on multiple lines, aligned on the left.
Element paragraphAlignJustify(const std::string &text)
Return an element drawing the paragraph on multiple lines, aligned using a justified alignment....
Element hcenter(Element)
Center an element horizontally.
A class representing terminal colors.
Element hflow(Elements)
A container displaying elements in rows from left to right. When filled, it starts on a new row below...
std::vector< Element > Elements
Elements paragraph(std::wstring text)
Element graph(GraphFunction)
Draw a graph using a GraphFunction.
input
Demo
#include <memory>
#include <string>
std::string first_name;
std::string last_name;
std::string password;
std::string phoneNumber;
Component input_first_name = Input(&first_name,
"first name");
Component input_last_name = Input(&last_name,
"last name");
Component input_password = Input(&password,
"password", password_option);
Component input_phone_number = Input(&phoneNumber,
"phone number");
input_phone_number |= CatchEvent([&](
Event event) {
return event.is_character() && !std::isdigit(event.
character()[0]);
});
input_phone_number |= CatchEvent([&](
Event event) {
return event.is_character() && phoneNumber.size() > 10;
});
auto component = Container::Vertical({
input_first_name,
input_last_name,
input_password,
input_phone_number,
});
auto renderer =
Renderer(component, [&] {
hbox(
text(
" First name : "), input_first_name->Render()),
hbox(
text(
" Last name : "), input_last_name->Render()),
hbox(
text(
" Password : "), input_password->Render()),
hbox(
text(
" Phone num : "), input_phone_number->Render()),
text(
"Hello " + first_name +
" " + last_name),
text(
"Your password is " + password),
text(
"Your phone number is " + phoneNumber),
}) |
border;
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(renderer);
}
Ref< bool > password
Obscure the input content using '*'.
std::string character() const
input_in_frame
Demo
#include <memory>
#include <string>
#include <vector>
Component input_list = Container::Vertical({});
std::vector<std::string> items(100, "");
for (size_t i = 0; i < items.size(); ++i) {
input_list->Add(Input(&(items[i]), "placeholder " + std::to_string(i)));
}
auto renderer = Renderer(input_list, [&] {
return input_list->Render() | vscroll_indicator | frame | border |
size(HEIGHT, LESS_THAN, 10);
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(renderer);
}
input_style
Demo
#include <functional>
#include <string>
#include <utility>
state.element |= borderEmpty;
if (state.is_placeholder) {
state.element |= dim;
}
if (state.focused) {
state.element |= borderDouble;
state.element |= bgcolor(Color::White);
state.element |= color(Color::Black);
} else if (state.hovered) {
state.element |= borderRounded;
state.element |= bgcolor(
LinearGradient(90, Color::Blue, Color::Red));
state.element |= color(Color::White);
} else {
state.element |=
color(Color::White);
}
return state.element;
};
std::move(state.element),
});
if (state.is_placeholder) {
}
if (state.focused) {
state.element |=
bgcolor(Color::Black);
} else {
state.element |=
bgcolor(Color::Blue);
}
if (state.hovered) {
state.element |=
bgcolor(Color::GrayDark);
}
};
auto first_name = new std::string();
auto middle_name = new std::string();
auto last_name = new std::string();
return Container::Vertical({
Input(first_name,
"first name", style),
Input(middle_name,
"middle name", style),
Input(last_name,
"last name", style),
}) |
borderEmpty;
};
auto ui = Container::Horizontal({
generateUiFromStyle(style_1),
generateUiFromStyle(style_2),
generateUiFromStyle(style_3),
generateUiFromStyle(style_4),
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(ui);
}
std::function< Element(InputState)> transform
Element separatorEmpty()
Draw a vertical or horizontal separation in between two other elements, using the EMPTY style.
Element dim(Element)
Use a light font, for elements with less emphasis.
A class representing the settings for linear-gradient color effect.
linear_gradient_gallery
Demo
#include <memory>
#include <string>
auto screen = ScreenInteractive::Fullscreen();
float start = 0.f;
float end = 1.f;
std::string slider_angle_text;
std::string slider_start_text;
std::string slider_end_text;
auto slider_angle = Slider(&slider_angle_text, &
angle, 0, 360);
auto slider_start = Slider(&slider_start_text, &start, 0.f, 1.f, 0.05f);
auto slider_end = Slider(&slider_end_text, &end, 0.f, 1.f, 0.05f);
auto layout = Container::Vertical({
slider_angle,
slider_start,
slider_end,
});
auto renderer = Renderer(layout, [&] {
slider_angle_text =
"angle = " + std::to_string(
angle) +
"°";
slider_start_text = "start = " + std::to_string(int(start * 100)) + "%";
slider_end_text = "end = " + std::to_string(int(end * 100)) + "%";
auto background = text("Gradient") | center |
.Stop(Color::Blue, start)
.Stop(Color::Red, end));
return vbox({
background | flex,
layout->Render(),
}) |
flex;
});
screen.Loop(renderer);
}
maybe
Demo
#include <string>
#include <vector>
std::vector<std::string> entries = {
"entry 1",
"entry 2",
"entry 3",
};
int menu_1_selected = 0;
int menu_2_selected = 0;
bool menu_1_show = false;
bool menu_2_show = false;
auto layout = Container::Vertical({
Checkbox("Show menu_1", &menu_1_show),
Radiobox(&entries, &menu_1_selected) | border | Maybe(&menu_1_show),
Checkbox("Show menu_2", &menu_2_show),
Radiobox(&entries, &menu_2_selected) | border | Maybe(&menu_2_show),
Renderer([] {
return text("You found the secret combinaison!") | color(Color::Red);
}) | Maybe([&] { return menu_1_selected == 1 && menu_2_selected == 2; }),
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(layout);
}
menu
Demo
#include <functional>
#include <iostream>
#include <string>
#include <vector>
auto screen = ScreenInteractive::TerminalOutput();
std::vector<std::string> entries = {
"entry 1",
"entry 2",
"entry 3",
};
int selected = 0;
option.
on_enter = screen.ExitLoopClosure();
auto menu = Menu(&entries, &selected, option);
screen.Loop(menu);
std::cout << "Selected element = " << selected << std::endl;
}
std::function< void()> on_enter
menu2
Demo
#include <functional>
#include <memory>
#include <string>
#include <vector>
auto screen = ScreenInteractive::TerminalOutput();
std::vector<std::string> left_menu_entries = {
"0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%",
};
std::vector<std::string> right_menu_entries = {
"0%", "1%", "2%", "3%", "4%", "5%", "6%", "7%", "8%", "9%", "10%",
};
menu_option.on_enter = screen.ExitLoopClosure();
int left_menu_selected = 0;
int right_menu_selected = 0;
Menu(&left_menu_entries, &left_menu_selected, menu_option);
Menu(&right_menu_entries, &right_menu_selected, menu_option);
Component container = Container::Horizontal({
left_menu_,
right_menu_,
});
auto renderer =
Renderer(container, [&] {
int sum = left_menu_selected * 10 + right_menu_selected;
left_menu_->Render(),
}),
right_menu_->Render(),
}),
}),
}),
text(std::to_string(sum) +
" %"),
}),
}),
}) |
border;
});
screen.Loop(renderer);
}
menu_entries
Demo
#include <functional>
#include <iostream>
#include <memory>
#include <string>
state.label = (state.active ? "> " : " ") + state.label;
Element e = text(state.label) | color(c);
if (state.focused)
e = e | inverted;
if (state.active)
e = e | bold;
return e;
};
return option;
}
auto screen = ScreenInteractive::TerminalOutput();
int selected = 0;
auto menu = Container::Vertical(
{
MenuEntry(" 1. improve"),
MenuEntry(" 2. tolerant"),
MenuEntry(" 3. career"),
MenuEntry(" 4. cast"),
MenuEntry(" 5. question"),
Renderer([] { return separator(); }),
},
&selected);
menu->Render() |
frame |
size(HEIGHT, LESS_THAN, 10),
}) |
border;
});
screen.Loop(renderer);
std::cout << "Selected element = " << selected << std::endl;
}
std::function< Element(const EntryState &state)> transform
Component MenuEntry(MenuEntryOption options)
A specific menu entry. They can be put into a Container::Vertical to form a menu.
menu_entries_animated
Demo
#include <iostream>
#include <memory>
#include <string>
return option;
}
auto screen = ScreenInteractive::TerminalOutput();
int selected = 0;
auto menu = Container::Vertical(
{
MenuEntry(
" 1. rear",
Colored(Color::Red)),
MenuEntry(
" 2. drown",
Colored(Color::Yellow)),
MenuEntry(
" 3. nail",
Colored(Color::Green)),
MenuEntry(
" 4. quit",
Colored(Color::Cyan)),
MenuEntry(
" 5. decorative",
Colored(Color::Blue)),
MenuEntry(" 7. costume"),
MenuEntry(" 8. pick"),
MenuEntry(" 9. oral"),
MenuEntry("11. minister"),
MenuEntry("12. football"),
MenuEntry("13. welcome"),
MenuEntry("14. copper"),
MenuEntry("15. inhabitant"),
},
&selected);
auto renderer = Renderer(menu, [&] {
return vbox({
hbox(text("selected = "), text(std::to_string(selected))),
separator(),
menu->Render() | frame,
}) |
});
screen.Loop(renderer);
std::cout << "Selected element = " << selected << std::endl;
}
AnimatedColorsOption animated_colors
AnimatedColorOption foreground
AnimatedColorOption background
menu_in_frame
Demo
#include <memory>
#include <string>
#include <vector>
std::vector<std::string> entries;
int selected = 0;
for (int i = 0; i < 30; ++i)
entries.push_back("Entry " + std::to_string(i));
auto radiobox = Menu(&entries, &selected);
auto renderer = Renderer(radiobox, [&] {
return radiobox->Render() | vscroll_indicator | frame |
size(HEIGHT, LESS_THAN, 10) | border;
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(renderer);
return 0;
}
menu_in_frame_horizontal
Demo
#include <memory>
#include <string>
#include <vector>
std::vector<std::string> entries;
int selected = 0;
for (int i = 0; i < 100; ++i)
entries.push_back(std::to_string(i));
auto radiobox = Menu(&entries, &selected, MenuOption::Horizontal());
auto renderer = Renderer(
radiobox, [&] { return radiobox->Render() | hscroll_indicator | frame; });
auto screen = ScreenInteractive::FitComponent();
screen.Loop(renderer);
return 0;
}
menu_multiple
Demo
#include <stdlib.h>
#include <memory>
#include <string>
#include <vector>
return Renderer(component, [component, title] {
return window(text(title), component->Render()) | flex;
});
}
int menu_selected[] = {0, 0, 0};
std::vector<std::vector<std::string>> menu_entries = {
{
"Ananas",
"Raspberry",
"Citrus",
},
{
"Potatoes",
"Weat",
"Rise",
},
{
"Carrot",
"Lettuce",
"Tomato",
},
};
int menu_selected_global = 0;
auto menu_global = Container::Vertical(
{
Window(
"Menu 1",
Menu(&menu_entries[0], &menu_selected[0])),
Window(
"Menu 2",
Menu(&menu_entries[1], &menu_selected[1])),
Window(
"Menu 3",
Menu(&menu_entries[2], &menu_selected[2])),
},
&menu_selected_global);
int g = menu_selected_global;
std::string value = menu_entries[g][menu_selected[g]];
text(
"menu_selected_global = " + std::to_string(g)),
text(
"menu_selected[0] = " +
std::to_string(menu_selected[0])),
text(
"menu_selected[1] = " +
std::to_string(menu_selected[1])),
text(
"menu_selected[2] = " +
std::to_string(menu_selected[2])),
text(
"Value = " + value),
})) |
flex;
});
auto global = Container::Horizontal({
menu_global,
info,
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(global);
return EXIT_SUCCESS;
}
menu_style
Demo
#include <array>
#include <chrono>
#include <functional>
#include <memory>
#include <string>
#include <vector>
auto screen = ScreenInteractive::TerminalOutput();
std::vector<std::string> entries{
"Monkey", "Dog", "Cat", "Bird", "Elephant", "Cat",
};
std::array<int, 12> selected = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
auto vmenu_1_ =
VMenu1(&entries, &selected[0]);
auto vmenu_2_ =
VMenu2(&entries, &selected[1]);
auto vmenu_3_ =
VMenu3(&entries, &selected[2]);
auto vmenu_4_ =
VMenu4(&entries, &selected[3]);
auto vmenu_5_ =
VMenu5(&entries, &selected[4]);
auto vmenu_6_ =
VMenu6(&entries, &selected[5]);
auto vmenu_7_ =
VMenu7(&entries, &selected[6]);
auto vmenu_8_ =
VMenu8(&entries, &selected[7]);
auto hmenu_1_ =
HMenu1(&entries, &selected[8]);
auto hmenu_2_ =
HMenu2(&entries, &selected[9]);
auto hmenu_3_ =
HMenu3(&entries, &selected[10]);
auto hmenu_4_ =
HMenu4(&entries, &selected[11]);
auto hmenu_5_ =
HMenu5(&entries, &selected[12]);
auto container = Container::Vertical({
Container::Horizontal({
vmenu_1_,
vmenu_2_,
vmenu_3_,
vmenu_4_,
vmenu_5_,
vmenu_6_,
vmenu_7_,
vmenu_8_,
}),
hmenu_1_,
hmenu_2_,
hmenu_3_,
hmenu_4_,
hmenu_5_,
});
auto renderer =
Renderer(container, [&] {
return
vmenu_1_->Render(),
vmenu_2_->Render(),
vmenu_3_->Render(),
vmenu_4_->Render(),
vmenu_5_->Render(),
vmenu_6_->Render(),
vmenu_7_->Render(),
vmenu_8_->Render(),
}),
hmenu_1_->Render(),
hmenu_2_->Render(),
hmenu_3_->Render(),
hmenu_4_->Render(),
hmenu_5_->Render(),
}) | border,
});
});
screen.Loop(renderer);
}
auto option = MenuOption::Vertical();
state.label = (state.active ? "> " : " ") + state.label;
if (state.focused)
if (state.active)
return e;
};
return Menu(entries, selected, option);
}
auto option = MenuOption::Vertical();
state.label += (state.active ? " <" : " ");
if (state.focused)
if (state.active)
return e;
};
return Menu(entries, selected, option);
}
auto option = MenuOption::Vertical();
Element e = state.active ?
text(
"[" + state.label +
"]")
:
text(
" " + state.label +
" ");
if (state.focused)
e = e | bold;
if (state.focused)
e = e |
color(Color::Blue);
if (state.active)
e = e | bold;
return e;
};
return Menu(entries, selected, option);
}
auto option = MenuOption::Vertical();
if (state.active && state.focused) {
}
if (state.active) {
}
if (state.focused) {
}
};
return Menu(entries, selected, option);
}
auto option = MenuOption::Vertical();
auto element =
text(state.label);
if (state.active && state.focused) {
}
if (state.active) {
}
if (state.focused) {
}
return element;
};
return Menu(entries, selected, option);
}
auto option = MenuOption::VerticalAnimated();
option.underline.color_inactive = Color::Default;
option.underline.color_active = Color::Red;
option.underline.SetAnimationFunction(animation::easing::Linear);
return Menu(entries, selected, option);
}
auto option = MenuOption::Vertical();
return Menu(entries, selected, option);
}
auto option = MenuOption::Vertical();
Color::Red, Color::White, std::chrono::milliseconds(500));
return Menu(entries, selected, option);
}
return Menu(entries, selected, MenuOption::Horizontal());
}
return Menu(entries, selected, MenuOption::Toggle());
}
auto option = MenuOption::Toggle();
option.elements_infix = [] {
return text(
" 🮣🮠 "); };
return Menu(entries, selected, option);
}
return Menu(entries, selected, MenuOption::HorizontalAnimated());
}
auto option = MenuOption::HorizontalAnimated();
option.underline.SetAnimation(std::chrono::milliseconds(1500),
animation::easing::ElasticOut);
if (state.active && state.focused)
if (!state.focused && !state.active)
return e;
};
option.underline.color_inactive = Color::Default;
option.underline.color_active = Color::Red;
return Menu(entries, selected, option);
}
void Set(Color inactive, Color active, animation::Duration duration=std::chrono::milliseconds(250), animation::easing::Function function=animation::easing::QuadraticInOut)
A color option that can be animated. @params _inactive The color when the component is inactive....
Element borderDouble(Element)
Draw a double border around the element.
menu_underline_animated_gallery
Demo
#include <chrono>
#include <memory>
#include <string>
#include <vector>
return Renderer([id](bool focused) {
auto t = text("component " + std::to_string(id));
if (focused)
t = t | inverted;
return t;
});
}
return Renderer([t] { return text(t) | borderEmpty; });
}
using namespace std::literals;
std::vector<std::string> tab_values{
"Tab 1", "Tab 2", "Tab 3", "A very very long tab", "탭",
};
int tab_selected = 0;
auto container = Container::Vertical({});
int frame_count = 0;
[&] {
return text(
"Frame count: " + std::to_string(frame_count++)); }));
{
auto option = MenuOption::HorizontalAnimated();
container->Add(
Text(
"This demonstrate the Menu component"));
container->Add(
Menu(&tab_values, &tab_selected, option));
}
{
container->Add(
Text(
"Set underline color to blue"));
auto option = MenuOption::HorizontalAnimated();
option.underline.color_inactive = Color::Blue;
container->Add(
Menu(&tab_values, &tab_selected, option));
}
{
container->Add(
Text(
"Set underline active color to red"));
auto option = MenuOption::HorizontalAnimated();
option.underline.color_active = Color::Red;
container->Add(
Menu(&tab_values, &tab_selected, option));
}
{
container->Add(
Text(
"Set animation duration to 0ms"));
auto option = MenuOption::HorizontalAnimated();
option.underline.SetAnimationDuration(0ms);
container->Add(
Menu(&tab_values, &tab_selected, option));
}
{
container->Add(
Text(
"Set animation easing function to back-out"));
auto option = MenuOption::HorizontalAnimated();
option.underline.SetAnimationFunction(animation::easing::BackOut);
option.underline.SetAnimationDuration(350ms);
container->Add(
Menu(&tab_values, &tab_selected, option));
}
{
container->Add(
Text(
"Add delay to desynchronize animation"));
auto option = MenuOption::HorizontalAnimated();
option.underline.follower_delay = 250ms;
container->Add(
Menu(&tab_values, &tab_selected, option));
}
container->SetActiveChild(container->ChildAt(2));
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(container);
}
modal_dialog
Demo
#include <functional>
#include <memory>
std::function<void()> exit) {
auto component = Container::Vertical({
});
component |= Renderer([&](
Element inner) {
return vbox({
text("Main component"),
separator(),
inner,
})
| size(WIDTH, GREATER_THAN, 15)
| size(HEIGHT, GREATER_THAN, 15)
| border
| center;
});
return component;
}
std::function<void()> hide_modal) {
auto component = Container::Vertical({
});
text(
"Modal component "),
inner,
})
|
size(WIDTH, GREATER_THAN, 30)
});
return component;
}
int main(
int argc,
const char* argv[]) {
auto screen = ScreenInteractive::TerminalOutput();
bool modal_shown = false;
auto show_modal = [&] { modal_shown = true; };
auto hide_modal = [&] { modal_shown = false; };
auto exit = screen.ExitLoopClosure();
auto do_nothing = [&] {};
main_component |=
Modal(modal_component, &modal_shown);
screen.Loop(main_component);
return 0;
}
Component Modal(Component main, Component modal, const bool *show_modal)
Component ModalComponent(std::function< void()> do_nothing, std::function< void()> hide_modal)
Component MainComponent(std::function< void()> show_modal, std::function< void()> exit)
modal_dialog_custom
Demo
#include <memory>
#include <string>
#include <vector>
auto screen = ScreenInteractive::TerminalOutput();
int depth = 0;
std::string rating = "3/5 stars";
auto button_rate_ftxui = Button("Rate FTXUI", [&] { depth = 1; });
auto button_quit = Button("Quit", screen.ExitLoopClosure());
auto depth_0_container = Container::Horizontal({
button_rate_ftxui,
button_quit,
});
auto depth_0_renderer = Renderer(depth_0_container, [&] {
return vbox({
text("Modal dialog example"),
separator(),
text("☆☆☆ FTXUI:" + rating + " ☆☆☆") | bold,
filler(),
hbox({
button_rate_ftxui->Render(),
filler(),
button_quit->Render(),
}),
}) |
});
std::vector<std::string> rating_labels = {
"1/5 stars", "2/5 stars", "3/5 stars", "4/5 stars", "5/5 stars",
};
auto on_rating = [&](std::string new_rating) {
rating = new_rating;
depth = 0;
};
auto depth_1_container = Container::Horizontal({
Button(&rating_labels[0], [&] { on_rating(rating_labels[0]); }),
Button(&rating_labels[1], [&] { on_rating(rating_labels[1]); }),
Button(&rating_labels[2], [&] { on_rating(rating_labels[2]); }),
Button(&rating_labels[3], [&] { on_rating(rating_labels[3]); }),
Button(&rating_labels[4], [&] { on_rating(rating_labels[4]); }),
});
auto depth_1_renderer =
Renderer(depth_1_container, [&] {
text(
"Do you like FTXUI?"),
hbox(depth_1_container->Render()),
}) |
border;
});
auto main_container = Container::Tab(
{
depth_0_renderer,
depth_1_renderer,
},
&depth);
auto main_renderer =
Renderer(main_container, [&] {
Element document = depth_0_renderer->Render();
if (depth == 1) {
document,
});
}
return document;
});
screen.Loop(main_renderer);
return 0;
}
Element clear_under(Element element)
Before drawing |child|, clear the pixels below. This is useful in.
Element dbox(Elements)
Stack several element on top of each other.
nested_screen
Demo
#include <memory>
#include <string>
void Nested(std::string path) {
auto screen = ScreenInteractive::FitComponent();
auto back_button = Button("Back", screen.ExitLoopClosure());
auto goto_1 = Button(
"Goto /1", [path] {
Nested(path +
"/1"); });
auto goto_2 = Button(
"Goto /2", [path] {
Nested(path +
"/2"); });
auto goto_3 = Button(
"Goto /3", [path] {
Nested(path +
"/3"); });
auto layout = Container::Vertical({
back_button,
goto_1,
goto_2,
goto_3,
});
back_button->Render(),
goto_1->Render(),
goto_2->Render(),
goto_3->Render(),
}) |
border;
});
screen.Loop(renderer);
}
auto screen = ScreenInteractive::FitComponent();
auto button_quit =
Button(
"Quit", screen.ExitLoopClosure());
screen.Loop(Container::Vertical({
button_quit,
button_nested,
}));
return 0;
}
void Nested(std::string path)
print_key_press
Demo
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <string>
#include <utility>
#include <vector>
std::string codes;
for (
auto& it : event.
input()) {
codes += " " + std::to_string((unsigned int)it);
}
return codes;
}
auto screen = ScreenInteractive::TerminalOutput();
std::vector<Event> keys;
auto left_column = Renderer([&] {
text("Codes"),
separator(),
};
for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i) {
children.push_back(
text(
Code(keys[i])));
}
});
};
for (size_t i = std::max(0, (int)keys.size() - 20); i < keys.size(); ++i) {
children.push_back(
text(keys[i].DebugString()));
}
});
int split_size = 40;
keys.push_back(event);
return false;
});
screen.Loop(component);
}
std::string Code(Event event)
const std::string & input() const
radiobox
Demo
#include <string>
#include <vector>
std::vector<std::string> radiobox_list = {
"Use gcc",
"Use clang",
"Use emscripten",
"Use tcc",
};
int selected = 0;
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(Radiobox(&radiobox_list, &selected));
return 0;
}
radiobox_in_frame
Demo
#include <memory>
#include <string>
#include <vector>
std::vector<std::string> entries;
int selected = 0;
for (int i = 0; i < 30; ++i)
entries.push_back("RadioBox " + std::to_string(i));
auto radiobox = Radiobox(&entries, &selected);
auto renderer = Renderer(radiobox, [&] {
return radiobox->Render() | vscroll_indicator | frame |
size(HEIGHT, LESS_THAN, 10) | border;
});
auto screen = ScreenInteractive::FitComponent();
screen.Loop(renderer);
return 0;
}
renderer
Demo
#include <memory>
auto screen = ScreenInteractive::FitComponent();
auto renderer_focusable = Renderer([](bool focused) {
if (focused)
return text("FOCUSABLE RENDERER()") | center | bold | border;
else
return text(" Focusable renderer() ") | center | border;
});
auto renderer_non_focusable = Renderer([&] {
return text("~~~~~ Non Focusable renderer() ~~~~~");
});
auto button = Button("Wrapped quit button", screen.ExitLoopClosure());
auto renderer_wrap = Renderer(button, [&] {
if (button->Focused())
return button->Render() | bold | color(Color::Red);
else
return button->Render();
});
screen.Loop(Container::Vertical({
renderer_focusable,
renderer_non_focusable,
renderer_wrap,
}));
}
resizable_split
Demo
#include <memory>
auto screen = ScreenInteractive::Fullscreen();
auto middle = Renderer([] { return text("middle") | center; });
auto left = Renderer([] {
return text(
"Left") | center; });
auto right = Renderer([] {
return text(
"right") | center; });
int left_size = 20;
int right_size = 20;
int top_size = 10;
int bottom_size = 10;
auto container = middle;
auto renderer =
screen.Loop(renderer);
}
Component ResizableSplitTop(Component main, Component back, int *main_size)
An vertical split in between two components, configurable using the mouse.
scrollbar
Demo
private:
float scroll_x = 0.1;
float scroll_y = 0.1;
public:
Impl() {
auto content = Renderer([=] {
const std::string lorem =
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed "
"do eiusmod tempor incididunt ut labore et dolore magna "
"aliqua. Ut enim ad minim veniam, quis nostrud exercitation "
"ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis "
"aute irure dolor in reprehenderit in voluptate velit esse "
"cillum dolore eu fugiat nulla pariatur. Excepteur sint "
"occaecat cupidatat non proident, sunt in culpa qui officia "
"deserunt mollit anim id est laborum.";
return vbox({
text(lorem.substr(0, -1)), text(lorem.substr(5, -1)), text(""),
text(lorem.substr(10, -1)), text(lorem.substr(15, -1)), text(""),
text(lorem.substr(20, -1)), text(lorem.substr(25, -1)), text(""),
text(lorem.substr(30, -1)), text(lorem.substr(35, -1)), text(""),
text(lorem.substr(40, -1)), text(lorem.substr(45, -1)), text(""),
text(lorem.substr(50, -1)), text(lorem.substr(55, -1)), text(""),
text(lorem.substr(60, -1)), text(lorem.substr(65, -1)), text(""),
text(lorem.substr(70, -1)), text(lorem.substr(75, -1)), text(""),
text(lorem.substr(80, -1)), text(lorem.substr(85, -1)), text(""),
text(lorem.substr(90, -1)), text(lorem.substr(95, -1)), text(""),
text(lorem.substr(100, -1)), text(lorem.substr(105, -1)), text(""),
text(lorem.substr(110, -1)), text(lorem.substr(115, -1)), text(""),
text(lorem.substr(120, -1)), text(lorem.substr(125, -1)), text(""),
text(lorem.substr(130, -1)), text(lorem.substr(135, -1)), text(""),
text(lorem.substr(140, -1)),
});
});
auto scrollable_content = Renderer(content, [&, content] {
return content->Render() | focusPositionRelative(scroll_x, scroll_y) |
frame | flex;
});
option_x.
value = &scroll_x;
option_x.min = 0.f;
option_x.max = 1.f;
option_x.increment = 0.1f;
option_x.direction = Direction::Right;
option_x.color_active = Color::Blue;
option_x.color_inactive = Color::BlueLight;
auto scrollbar_x =
Slider(option_x);
option_y.
value = &scroll_y;
auto scrollbar_y =
Slider(option_y);
Add(Container::Vertical({
Container::Horizontal({
scrollable_content,
scrollbar_y,
}) | flex,
Container::Horizontal({
scrollbar_x,
}),
}));
}
};
return Make<Impl>();
}
.title = "First window",
.width = 80,
.height = 30,
});
.title = "My window",
.left = 40,
.top = 20,
.width = 80,
.height = 30,
});
auto window_container = Container::Stacked({
window_1,
window_2,
});
auto screen = ScreenInteractive::Fullscreen();
screen.Loop(window_container);
return EXIT_SUCCESS;
}
It implement rendering itself as ftxui::Element. It implement keyboard navigation by responding to ft...
selection
Demo
#include <string>
return vbox({
text("FTXUI: A powerful library for building user interfaces."),
text("Enjoy a rich set of components and a declarative style."),
text("Create beautiful and responsive UIs with minimal effort."),
text("Join the community and experience the power of FTXUI."),
});
}
auto screen = ScreenInteractive::TerminalOutput();
auto quit =
Button("Quit", screen.ExitLoopClosure(), ButtonOption::Animated());
int selection_change_counter = 0;
std::string selection_content = "";
screen.SelectionChange([&] {
selection_change_counter++;
selection_content = screen.GetSelection();
});
text(
"Select changed: " + std::to_string(selection_change_counter) +
" times"),
text(
"Currently selected: "),
})),
})),
}),
}),
}),
})),
quit->Render(),
});
});
screen.Loop(renderer);
}
Decorator selectionStyle(std::function< void(Pixel &)> style)
Set the style of an element when selected.
Decorator selectionBackgroundColor(Color foreground)
Set the background color of an element when selected. Note that the style is applied on top of the ex...
Decorator selectionColor(Color foreground)
Set the color of an element when selected.
Element selectionStyleReset(Element)
Reset the selection style of an element.
slider
Demo
auto screen = ScreenInteractive::TerminalOutput();
int value = 50;
auto slider = Slider("Value:", &value, 0, 100, 1);
screen.Loop(slider);
}
slider_direction
Demo
#include <array>
#include <cmath>
#include <memory>
auto screen = ScreenInteractive::TerminalOutput();
std::array<int, 30> values;
for (size_t i = 0; i < values.size(); ++i) {
values[i] = 50 + 20 * std::sin(i * 0.3);
}
auto layout_horizontal = Container::Horizontal({});
for (auto& value : values) {
layout_horizontal->Add(Slider<int>(option));
}
layout_horizontal |=
size(HEIGHT, GREATER_THAN, 20);
screen.Loop(layout_horizontal);
}
slider_rgb
Demo
#include <memory>
#include <string>
return text("") | size(WIDTH, GREATER_THAN, 14) |
size(HEIGHT, GREATER_THAN, 7) | bgcolor(Color::RGB(red, green, blue));
}
return text("RGB = (" +
std::to_string(red) + "," +
std::to_string(green) + "," +
std::to_string(blue) + ")"
);
}
int red = 128;
int green = 25;
int blue = 100;
auto slider_red = Slider("Red :", &red, 0, 255, 1);
auto slider_green = Slider("Green:", &green, 0, 255, 1);
auto slider_blue = Slider("Blue :", &blue, 0, 255, 1);
auto container = Container::Vertical({
slider_red,
slider_green,
slider_blue,
});
auto renderer =
Renderer(container, [&] {
slider_red->Render(),
slider_green->Render(),
slider_blue->Render(),
}) | xflex,
}) |
border |
size(WIDTH, LESS_THAN, 80);
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(renderer);
}
Element ColorTile(int red, int green, int blue)
Element ColorString(int red, int green, int blue)
tab_horizontal
Demo
#include <memory>
#include <string>
#include <vector>
std::vector<std::string> tab_values{
"tab_1",
"tab_2",
"tab_3",
};
int tab_selected = 0;
auto tab_toggle = Toggle(&tab_values, &tab_selected);
std::vector<std::string> tab_1_entries{
"Forest",
"Water",
"I don't know",
};
int tab_1_selected = 0;
std::vector<std::string> tab_2_entries{
"Hello",
"Hi",
"Hay",
};
int tab_2_selected = 0;
std::vector<std::string> tab_3_entries{
"Table",
"Nothing",
"Is",
"Empty",
};
int tab_3_selected = 0;
auto tab_container = Container::Tab(
{
Radiobox(&tab_1_entries, &tab_1_selected),
Radiobox(&tab_2_entries, &tab_2_selected),
Radiobox(&tab_3_entries, &tab_3_selected),
},
&tab_selected);
auto container = Container::Vertical({
tab_toggle,
tab_container,
});
auto renderer =
Renderer(container, [&] {
tab_toggle->Render(),
tab_container->Render(),
}) |
border;
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(renderer);
}
tab_vertical
Demo
#include <memory>
#include <string>
#include <vector>
std::vector<std::string> tab_values{
"tab_1",
"tab_2",
"tab_3",
};
int tab_selected = 0;
auto tab_menu = Menu(&tab_values, &tab_selected);
std::vector<std::string> tab_1_entries{
"Forest",
"Water",
"I don't know",
};
int tab_1_selected = 0;
std::vector<std::string> tab_2_entries{
"Hello",
"Hi",
"Hay",
};
int tab_2_selected = 0;
std::vector<std::string> tab_3_entries{
"Table",
"Nothing",
"Is",
"Empty",
};
int tab_3_selected = 0;
auto tab_container = Container::Tab(
{
Radiobox(&tab_1_entries, &tab_1_selected),
Radiobox(&tab_2_entries, &tab_2_selected),
Radiobox(&tab_3_entries, &tab_3_selected),
},
&tab_selected);
auto container = Container::Horizontal({
tab_menu,
tab_container,
});
auto renderer =
Renderer(container, [&] {
tab_menu->Render(),
tab_container->Render(),
}) |
border;
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(renderer);
}
textarea
Demo
#include <memory>
#include <string>
std::string content_1;
std::string content_2;
auto textarea_1 = Input(&content_1);
auto textarea_2 = Input(&content_2);
int size = 50;
auto layout = ResizableSplitLeft(textarea_1, textarea_2, &size);
auto component = Renderer(layout, [&] {
return vbox({
text("Input:"),
separator(),
layout->Render() | flex,
}) |
border;
});
auto screen = ScreenInteractive::Fullscreen();
screen.Loop(component);
}
toggle
Demo
#include <memory>
#include <string>
#include <vector>
std::vector<std::string> toggle_1_entries = {
"On",
"Off",
};
std::vector<std::string> toggle_2_entries = {
"Enabled",
"Disabled",
};
std::vector<std::string> toggle_3_entries = {
"10€",
"0€",
};
std::vector<std::string> toggle_4_entries = {
"Nothing",
"One element",
"Several elements",
};
int toggle_1_selected = 0;
int toggle_2_selected = 0;
int toggle_3_selected = 0;
int toggle_4_selected = 0;
auto container = Container::Vertical({
toggle_1,
toggle_2,
toggle_3,
toggle_4,
});
auto renderer =
Renderer(container, [&] {
text(
"Choose your options:"),
hbox(
text(
" * Poweroff on startup : "), toggle_1->Render()),
hbox(
text(
" * Out of process : "), toggle_2->Render()),
hbox(
text(
" * Price of the information : "), toggle_3->Render()),
hbox(
text(
" * Number of elements : "), toggle_4->Render()),
});
});
auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(renderer);
}
window
Demo
private:
bool checked[3] = {false, false, false};
float slider = 50;
public:
Impl() {
Add(Container::Vertical({
Checkbox("Check me", &checked[0]),
Checkbox("Check me", &checked[1]),
Checkbox("Check me", &checked[2]),
Slider("Slider", &slider, 0.f, 100.f),
}));
}
};
return Make<Impl>();
}
int window_1_left = 20;
int window_1_top = 10;
int window_1_width = 40;
int window_1_height = 20;
.title = "First window",
.left = &window_1_left,
.top = &window_1_top,
.width = &window_1_width,
.height = &window_1_height,
});
.title = "My window",
.left = 40,
.top = 20,
});
.title = "My window",
.left = 60,
.top = 30,
});
});
auto window_container = Container::Stacked({
window_1,
window_2,
window_3,
window_4,
window_5,
});
return text(
"window_1: " +
std::to_string(window_1_width) + "x" +
std::to_string(window_1_height) + " + " +
std::to_string(window_1_left) + "," +
std::to_string(window_1_top));
});
auto layout = Container::Vertical({
display_win_1,
window_container,
});
auto screen = ScreenInteractive::Fullscreen();
screen.Loop(layout);
return EXIT_SUCCESS;
}
with_restored_io
Demo
#include <cstdlib>
#include <iostream>
#include <memory>
#include <string>
auto screen = ScreenInteractive::Fullscreen();
auto btn_run = Button("Execute with restored IO", screen.WithRestoredIO([] {
std::cout << "This is a child program using stdin/stdout." << std::endl;
for (int i = 0; i < 10; ++i) {
std::cout << "Please enter 10 strings (" << i << "/10)" << std::flush;
std::string input;
std::getline(std::cin, input);
}
}));
auto btn_quit = Button("Quit", screen.ExitLoopClosure());
auto layout = Container::Horizontal({
btn_run,
btn_quit,
});
auto renderer = Renderer(layout, [&] {
auto explanation = paragraph(
"After clicking this button, the ScreenInteractive will be "
"suspended and access to stdin/stdout will temporarilly be "
"restore for running a function.");
auto element = vbox({
explanation | borderEmpty,
hbox({
btn_run->Render(),
filler(),
btn_quit->Render(),
}),
});
return element;
});
screen.Loop(renderer);
return EXIT_SUCCESS;
}