Implement flexbox (#277)

This implement the flexbox elements, following the HTML one.

Built from them, there is also the following elements:
- `paragraph`
- `paragraphAlignLeft`
- `paragraphAlignRight`
- `paragraphAlignCenter`
- `paragraphAlignJustify`

This is a breaking change.
This commit is contained in:
Arthur Sonzogni 2021-12-11 17:58:25 +01:00 committed by GitHub
parent f7c6bf91a7
commit 602392c43d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
70 changed files with 2163 additions and 300 deletions

View File

@ -4,8 +4,24 @@ Changelog
unreleased (development) unreleased (development)
------------------------ ------------------------
# Component: ### Features:
- Bugfix: Input shouldn't take focus when hovered by the mouse. - Support `flexbox` dom elements. This is build symmetrically to the HTML one.
All the following attributes are supported: direction, wrap, justify-content,
align-items, align-content, gap
- Add the dom elements helper based on `flexbox`:
- `paragraph`
- `paragraphAlignLeft`
- `paragraphAlignCenter`
- `paragraphAlignRight`
- `paragraphAlignJustify`
- Add the helper elements based on `flexbox`: `hflow()`, `vflow()`.
### Breaking changes:
- The behavior of `paragraph` has been modified. It now returns en Element,
instead of a list of elements.
### Bug
- Input shouldn't take focus when hovered by the mouse.
0.11.1 0.11.1
------ ------

View File

@ -38,6 +38,7 @@ add_library(screen
add_library(dom add_library(dom
include/ftxui/dom/elements.hpp include/ftxui/dom/elements.hpp
include/ftxui/dom/flexbox_config.hpp
include/ftxui/dom/node.hpp include/ftxui/dom/node.hpp
include/ftxui/dom/requirement.hpp include/ftxui/dom/requirement.hpp
include/ftxui/dom/take_any_args.hpp include/ftxui/dom/take_any_args.hpp
@ -52,12 +53,15 @@ add_library(dom
src/ftxui/dom/dbox.cpp src/ftxui/dom/dbox.cpp
src/ftxui/dom/dim.cpp src/ftxui/dom/dim.cpp
src/ftxui/dom/flex.cpp src/ftxui/dom/flex.cpp
src/ftxui/dom/flexbox.cpp
src/ftxui/dom/flexbox_config.cpp
src/ftxui/dom/flexbox_helper.cpp
src/ftxui/dom/flexbox_helper.hpp
src/ftxui/dom/frame.cpp src/ftxui/dom/frame.cpp
src/ftxui/dom/gauge.cpp src/ftxui/dom/gauge.cpp
src/ftxui/dom/graph.cpp src/ftxui/dom/graph.cpp
src/ftxui/dom/gridbox.cpp src/ftxui/dom/gridbox.cpp
src/ftxui/dom/hbox.cpp src/ftxui/dom/hbox.cpp
src/ftxui/dom/hflow.cpp
src/ftxui/dom/inverted.cpp src/ftxui/dom/inverted.cpp
src/ftxui/dom/node.cpp src/ftxui/dom/node.cpp
src/ftxui/dom/node_decorator.cpp src/ftxui/dom/node_decorator.cpp

View File

@ -19,10 +19,12 @@ add_executable(tests
src/ftxui/component/screen_interactive_test.cpp src/ftxui/component/screen_interactive_test.cpp
src/ftxui/component/terminal_input_parser_test.cpp src/ftxui/component/terminal_input_parser_test.cpp
src/ftxui/component/toggle_test.cpp src/ftxui/component/toggle_test.cpp
src/ftxui/dom/flexbox_helper_test.cpp
src/ftxui/dom/flexbox_test.cpp
src/ftxui/dom/gauge_test.cpp src/ftxui/dom/gauge_test.cpp
src/ftxui/dom/table_test.cpp
src/ftxui/dom/gridbox_test.cpp src/ftxui/dom/gridbox_test.cpp
src/ftxui/dom/hbox_test.cpp src/ftxui/dom/hbox_test.cpp
src/ftxui/dom/table_test.cpp
src/ftxui/dom/text_test.cpp src/ftxui/dom/text_test.cpp
src/ftxui/dom/vbox_test.cpp src/ftxui/dom/vbox_test.cpp
src/ftxui/screen/string_test.cpp src/ftxui/screen/string_test.cpp

View File

@ -5,6 +5,7 @@ example(checkbox)
example(checkbox_in_frame) example(checkbox_in_frame)
example(composition) example(composition)
example(dropdown) example(dropdown)
example(flexbox)
example(gallery) example(gallery)
example(homescreen) example(homescreen)
example(input) example(input)

View File

@ -1,6 +1,12 @@
#include <memory> // for allocator, __shared_ptr_access
#include <string> // for string, basic_string, operator+, to_string
#include <vector> // for vector
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Input, Renderer, Vertical
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" #include "ftxui/dom/elements.hpp" // for operator|, Element, size, border, frame, vscroll_indicator, HEIGHT, LESS_THAN
#include "ftxui/component/component.hpp"
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;
@ -19,3 +25,7 @@ int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::TerminalOutput(); auto screen = ScreenInteractive::TerminalOutput();
screen.Loop(renderer); screen.Loop(renderer);
} }
// Copyright 2021 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -0,0 +1,192 @@
#include <stddef.h> // for size_t
#include <memory> // for shared_ptr, __shared_ptr_access, allocator
#include <string> // for string, basic_string, to_string, operator+, char_traits
#include <vector> // for vector
#include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Radiobox, Vertical, Checkbox, Horizontal, Renderer, ResizableSplitBottom, ResizableSplitRight
#include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/screen_interactive.hpp" // for ScreenInteractive
#include "ftxui/dom/elements.hpp" // for text, window, operator|, vbox, hbox, Element, flexbox, bgcolor, filler, flex, size, border, hcenter, color, EQUAL, bold, dim, notflex, xflex_grow, yflex_grow, HEIGHT, WIDTH
#include "ftxui/dom/flexbox_config.hpp" // for FlexboxConfig, FlexboxConfig::AlignContent, FlexboxConfig::JustifyContent, FlexboxConfig::AlignContent::Center, FlexboxConfig::AlignItems, FlexboxConfig::Direction, FlexboxConfig::JustifyContent::Center, FlexboxConfig::Wrap
#include "ftxui/screen/color.hpp" // for Color, Color::Black
using namespace ftxui;
int main(int argc, const char* argv[]) {
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)) |
color(Color::Black);
if (element_xflex_grow)
element = element | xflex_grow;
if (element_yflex_grow)
element = element | yflex_grow;
return element;
};
auto content_renderer = Renderer([&] {
FlexboxConfig config;
config.direction = static_cast<FlexboxConfig::Direction>(direction_index);
config.wrap = static_cast<FlexboxConfig::Wrap>(wrap_index);
config.justify_content =
static_cast<FlexboxConfig::JustifyContent>(justify_content_index);
config.align_items =
static_cast<FlexboxConfig::AlignItems>(align_items_index);
config.align_content =
static_cast<FlexboxConfig::AlignContent>(align_content_index);
auto group = flexbox(
{
make_box(8, 4, 0),
make_box(9, 6, 1),
make_box(11, 6, 2),
make_box(10, 4, 3),
make_box(13, 7, 4),
make_box(12, 4, 5),
make_box(12, 5, 6),
make_box(10, 4, 7),
make_box(12, 4, 8),
make_box(10, 5, 9),
},
config);
group = group | bgcolor(Color::Black);
group = group | notflex;
if (!group_xflex_grow)
group = hbox(group, filler());
if (!group_yflex_grow)
group = vbox(group, filler());
group = group | flex;
return group;
});
auto center = FlexboxConfig()
.Set(FlexboxConfig::JustifyContent::Center)
.Set(FlexboxConfig::AlignContent::Center);
int space_right = 10;
int space_bottom = 1;
content_renderer = ResizableSplitRight(
Renderer([&] { return flexbox({text("resizable")}, center); }),
content_renderer, &space_right);
content_renderer = ResizableSplitBottom(
Renderer([&] { return flexbox({text("resizable")}, center); }),
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, [&] {
return vbox({
vbox({hbox({
window(text("FlexboxConfig::Direction"),
radiobox_direction->Render()),
window(text("FlexboxConfig::Wrap"), radiobox_wrap->Render()),
window(text("Misc:"),
vbox({
checkbox_element_xflex_grow->Render(),
checkbox_element_yflex_grow->Render(),
checkbox_group_xflex_grow->Render(),
checkbox_group_yflex_grow->Render(),
})),
}),
hbox({
window(text("FlexboxConfig::JustifyContent"),
radiobox_justify_content->Render()),
window(text("FlexboxConfig::AlignItems"),
radiobox_align_items->Render()),
window(text("FlexboxConfig::AlignContent"),
radiobox_align_content->Render()),
})}),
content_renderer->Render() | flex | border,
});
});
screen.Loop(main_renderer);
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.

View File

@ -1,27 +1,33 @@
#include <stddef.h> // for size_t
#include <array> // for array #include <array> // for array
#include <chrono> // for operator""s, chrono_literals #include <chrono> // for operator""s, chrono_literals
#include <cmath> // for sin #include <cmath> // for sin
#include <functional> // for ref, reference_wrapper, function #include <functional> // for ref, reference_wrapper, function
#include <memory> // for allocator, shared_ptr, __shared_ptr_access #include <memory> // for allocator, shared_ptr, __shared_ptr_access
#include <string> // for string, basic_string, operator+, char_traits, to_string #include <string> // for string, basic_string, operator+, to_string, char_traits
#include <thread> // for sleep_for, thread #include <thread> // for sleep_for, thread
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/component/captured_mouse.hpp" // for ftxui #include "ftxui/component/captured_mouse.hpp" // for ftxui
#include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Menu, Radiobox, Tab, Toggle #include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Input, Menu, Radiobox, ResizableSplitLeft, Tab, Toggle
#include "ftxui/component/component_base.hpp" // for ComponentBase #include "ftxui/component/component_base.hpp" // for ComponentBase
#include "ftxui/component/component_options.hpp" // for InputOption #include "ftxui/component/component_options.hpp" // for InputOption
#include "ftxui/component/event.hpp" // for Event, Event::Custom #include "ftxui/component/event.hpp" // for Event, Event::Custom
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for operator|, color, bgcolor, filler, Element, size, vbox, flex, hbox, graph, separator, EQUAL, WIDTH, hcenter, bold, border, window, HEIGHT, Elements, hflow, flex_grow, frame, gauge, LESS_THAN, spinner, dim, GREATER_THAN #include "ftxui/dom/elements.hpp" // for text, operator|, color, bgcolor, filler, Element, size, vbox, flex, hbox, separator, graph, EQUAL, paragraph, hcenter, WIDTH, bold, window, border, vscroll_indicator, Elements, HEIGHT, hflow, frame, flex_grow, flexbox, gauge, paragraphAlignCenter, paragraphAlignJustify, paragraphAlignLeft, paragraphAlignRight, dim, spinner, Decorator, LESS_THAN, center, yflex, GREATER_THAN
#include "ftxui/screen/color.hpp" // for Color, Color::BlueLight, Color::RedLight, Color::Black, Color::Blue, Color::Cyan, Color::CyanLight, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::White, Color::Yellow, Color::YellowLight, Color::Default #include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::BlueLight, Color::RedLight, Color::Black, Color::Cyan, Color::CyanLight, Color::GrayDark, Color::GrayLight, Color::Green, Color::GreenLight, Color::Magenta, Color::MagentaLight, Color::Red, Color::White, Color::Yellow, Color::YellowLight, Color::Default
#include "ftxui/screen/terminal.hpp" // for Size, Dimensions
using namespace ftxui; using namespace ftxui;
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
auto screen = ScreenInteractive::Fullscreen(); auto screen = ScreenInteractive::Fullscreen();
// ---------------------------------------------------------------------------
// HTOP
// ---------------------------------------------------------------------------
int shift = 0; int shift = 0;
auto my_graph = [&shift](int width, int height) { auto my_graph = [&shift](int width, int height) {
@ -92,6 +98,10 @@ int main(int argc, const char* argv[]) {
flex | border; flex | border;
}); });
// ---------------------------------------------------------------------------
// Compiler
// ---------------------------------------------------------------------------
const std::vector<std::string> compiler_entries = { const std::vector<std::string> compiler_entries = {
"gcc", "gcc",
"clang", "clang",
@ -248,6 +258,9 @@ int main(int argc, const char* argv[]) {
flex_grow | border; flex_grow | border;
}); });
// ---------------------------------------------------------------------------
// Spiner
// ---------------------------------------------------------------------------
auto spinner_tab_renderer = Renderer([&] { auto spinner_tab_renderer = Renderer([&] {
Elements entries; Elements entries;
for (int i = 0; i < 22; ++i) { for (int i = 0; i < 22; ++i) {
@ -257,6 +270,9 @@ int main(int argc, const char* argv[]) {
return hflow(std::move(entries)) | border; return hflow(std::move(entries)) | border;
}); });
// ---------------------------------------------------------------------------
// Colors
// ---------------------------------------------------------------------------
auto color_tab_renderer = Renderer([] { auto color_tab_renderer = Renderer([] {
return hbox({ return hbox({
vbox({ vbox({
@ -301,6 +317,9 @@ int main(int argc, const char* argv[]) {
hcenter | border; hcenter | border;
}); });
// ---------------------------------------------------------------------------
// Gauges
// ---------------------------------------------------------------------------
auto render_gauge = [&shift](int delta) { auto render_gauge = [&shift](int delta) {
float progress = (shift + delta) % 1000 / 1000.f; float progress = (shift + delta) % 1000 / 1000.f;
return hbox({ return hbox({
@ -333,9 +352,84 @@ int main(int argc, const char* argv[]) {
border; border;
}); });
// ---------------------------------------------------------------------------
// Paragraph
// ---------------------------------------------------------------------------
auto make_box = [](size_t dimx, size_t dimy) {
std::string title = std::to_string(dimx) + "x" + std::to_string(dimy);
return window(text(title) | hcenter | bold,
text("content") | hcenter | dim) |
size(WIDTH, EQUAL, dimx) | size(HEIGHT, EQUAL, dimy);
};
auto paragraph_renderer_left = Renderer([&] {
auto title_style = bold | bgcolor(Color::Blue) | color(Color::Black);
std::string str =
"Lorem Ipsum is simply dummy text of the printing and typesetting "
"industry. Lorem 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.";
return vbox({
// [ Left ]
text("Align left:") | title_style,
paragraphAlignLeft(str),
// [ Center ]
text("Align center:") | title_style,
paragraphAlignCenter(str),
// [ Right ]
text("Align right:") | title_style,
paragraphAlignRight(str),
// [ Justify]
text("Align justify:") | title_style,
paragraphAlignJustify(str),
// [ Side by side ]
text("Side by side:") | title_style,
hbox({
paragraph(str),
separator() | color(Color::Blue),
paragraph(str),
}),
// [ Misc ]
text("Elements with different size:") | title_style,
flexbox({
make_box(10, 5),
make_box(9, 4),
make_box(8, 4),
make_box(6, 3),
make_box(10, 5),
make_box(9, 4),
make_box(8, 4),
make_box(6, 3),
make_box(10, 5),
make_box(9, 4),
make_box(8, 4),
make_box(6, 3),
}),
}) |
// vscroll_indicator | yflex;
yflex | vscroll_indicator;
});
auto paragraph_renderer_right = Renderer([] {
return paragraph("<--- This vertical bar is resizable using the mouse") |
center;
});
int paragraph_renderer_split_position = Terminal::Size().dimx / 2;
auto paragraph_renderer_group =
ResizableSplitLeft(paragraph_renderer_left, paragraph_renderer_right,
&paragraph_renderer_split_position);
auto paragraph_renderer_group_renderer =
Renderer(paragraph_renderer_group,
[&] { return paragraph_renderer_group->Render() | border; });
// ---------------------------------------------------------------------------
// Tabs
// ---------------------------------------------------------------------------
int tab_index = 0; int tab_index = 0;
std::vector<std::string> tab_entries = { std::vector<std::string> tab_entries = {
"htop", "color", "spinner", "gauge", "compiler", "htop", "color", "spinner", "gauge", "compiler", "paragraph",
}; };
auto tab_selection = Toggle(&tab_entries, &tab_index); auto tab_selection = Toggle(&tab_entries, &tab_index);
auto tab_content = Container::Tab( auto tab_content = Container::Tab(
@ -345,6 +439,7 @@ int main(int argc, const char* argv[]) {
spinner_tab_renderer, spinner_tab_renderer,
gauge_component, gauge_component,
compiler_renderer, compiler_renderer,
paragraph_renderer_group_renderer,
}, },
&tab_index); &tab_index);

View File

@ -11,6 +11,7 @@ example(gauge)
example(graph) example(graph)
example(gridbox) example(gridbox)
example(hflow) example(hflow)
example(vflow)
example(html_like) example(html_like)
example(package_manager) example(package_manager)
example(paragraph) example(paragraph)

View File

@ -2,8 +2,8 @@
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,10 +1,10 @@
#include <ftxui/dom/elements.hpp> // for text, operator|, vbox, border, Element, Fit, hbox #include <ftxui/dom/elements.hpp> // for operator|, text, Element, Fit, borderDouble, borderHeavy, borderLight, borderRounded, vbox
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Screen
#include <iostream> #include <iostream> // for endl, cout, ostream
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -4,8 +4,8 @@
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector, allocator #include <vector> // for vector, allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color, Color::Palette256 #include "ftxui/screen/color.hpp" // for Color, Color::Palette256
using namespace ftxui; using namespace ftxui;

View File

@ -3,8 +3,8 @@
#include <memory> // for allocator #include <memory> // for allocator
#include <utility> // for move #include <utility> // for move
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color #include "ftxui/screen/color.hpp" // for Color
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {

View File

@ -3,8 +3,8 @@
#include <memory> // for allocator #include <memory> // for allocator
#include <utility> // for move #include <utility> // for move
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color #include "ftxui/screen/color.hpp" // for Color
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {

View File

@ -2,8 +2,8 @@
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -5,8 +5,8 @@
#include <string> // for allocator, operator+, char_traits, operator<<, string, to_string, basic_string #include <string> // for allocator, operator+, char_traits, operator<<, string, to_string, basic_string
#include <thread> // for sleep_for #include <thread> // for sleep_for
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,16 +1,16 @@
#include <chrono> #include <chrono> // for operator""s, chrono_literals
#include <cmath> #include <cmath> // for sin
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, graph, separator, color, Element, vbox, flex, inverted, Fit, hbox, size, border, GREATER_THAN, HEIGHT
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <functional> #include <functional> // for ref, reference_wrapper
#include <iostream> #include <iostream> // for cout, ostream
#include <string> #include <string> // for operator<<, string
#include <thread> #include <thread> // for sleep_for
#include <vector> #include <vector> // for vector
#include "ftxui/dom/node.hpp" #include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/color.hpp" #include "ftxui/screen/color.hpp" // for Color, Color::BlueLight, Color::RedLight, Color::YellowLight
class Graph { class Graph {
public: public:

View File

@ -1,10 +1,10 @@
#include <stdio.h> // for getchar #include <stdio.h> // for getchar
#include <ftxui/dom/elements.hpp> // for filler, text, hbox, vbox #include <ftxui/dom/elements.hpp> // for Elements, gridbox, Fit, operator|, text, border, Element
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Screen
#include <memory> // for allocator #include <memory> // for allocator, shared_ptr
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -1,11 +1,12 @@
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <stdio.h> // for getchar
#include <ftxui/dom/elements.hpp> // for operator|, size, Element, text, hcenter, Decorator, Fit, WIDTH, hflow, window, EQUAL, GREATER_THAN, HEIGHT, bold, border, dim, LESS_THAN #include <ftxui/dom/elements.hpp> // for operator|, size, Element, text, hcenter, Decorator, Fit, WIDTH, hflow, window, EQUAL, GREATER_THAN, HEIGHT, bold, border, dim, LESS_THAN
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator, shared_ptr #include <memory> // for allocator, shared_ptr
#include <string> // for operator+, to_string, char_traits, string #include <string> // for operator+, to_string, char_traits, string
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;
@ -44,6 +45,7 @@ int main(int argc, const char* argv[]) {
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document)); auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document); Render(screen, document);
screen.Print(); screen.Print();
getchar();
return 0; return 0;
} }

View File

@ -44,7 +44,7 @@ int main(int argc, const char* argv[]) {
paragraph(" A spinner "), spinner(6, i / 10)) | paragraph(" A spinner "), spinner(6, i / 10)) |
border; border;
auto screen = Screen::Create(Dimension::Full()); auto screen = Screen::Create(Dimension::Fit(document));
Render(screen, document); Render(screen, document);
std::cout << reset_position; std::cout << reset_position;
screen.Print(); screen.Print();

View File

@ -9,8 +9,8 @@
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color, Color::Green, Color::Red, Color::RedLight #include "ftxui/screen/color.hpp" // for Color, Color::Green, Color::Red, Color::RedLight
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {

View File

@ -1,35 +1,50 @@
#include <stdio.h> // for getchar #include <chrono> // for operator""s, chrono_literals
#include <ftxui/dom/elements.hpp> // for operator|, hflow, paragraph, border, Element, hbox, flex, vbox
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <string> // for allocator, string #include <iostream> // for cout, ostream
#include <memory> // for allocator, shared_ptr
#include <string> // for string, operator<<
#include <thread> // for sleep_for
#include "ftxui/dom/elements.hpp" // for hflow, paragraph, separator, hbox, vbox, filler, operator|, border, Element
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui #include "ftxui/screen/box.hpp" // for ftxui
using namespace std::chrono_literals;
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;
std::string p = std::string p =
R"(In probability theory and statistics, Bayes' theorem (alternatively Bayes' law or Bayes' rule) describes the probability of an event, based on prior knowledge of conditions that might be related to the event. For example, if cancer is related to age, then, using Bayes' theorem, a person's age can be used to more accurately assess the probability that they have cancer, compared to the assessment of the probability of cancer made without knowledge of the person's age. One of the many applications of Bayes' theorem is Bayesian inference, a particular approach to statistical inference. When applied, the probabilities involved in Bayes' theorem may have different probability interpretations. With the Bayesian probability interpretation the theorem expresses how a subjective degree of belief should rationally change to account for availability of related evidence. Bayesian inference is fundamental to Bayesian statistics.)"; R"(In probability theory and statistics, Bayes' theorem (alternatively Bayes' law or Bayes' rule) describes the probability of an event, based on prior knowledge of conditions that might be related to the event. For example, if cancer is related to age, then, using Bayes' theorem, a person's age can be used to more accurately assess the probability that they have cancer, compared to the assessment of the probability of cancer made without knowledge of the person's age. One of the many applications of Bayes' theorem is Bayesian inference, a particular approach to statistical inference. When applied, the probabilities involved in Bayes' theorem may have different probability interpretations. With the Bayesian probability interpretation the theorem expresses how a subjective degree of belief should rationally change to account for availability of related evidence. Bayesian inference is fundamental to Bayesian statistics.)";
std::string reset_position;
for (int i = 0;; ++i) {
auto document = vbox({ auto document = vbox({
hflow(paragraph(p)),
separator(),
hflow(paragraph(p)),
separator(),
hbox({ hbox({
hflow(paragraph(p)) | border, hflow(paragraph(p)),
hflow(paragraph(p)) | border, separator(),
hflow(paragraph(p)) | border, hflow(paragraph(p)),
}) | flex, }),
hbox({ }) |
hflow(paragraph(p)) | border, border;
hflow(paragraph(p)) | border,
}) | flex,
hbox({
hflow(paragraph(p)) | border,
}) | flex,
});
auto screen = Screen::Create(Dimension::Full(), Dimension::Full()); document = vbox(filler(), document);
// auto screen = Screen::Create(Dimension::Fit(document));
// Render(screen, document);
// screen.Print();
// getchar();
auto screen = Screen::Create(Dimension::Full());
Render(screen, document); Render(screen, document);
std::cout << reset_position;
screen.Print(); screen.Print();
getchar(); reset_position = screen.ResetPosition();
std::this_thread::sleep_for(0.01s);
}
return 0; return 0;
} }

View File

@ -2,8 +2,8 @@
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -4,8 +4,8 @@
#include <string> // for string, to_string #include <string> // for string, to_string
#include <utility> // for move #include <utility> // for move
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -7,8 +7,8 @@
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -2,8 +2,8 @@
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -2,8 +2,8 @@
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -2,8 +2,8 @@
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -2,8 +2,8 @@
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color, Color::Blue #include "ftxui/screen/color.hpp" // for Color, Color::Blue
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {

View File

@ -2,8 +2,8 @@
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -2,8 +2,8 @@
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

View File

@ -5,8 +5,8 @@
#include <string> // for basic_string, allocator, string #include <string> // for basic_string, allocator, string
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::Cyan, Color::White #include "ftxui/screen/color.hpp" // for Color, Color::Blue, Color::Cyan, Color::White
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {

View File

@ -3,8 +3,8 @@
#include <ftxui/screen/screen.hpp> // for Full, Screen #include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
int main(int argc, const char* argv[]) { int main(int argc, const char* argv[]) {
using namespace ftxui; using namespace ftxui;

52
examples/dom/vflow.cpp Normal file
View File

@ -0,0 +1,52 @@
#include <stddef.h> // for size_t
#include <stdio.h> // for getchar
#include <ftxui/dom/elements.hpp> // for operator|, Element, size, text, hcenter, Fit, vflow, window, EQUAL, bold, border, dim, HEIGHT, WIDTH
#include <ftxui/screen/screen.hpp> // for Full, Screen
#include <memory> // for allocator, shared_ptr
#include <string> // for operator+, to_string, char_traits, string
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render
int main(int argc, const char* argv[]) {
using namespace ftxui;
auto make_box = [](size_t dimx, size_t dimy) {
std::string title = std::to_string(dimx) + "x" + std::to_string(dimy);
return window(text(title) | hcenter | bold,
text("content") | hcenter | dim) |
size(WIDTH, EQUAL, dimx) | size(HEIGHT, EQUAL, dimy);
};
auto document = vflow({
make_box(7, 7),
make_box(7, 5),
make_box(5, 7),
make_box(10, 4),
make_box(10, 4),
make_box(10, 4),
make_box(10, 4),
make_box(11, 4),
make_box(11, 4),
make_box(11, 4),
make_box(11, 4),
make_box(12, 4),
make_box(12, 5),
make_box(12, 4),
make_box(13, 4),
make_box(13, 3),
make_box(13, 3),
make_box(10, 3),
}) |
border;
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
Render(screen, document);
screen.Print();
getchar();
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.

View File

@ -1,10 +1,10 @@
#include <ftxui/dom/elements.hpp> #include <ftxui/dom/elements.hpp> // for operator|, color, Element, bgcolor, graph, border
#include <ftxui/screen/screen.hpp> #include <ftxui/screen/screen.hpp> // for Fixed, Screen
#include <vector> #include <vector> // for vector
#include "ftxui/dom/node.hpp" #include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/screen/box.hpp" #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/color.hpp" #include "ftxui/screen/color.hpp" // for Color, Color::DarkBlue, Color::Green, Color::Red
int main(void) { int main(void) {
using namespace ftxui; using namespace ftxui;

View File

@ -4,6 +4,7 @@
#include <functional> #include <functional>
#include <memory> #include <memory>
#include "ftxui/dom/flexbox_config.hpp"
#include "ftxui/dom/node.hpp" #include "ftxui/dom/node.hpp"
#include "ftxui/screen/box.hpp" #include "ftxui/screen/box.hpp"
#include "ftxui/screen/color.hpp" #include "ftxui/screen/color.hpp"
@ -49,7 +50,11 @@ Decorator borderStyled(BorderStyle);
Decorator borderWith(Pixel); Decorator borderWith(Pixel);
Element window(Element title, Element content); Element window(Element title, Element content);
Element spinner(int charset_index, size_t image_index); Element spinner(int charset_index, size_t image_index);
Elements paragraph(std::string text); // Use inside hflow(). Split by space. Element paragraph(std::string text);
Element paragraphAlignLeft(std::string text);
Element paragraphAlignRight(std::string text);
Element paragraphAlignCenter(std::string text);
Element paragraphAlignJustify(std::string text);
Element graph(GraphFunction); Element graph(GraphFunction);
Element emptyElement(); Element emptyElement();
@ -69,8 +74,11 @@ Element bgcolor(Color, Element);
Element hbox(Elements); Element hbox(Elements);
Element vbox(Elements); Element vbox(Elements);
Element dbox(Elements); Element dbox(Elements);
Element flexbox(Elements, FlexboxConfig config = FlexboxConfig());
Element gridbox(std::vector<Elements> lines); Element gridbox(std::vector<Elements> lines);
Element hflow(Elements);
Element hflow(Elements); // Helper: default flexbox with row direction.
Element vflow(Elements); // Helper: default flexbox with column direction.
// -- Flexibility --- // -- Flexibility ---
// Define how to share the remaining space when not all of it is used inside a // Define how to share the remaining space when not all of it is used inside a

View File

@ -0,0 +1,115 @@
#ifndef FTXUI_DOM_FLEXBOX_CONFIG_HPP
#define FTXUI_DOM_FLEXBOX_CONFIG_HPP
/*
This replicate the CSS flexbox model.
See guide for documentation:
https://css-tricks.com/snippets/css/a-guide-to-flexbox/
*/
namespace ftxui {
struct FlexboxConfig {
/// This establishes the main-axis, thus defining the direction flex items are
/// placed in the flex container. Flexbox is (aside wrapping) single-direction
/// layout concept. Think of flex items as primarily laying out either in
/// horizontal rows or vertical columns.
enum class Direction {
Row, ///< Flex items are laid out in a row.
RowInversed, ///< Flex items are laid out in a row, but in reverse order.
Column, ///< Flex items are laid out in a column.
ColumnInversed ///< Flex items are laid out in a column, but in reverse
///< order.
};
Direction direction = Direction::Row;
/// By default, flex items will all try to fit onto one line. You can change
/// that and allow the items to wrap as needed with this property.
enum class Wrap {
NoWrap, ///< Flex items will all try to fit onto one line.
Wrap, ///< Flex items will wrap onto multiple lines.
WrapInversed, ///< Flex items will wrap onto multiple lines, but in reverse
///< order.
};
Wrap wrap = Wrap::Wrap;
/// This defines the alignment along the main axis. It helps distribute extra
/// free space leftover when either all the flex items on a line are
/// inflexible, or are flexible but have reached their maximum size. It also
/// exerts some control over the alignment of items when they overflow the
/// line.
enum class JustifyContent {
/// Items are aligned to the start of flexbox's direction.
FlexStart,
/// Items are aligned to the end of flexbox's direction.
FlexEnd,
/// Items are centered along the line.
Center,
/// Items are stretched to fill the line.
Stretch,
/// Items are evenly distributed in the line; first item is on the start
// line, last item on the end line
SpaceBetween,
/// Items are evenly distributed in the line with equal space around them.
/// Note that visually the spaces arent equal, since all the items have
/// equal space on both sides. The first item will have one unit of space
/// against the container edge, but two units of space between the next item
/// because that next item has its own spacing that applies.
SpaceAround,
/// Items are distributed so that the spacing between any two items (and the
/// space to the edges) is equal.
SpaceEvenly,
};
JustifyContent justify_content = JustifyContent::FlexStart;
/// This defines the default behavior for how flex items are laid out along
/// the cross axis on the current line. Think of it as the justify-content
/// version for the cross-axis (perpendicular to the main-axis).
enum class AlignItems {
FlexStart, ///< items are placed at the start of the cross axis.
FlexEnd, ///< items are placed at the end of the cross axis.
Center, ///< items are centered along the cross axis.
Stretch, ///< items are stretched to fill the cross axis.
};
AlignItems align_items = AlignItems::FlexStart;
// This aligns a flex containers lines within when there is extra space in
// the cross-axis, similar to how justify-content aligns individual items
// within the main-axis.
enum class AlignContent {
FlexStart, ///< items are placed at the start of the cross axis.
FlexEnd, ///< items are placed at the end of the cross axis.
Center, ///< items are centered along the cross axis.
Stretch, ///< items are stretched to fill the cross axis.
SpaceBetween, ///< items are evenly distributed in the cross axis.
SpaceAround, ///< tems evenly distributed with equal space around each
///< line.
SpaceEvenly, ///< items are evenly distributed in the cross axis with equal
///< space around them.
};
AlignContent align_content = AlignContent::FlexStart;
int gap_x = 0;
int gap_y = 0;
// Constructor pattern. For chained use like:
// ```
// FlexboxConfig()
// .Set(FlexboxConfig::Direction::Row)
// .Set(FlexboxConfig::Wrap::Wrap);
// ```
FlexboxConfig& Set(FlexboxConfig::Direction);
FlexboxConfig& Set(FlexboxConfig::Wrap);
FlexboxConfig& Set(FlexboxConfig::JustifyContent);
FlexboxConfig& Set(FlexboxConfig::AlignItems);
FlexboxConfig& Set(FlexboxConfig::AlignContent);
FlexboxConfig& SetGap(int gap_x, int gap_y);
};
} // namespace ftxui
#endif /* end of include guard: FTXUI_DOM_FLEXBOX_CONFIG_HPP */
// Copyright 2021 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -35,6 +35,15 @@ class Node {
// Step 3: Draw this element. // Step 3: Draw this element.
virtual void Render(Screen& screen); virtual void Render(Screen& screen);
// Layout may not resolve within a single iteration for some elements. This
// allows them to request additionnal iterations. This signal must be
// forwarded to children at least once.
struct Status {
int iteration = 0;
bool need_iteration = false;
};
virtual void Check(Status* status);
protected: protected:
Elements children_; Elements children_;
Requirement requirement_; Requirement requirement_;

View File

@ -28,7 +28,7 @@ struct Requirement {
} // namespace ftxui } // namespace ftxui
#endif /* end of include guard: FTXUI_REQUIREMENT_HPP */ #endif /* end of include guard: FTXUI_DOM_REQUIREMENT_HPP */
// Copyright 2020 Arthur Sonzogni. All rights reserved. // Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in // Use of this source code is governed by the MIT license that can be found in

View File

@ -11,6 +11,8 @@ struct Box {
static Box Intersection(Box a, Box b); static Box Intersection(Box a, Box b);
bool Contain(int x, int y); bool Contain(int x, int y);
bool operator==(const Box& other) const;
bool operator!=(const Box& other) const;
}; };
} // namespace ftxui } // namespace ftxui

View File

@ -1,12 +1,17 @@
[ [
{ symbol: [ "char_traits", private, "<string>", public ] }, { include: ["<bits/termios-c_cc.h>", "private", "<termios.h>", "public"]},
{ symbol: [ "ECHO", private, "<termios.h>", public ] }, { include: ["<bits/termios-c_lflag.h>", "private", "<termios.h>", "public"]},
{ symbol: [ "ICANON", private, "<termios.h>", public ] }, { include: ["<bits/termios-struct.h>", "private", "<termios.h>", "public"]},
{ symbol: [ "TCSANOW", private, "<termios.h>", public ] }, { include: ["<bits/termios-tcflow.h>", "private", "<termios.h>", "public"]},
{ symbol: [ "VMIN", private, "<termios.h>", public ] }, { include: ["<ext/alloc_traits.h>", "private", "<vector>", "public"] },
{ symbol: [ "VTIME", private, "<termios.h>", public ] }, { symbol: [ "ftxui", "private", "", "public" ] },
{ symbol: [ "__shared_ptr_access", private, "<memory>", public ] }, { symbol: [ "char_traits", "private", "<string>", "public" ] },
{ symbol: [ "termios", private, "<termios.h>", public ] }, { symbol: [ "ECHO", "private", "<termios.h>", "public" ] },
{ symbol: ["__alloc_traits<>:value_type", private, "<vector>", public ] }, { symbol: [ "ICANON", "private", "<termios.h>", "public" ] },
{ include: ["<ext/alloc_traits.h>", private, "<vector>", public] }, { symbol: [ "TCSANOW", "private", "<termios.h>", "public" ] },
{ symbol: [ "VMIN", "private", "<termios.h>", "public" ] },
{ symbol: [ "VTIME", "private", "<termios.h>", "public" ] },
{ symbol: [ "__shared_ptr_access", "private", "<memory>", "public" ] },
{ symbol: [ "termios", "private", "<termios.h>", "public" ] },
{ symbol: ["__alloc_traits<>:value_type", "private", "<vector>", "public" ] },
] ]

View File

@ -1,5 +1,5 @@
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <algorithm> // for find_if, max #include <algorithm> // for find_if
#include <cassert> // for assert #include <cassert> // for assert
#include <iterator> // for begin, end #include <iterator> // for begin, end
#include <utility> // for move #include <utility> // for move
@ -7,7 +7,7 @@
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface
#include "ftxui/component/component.hpp" #include "ftxui/component/component.hpp"
#include "ftxui/component/component_base.hpp" // for ComponentBase, Component #include "ftxui/component/component_base.hpp" // for ComponentBase, Components
#include "ftxui/component/event.hpp" // for Event #include "ftxui/component/event.hpp" // for Event
#include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive #include "ftxui/component/screen_interactive.hpp" // for Component, ScreenInteractive
#include "ftxui/dom/elements.hpp" // for text, Element #include "ftxui/dom/elements.hpp" // for text, Element

View File

@ -6,7 +6,7 @@
#include "ftxui/component/component.hpp" // for Horizontal, Vertical, Tab #include "ftxui/component/component.hpp" // for Horizontal, Vertical, Tab
#include "ftxui/component/component_base.hpp" // for Components, Component, ComponentBase #include "ftxui/component/component_base.hpp" // for Components, Component, ComponentBase
#include "ftxui/component/event.hpp" // for Event, Event::Tab, Event::TabReverse, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp #include "ftxui/component/event.hpp" // for Event, Event::Tab, Event::TabReverse, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp, Event::End, Event::Home, Event::PageDown, Event::PageUp
#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::WheelDown, Mouse::WheelUp #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::WheelDown, Mouse::WheelUp
#include "ftxui/dom/elements.hpp" // for text, Elements, operator|, reflect, Element, hbox, vbox #include "ftxui/dom/elements.hpp" // for text, Elements, operator|, reflect, Element, hbox, vbox
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
@ -102,11 +102,11 @@ class VerticalContainer : public ContainerBase {
if (event == Event::ArrowDown || event == Event::Character('j')) if (event == Event::ArrowDown || event == Event::Character('j'))
MoveSelector(+1); MoveSelector(+1);
if (event == Event::PageUp) { if (event == Event::PageUp) {
for(int i = 0; i<box_.y_max - box_.y_min; ++i) for (int i = 0; i < box_.y_max - box_.y_min; ++i)
MoveSelector(-1); MoveSelector(-1);
} }
if (event == Event::PageDown) { if (event == Event::PageDown) {
for(int i = 0; i<box_.y_max - box_.y_min; ++i) for (int i = 0; i < box_.y_max - box_.y_min; ++i)
MoveSelector(1); MoveSelector(1);
} }
if (event == Event::Home) { if (event == Event::Home) {

View File

@ -1,4 +1,4 @@
#include <cmath> #include <algorithm> // for max, min
#include <memory> // for __shared_ptr_access #include <memory> // for __shared_ptr_access
#include <string> // for string #include <string> // for string
#include <utility> // for move #include <utility> // for move

View File

@ -6,7 +6,7 @@
#include <iostream> // for cout, ostream, basic_ostream, operator<<, endl, flush #include <iostream> // for cout, ostream, basic_ostream, operator<<, endl, flush
#include <stack> // for stack #include <stack> // for stack
#include <thread> // for thread #include <thread> // for thread
#include <utility> // for move #include <utility> // for swap, move
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface
@ -18,7 +18,7 @@
#include "ftxui/component/terminal_input_parser.hpp" // for TerminalInputParser #include "ftxui/component/terminal_input_parser.hpp" // for TerminalInputParser
#include "ftxui/dom/node.hpp" // for Node, Render #include "ftxui/dom/node.hpp" // for Node, Render
#include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/terminal.hpp" // for Terminal::Dimensions, Terminal #include "ftxui/screen/terminal.hpp" // for Size, Dimensions
#if defined(_WIN32) #if defined(_WIN32)
#define DEFINE_CONSOLEV2_PROPERTIES #define DEFINE_CONSOLEV2_PROPERTIES
@ -32,7 +32,7 @@
#endif #endif
#else #else
#include <sys/select.h> // for select, FD_ISSET, FD_SET, FD_ZERO, fd_set #include <sys/select.h> // for select, FD_ISSET, FD_SET, FD_ZERO, fd_set
#include <termios.h> // for tcsetattr, termios, tcgetattr, TCSANOW, cc_t, ECHO, ICANON, VMIN, VTIME #include <termios.h> // for tcsetattr, tcgetattr, cc_t
#include <unistd.h> // for STDIN_FILENO, read #include <unistd.h> // for STDIN_FILENO, read
#endif #endif

View File

@ -1,8 +1,8 @@
#include <benchmark/benchmark.h> #include <benchmark/benchmark.h>
#include "ftxui/dom/elements.hpp" // for separator, gauge, operator|, text, Element, blink, inverted, hbox, vbox, border #include "ftxui/dom/elements.hpp" // for separator, gauge, operator|, text, Element, blink, inverted, hbox, vbox, border
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
using namespace ftxui; using namespace ftxui;

View File

@ -23,7 +23,6 @@ class Blink : public NodeDecorator {
} }
}; };
/// @brief The text drawn alternates in between visible and hidden. /// @brief The text drawn alternates in between visible and hidden.
/// @ingroup dom /// @ingroup dom
Element blink(Element child) { Element blink(Element child) {

View File

@ -1,12 +1,12 @@
#include <algorithm> // for max #include <algorithm> // for max
#include <iterator> // for begin, end #include <iterator> // for begin, end
#include <memory> // for allocator, make_shared, __shared_ptr_access #include <memory> // for allocator, make_shared, __shared_ptr_access
#include <string> // for basic_string, string #include <string> // for string, basic_string
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector, __alloc_traits<>::value_type #include <vector> // for vector, __alloc_traits<>::value_type
#include "ftxui/dom/elements.hpp" // for unpack, Element, Decorator, Elements, border, borderWith, window #include "ftxui/dom/elements.hpp" // for unpack, Element, Decorator, BorderStyle, ROUNDED, Elements, DOUBLE, EMPTY, HEAVY, LIGHT, border, borderDouble, borderEmpty, borderHeavy, borderLight, borderRounded, borderStyled, borderWith, window
#include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/node.hpp" // for Node, Elements
#include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
#include "ftxui/screen/screen.hpp" // for Pixel, Screen #include "ftxui/screen/screen.hpp" // for Pixel, Screen

View File

@ -25,4 +25,4 @@ void Compute(std::vector<Element>* elements, int target_size);
// Copyright 2021 Arthur Sonzogni. All rights reserved. // Copyright 2021 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in // Use of this source code is governed by the MIT license that can be found in
// the LICENSE file. // the LICENSE file.line.

View File

@ -1,9 +1,9 @@
#include <memory> // for make_shared, __shared_ptr_access #include <memory> // for make_shared, __shared_ptr_access
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector, __alloc_traits<>::value_type #include <vector> // for __alloc_traits<>::value_type
#include "ftxui/dom/elements.hpp" // for Element, unpack, filler, flex, flex_grow, flex_shrink, notflex, xflex, xflex_grow, xflex_shrink, yflex, yflex_grow, yflex_shrink #include "ftxui/dom/elements.hpp" // for Element, unpack, filler, flex, flex_grow, flex_shrink, notflex, xflex, xflex_grow, xflex_shrink, yflex, yflex_grow, yflex_shrink
#include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/node.hpp" // for Elements, Node
#include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box

239
src/ftxui/dom/flexbox.cpp Normal file
View File

@ -0,0 +1,239 @@
#include <stddef.h> // for size_t
#include <algorithm> // for min, max
#include <memory> // for __shared_ptr_access, shared_ptr, allocator_traits<>::value_type, make_shared
#include <utility> // for move, swap
#include <vector> // for vector
#include "ftxui/dom/elements.hpp" // for Element, Elements, flexbox, hflow, vflow
#include "ftxui/dom/flexbox_config.hpp" // for FlexboxConfig, FlexboxConfig::Direction, FlexboxConfig::Direction::Column, FlexboxConfig::AlignContent, FlexboxConfig::Direction::ColumnInversed, FlexboxConfig::Direction::Row, FlexboxConfig::JustifyContent, FlexboxConfig::Wrap, FlexboxConfig::AlignContent::FlexStart, FlexboxConfig::Direction::RowInversed, FlexboxConfig::JustifyContent::FlexStart, FlexboxConfig::Wrap::Wrap
#include "ftxui/dom/flexbox_helper.hpp" // for Block, Global, Compute
#include "ftxui/dom/node.hpp" // for Node, Elements, Node::Status
#include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/box.hpp" // for Box
namespace ftxui {
namespace {
void Normalize(FlexboxConfig::Direction& direction) {
switch (direction) {
case FlexboxConfig::Direction::Row:
case FlexboxConfig::Direction::RowInversed: {
direction = FlexboxConfig::Direction::Row;
} break;
case FlexboxConfig::Direction::Column:
case FlexboxConfig::Direction::ColumnInversed: {
direction = FlexboxConfig::Direction::Column;
} break;
}
}
void Normalize(FlexboxConfig::AlignContent& align_content) {
align_content = FlexboxConfig::AlignContent::FlexStart;
}
void Normalize(FlexboxConfig::JustifyContent& justify_content) {
justify_content = FlexboxConfig::JustifyContent::FlexStart;
}
void Normalize(FlexboxConfig::Wrap& wrap) {
wrap = FlexboxConfig::Wrap::Wrap;
}
FlexboxConfig Normalize(FlexboxConfig config) {
Normalize(config.direction);
Normalize(config.wrap);
Normalize(config.justify_content);
Normalize(config.align_content);
return config;
}
class Flexbox : public Node {
public:
Flexbox(Elements children, FlexboxConfig config)
: Node(std::move(children)),
config_(config),
config_normalized_(Normalize(config)) {
requirement_.flex_grow_x = 1;
requirement_.flex_grow_y = 0;
if (IsColumnOriented())
std::swap(requirement_.flex_grow_x, requirement_.flex_grow_y);
}
bool IsColumnOriented() {
return config_.direction == FlexboxConfig::Direction::Column ||
config_.direction == FlexboxConfig::Direction::ColumnInversed;
}
void Layout(flexbox_helper::Global& global,
bool compute_requirement = false) {
for (auto& child : children_) {
flexbox_helper::Block block;
block.min_size_x = child->requirement().min_x;
block.min_size_y = child->requirement().min_y;
if (!compute_requirement) {
block.flex_grow_x = child->requirement().flex_grow_x;
block.flex_grow_y = child->requirement().flex_grow_y;
block.flex_shrink_x = child->requirement().flex_shrink_x;
block.flex_shrink_y = child->requirement().flex_shrink_y;
}
global.blocks.push_back(block);
}
flexbox_helper::Compute(global);
}
void ComputeRequirement() override {
for (auto& child : children_)
child->ComputeRequirement();
flexbox_helper::Global global;
global.config = config_normalized_;
if (IsColumnOriented()) {
global.size_x = 100000;
global.size_y = asked_;
} else {
global.size_x = asked_;
global.size_y = 100000;
}
Layout(global, true);
if (global.blocks.size() == 0) {
requirement_.min_x = 0;
requirement_.min_y = 0;
return;
}
Box box;
box.x_min = global.blocks[0].x;
box.y_min = global.blocks[0].y;
box.x_max = global.blocks[0].x + global.blocks[0].dim_x;
box.y_max = global.blocks[0].y + global.blocks[0].dim_y;
for (auto& b : global.blocks) {
box.x_min = std::min(box.x_min, b.x);
box.y_min = std::min(box.y_min, b.y);
box.x_max = std::max(box.x_max, b.x + b.dim_x);
box.y_max = std::max(box.y_max, b.y + b.dim_y);
}
requirement_.min_x = box.x_max - box.x_min;
requirement_.min_y = box.y_max - box.y_min;
}
void SetBox(Box box) override {
Node::SetBox(box);
asked_ = std::min(asked_, IsColumnOriented() ? box.y_max - box.y_min + 1
: box.x_max - box.x_min + 1);
flexbox_helper::Global global;
global.config = config_;
global.size_x = box.x_max - box.x_min + 1;
global.size_y = box.y_max - box.y_min + 1;
Layout(global);
need_iteration_ = false;
for (size_t i = 0; i < children_.size(); ++i) {
auto& child = children_[i];
auto& b = global.blocks[i];
Box children_box;
children_box.x_min = box.x_min + b.x;
children_box.y_min = box.y_min + b.y;
children_box.x_max = box.x_min + b.x + b.dim_x - 1;
children_box.y_max = box.y_min + b.y + b.dim_y - 1;
Box intersection = Box::Intersection(children_box, box);
child->SetBox(intersection);
need_iteration_ |= (intersection != children_box);
}
}
void Check(Status* status) override {
for (auto& child : children_)
child->Check(status);
if (status->iteration == 0) {
asked_ = 6000;
need_iteration_ = true;
}
status->need_iteration |= need_iteration_;
}
int asked_ = 6000;
bool need_iteration_ = true;
const FlexboxConfig config_;
const FlexboxConfig config_normalized_;
};
} // namespace
/// @brief A container displaying elements on row/columns and capable of
/// wrapping on the next column/row when full.
/// @param children The elements in the container
/// @param config The option
/// @return The container.
///
/// #### Example
///
/// ```cpp
/// flexbox({
/// text("element 1"),
/// text("element 2"),
/// text("element 3"),
/// }, FlexboxConfig()
// .Set(FlexboxConfig::Direction::Column)
// .Set(FlexboxConfig::Wrap::WrapInversed)
// .SetGapMainAxis(1)
// .SetGapCrossAxis(1)
// )
/// ```
Element flexbox(Elements children, FlexboxConfig config) {
return std::make_shared<Flexbox>(std::move(children), std::move(config));
}
/// @brief A container displaying elements in rows from left to right. When
/// filled, it starts on a new row below.
/// @param children The elements in the container
/// @return The container.
///
/// #### Example
///
/// ```cpp
/// hflow({
/// text("element 1"),
/// text("element 2"),
/// text("element 3"),
/// });
/// ```
Element hflow(Elements children) {
return flexbox(std::move(children), FlexboxConfig());
}
/// @brief A container displaying elements in rows from top to bottom. When
/// filled, it starts on a new columns on the right.
/// filled, it starts on a new row.
/// is full, it starts a new row.
/// @param children The elements in the container
/// @return The container.
///
/// #### Example
///
/// ```cpp
/// vflow({
/// text("element 1"),
/// text("element 2"),
/// text("element 3"),
/// });
/// ```
Element vflow(Elements children) {
return flexbox(std::move(children),
FlexboxConfig().Set(FlexboxConfig::Direction::Column));
}
} // namespace ftxui
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -0,0 +1,40 @@
#include "ftxui/dom/flexbox_config.hpp"
namespace ftxui {
FlexboxConfig& FlexboxConfig::Set(FlexboxConfig::Direction d) {
this->direction = d;
return *this;
}
FlexboxConfig& FlexboxConfig::Set(FlexboxConfig::Wrap w) {
this->wrap = w;
return *this;
}
FlexboxConfig& FlexboxConfig::Set(FlexboxConfig::JustifyContent j) {
this->justify_content = j;
return *this;
}
FlexboxConfig& FlexboxConfig::Set(FlexboxConfig::AlignItems a) {
this->align_items = a;
return *this;
}
FlexboxConfig& FlexboxConfig::Set(FlexboxConfig::AlignContent a) {
this->align_content = a;
return *this;
}
FlexboxConfig& FlexboxConfig::SetGap(int x, int y) {
this->gap_x = x;
this->gap_y = y;
return *this;
}
} // namespace ftxui
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -0,0 +1,325 @@
#include "ftxui/dom/flexbox_helper.hpp"
#include <stddef.h> // for size_t
#include <algorithm> // for min, max
#include <memory> // for allocator_traits<>::value_type
#include <utility> // for swap, move
#include "ftxui/dom/box_helper.hpp" // for Element, Compute
namespace ftxui {
namespace flexbox_helper {
namespace {
void SymmetryXY(FlexboxConfig& c) {
std::swap(c.gap_x, c.gap_y);
switch (c.direction) {
case FlexboxConfig::Direction::Row:
c.direction = FlexboxConfig::Direction::Column;
break;
case FlexboxConfig::Direction::RowInversed:
c.direction = FlexboxConfig::Direction::ColumnInversed;
break;
case FlexboxConfig::Direction::Column:
c.direction = FlexboxConfig::Direction::Row;
break;
case FlexboxConfig::Direction::ColumnInversed:
c.direction = FlexboxConfig::Direction::RowInversed;
break;
}
}
void SymmetryX(FlexboxConfig& c) {
switch (c.direction) {
case FlexboxConfig::Direction::Row:
c.direction = FlexboxConfig::Direction::RowInversed;
break;
case FlexboxConfig::Direction::RowInversed:
c.direction = FlexboxConfig::Direction::Row;
break;
default:
break;
}
}
void SymmetryY(FlexboxConfig& c) {
switch (c.wrap) {
case FlexboxConfig::Wrap::NoWrap:
break;
case FlexboxConfig::Wrap::Wrap:
c.wrap = FlexboxConfig::Wrap::WrapInversed;
break;
case FlexboxConfig::Wrap::WrapInversed:
c.wrap = FlexboxConfig::Wrap::Wrap;
break;
}
}
void SymmetryXY(Global& g) {
SymmetryXY(g.config);
std::swap(g.size_x, g.size_y);
for (auto& b : g.blocks) {
std::swap(b.min_size_x, b.min_size_y);
std::swap(b.flex_grow_x, b.flex_grow_y);
std::swap(b.flex_shrink_x, b.flex_shrink_y);
std::swap(b.x, b.y);
std::swap(b.dim_x, b.dim_y);
}
}
void SymmetryX(Global& g) {
SymmetryX(g.config);
for (auto& b : g.blocks) {
b.x = g.size_x - b.x - b.dim_x;
}
}
void SymmetryY(Global& g) {
SymmetryY(g.config);
for (auto& b : g.blocks) {
b.y = g.size_y - b.y - b.dim_y;
}
}
struct Line {
std::vector<Block*> blocks;
};
void SetX(Global& global, std::vector<Line> lines) {
for (auto& line : lines) {
std::vector<box_helper::Element> elements;
for (auto* block : line.blocks) {
box_helper::Element element;
element.min_size = block->min_size_x;
element.flex_grow =
block->flex_grow_x || global.config.justify_content ==
FlexboxConfig::JustifyContent::Stretch;
element.flex_shrink = block->flex_shrink_x;
elements.push_back(element);
}
box_helper::Compute(
&elements,
global.size_x - global.config.gap_x * (line.blocks.size() - 1));
int x = 0;
for (size_t i = 0; i < line.blocks.size(); ++i) {
line.blocks[i]->dim_x = elements[i].size;
line.blocks[i]->x = x;
x += elements[i].size;
x += global.config.gap_x;
}
}
}
void SetY(Global& g, std::vector<Line> lines) {
std::vector<box_helper::Element> elements;
for (auto& line : lines) {
box_helper::Element element;
element.flex_shrink = line.blocks.front()->flex_shrink_y;
element.flex_grow = line.blocks.front()->flex_grow_y;
for (auto* block : line.blocks) {
element.min_size = std::max(element.min_size, block->min_size_y);
element.flex_shrink = std::min(element.flex_shrink, block->flex_shrink_y);
element.flex_grow = std::min(element.flex_grow, block->flex_grow_y);
}
elements.push_back(element);
}
// box_helper::Compute(&elements, g.size_y);
box_helper::Compute(&elements, 10000);
// [Align-content]
std::vector<int> ys(elements.size());
int y = 0;
for (size_t i = 0; i < elements.size(); ++i) {
ys[i] = y;
y += elements[i].size;
y += g.config.gap_y;
}
int remaining_space = std::max(0, g.size_y - y);
switch (g.config.align_content) {
case FlexboxConfig::AlignContent::FlexStart: {
} break;
case FlexboxConfig::AlignContent::FlexEnd: {
for (size_t i = 0; i < ys.size(); ++i)
ys[i] += remaining_space;
} break;
case FlexboxConfig::AlignContent::Center: {
for (size_t i = 0; i < ys.size(); ++i)
ys[i] += remaining_space / 2;
} break;
case FlexboxConfig::AlignContent::Stretch: {
for (int i = ys.size() - 1; i >= 0; --i) {
int shifted = remaining_space * (i + 0) / (i + 1);
ys[i] += shifted;
int consumed = remaining_space - shifted;
elements[i].size += consumed;
remaining_space -= consumed;
}
} break;
case FlexboxConfig::AlignContent::SpaceBetween: {
for (int i = ys.size() - 1; i >= 1; --i) {
ys[i] += remaining_space;
remaining_space = remaining_space * (i - 1) / i;
}
} break;
case FlexboxConfig::AlignContent::SpaceAround: {
for (int i = ys.size() - 1; i >= 0; --i) {
ys[i] += remaining_space * (2 * i + 1) / (2 * i + 2);
remaining_space = remaining_space * (2 * i) / (2 * i + 2);
}
} break;
case FlexboxConfig::AlignContent::SpaceEvenly: {
for (int i = ys.size() - 1; i >= 0; --i) {
ys[i] += remaining_space * (i + 1) / (i + 2);
remaining_space = remaining_space * (i + 1) / (i + 2);
}
} break;
}
// [Align items]
for (size_t i = 0; i < lines.size(); ++i) {
auto& element = elements[i];
for (auto* block : lines[i].blocks) {
bool stretch =
block->flex_grow_y ||
g.config.align_content == FlexboxConfig::AlignContent::Stretch;
int size =
stretch ? element.size : std::min(element.size, block->min_size_y);
switch (g.config.align_items) {
case FlexboxConfig::AlignItems::FlexStart: {
block->y = ys[i];
block->dim_y = size;
} break;
case FlexboxConfig::AlignItems::Center: {
block->y = ys[i] + (element.size - size) / 2;
block->dim_y = size;
} break;
case FlexboxConfig::AlignItems::FlexEnd: {
block->y = ys[i] + element.size - size;
block->dim_y = size;
} break;
case FlexboxConfig::AlignItems::Stretch: {
block->y = ys[i];
block->dim_y = element.size;
} break;
}
}
}
}
void JustifyContent(Global& g, std::vector<Line> lines) {
for (auto& line : lines) {
Block* last = line.blocks.back();
int remaining_space = g.size_x - last->x - last->dim_x;
switch (g.config.justify_content) {
case FlexboxConfig::JustifyContent::FlexStart:
case FlexboxConfig::JustifyContent::Stretch:
break;
case FlexboxConfig::JustifyContent::FlexEnd: {
for (auto* block : line.blocks)
block->x += remaining_space;
} break;
case FlexboxConfig::JustifyContent::Center: {
for (auto* block : line.blocks)
block->x += remaining_space / 2;
} break;
case FlexboxConfig::JustifyContent::SpaceBetween: {
for (int i = line.blocks.size() - 1; i >= 1; --i) {
line.blocks[i]->x += remaining_space;
remaining_space = remaining_space * (i - 1) / i;
}
} break;
case FlexboxConfig::JustifyContent::SpaceAround: {
for (int i = line.blocks.size() - 1; i >= 0; --i) {
line.blocks[i]->x += remaining_space * (2 * i + 1) / (2 * i + 2);
remaining_space = remaining_space * (2 * i) / (2 * i + 2);
}
} break;
case FlexboxConfig::JustifyContent::SpaceEvenly: {
for (int i = line.blocks.size() - 1; i >= 0; --i) {
line.blocks[i]->x += remaining_space * (i + 1) / (i + 2);
remaining_space = remaining_space * (i + 1) / (i + 2);
}
} break;
}
}
}
} // namespace
void Compute(Global& global) {
if (global.config.direction == FlexboxConfig::Direction::Column ||
global.config.direction == FlexboxConfig::Direction::ColumnInversed) {
SymmetryXY(global);
Compute(global);
SymmetryXY(global);
return;
}
if (global.config.direction == FlexboxConfig::Direction::RowInversed) {
SymmetryX(global);
Compute(global);
SymmetryX(global);
return;
}
if (global.config.wrap == FlexboxConfig::Wrap::WrapInversed) {
SymmetryY(global);
Compute(global);
SymmetryY(global);
return;
}
// Step 1: Lay out every elements into rows:
std::vector<Line> lines;
{
Line line;
int x = 0;
for (auto& block : global.blocks) {
// Does it fit the end of the row?
// No? Then we need to start a new one:
if (x + block.min_size_x > global.size_x) {
x = 0;
if (!line.blocks.empty())
lines.push_back(std::move(line));
line = Line();
}
block.line = lines.size();
block.line_position = line.blocks.size();
line.blocks.push_back(&block);
x += block.min_size_x + global.config.gap_x;
}
if (!line.blocks.empty())
lines.push_back(std::move(line));
}
// Step 2: Set positions on the X axis.
SetX(global, lines);
JustifyContent(global, lines); // Distribute remaining space.
// Step 3: Set positions on the Y axis.
SetY(global, lines);
}
} // namespace flexbox_helper
} // namespace ftxui
// Copyright 2021 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -0,0 +1,45 @@
#ifndef FTXUI_DOM_FLEXBOX_HELPER_HPP
#define FTXUI_DOM_FLEXBOX_HELPER_HPP
#include <vector>
#include "ftxui/dom/flexbox_config.hpp"
namespace ftxui {
namespace flexbox_helper {
struct Block {
// Input:
int min_size_x = 0;
int min_size_y = 0;
int flex_grow_x = 0;
int flex_grow_y = 0;
int flex_shrink_x = 0;
int flex_shrink_y = 0;
// Output:
int line;
int line_position;
int x = 0;
int y = 0;
int dim_x = 0;
int dim_y = 0;
bool overflow = false;
};
struct Global {
std::vector<Block> blocks;
FlexboxConfig config;
int size_x;
int size_y;
};
void Compute(Global& global);
} // namespace flexbox_helper
} // namespace ftxui
#endif /* end of include guard: FTXUI_DOM_FLEXBOX_HELPER_HPP*/
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -0,0 +1,233 @@
#include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for TestPartResult, SuiteApiResolver, TestFactoryImpl
#include <memory> // for allocator_traits<>::value_type
#include "ftxui/dom/flexbox_helper.hpp"
#include "gtest/gtest_pred_impl.h" // for EXPECT_EQ, Test, TEST
using namespace ftxui;
using namespace ftxui;
TEST(FlexboxHelperTest, BasicRow) {
flexbox_helper::Block block_10_5;
block_10_5.min_size_x = 10;
block_10_5.min_size_y = 5;
flexbox_helper::Global g;
g.blocks = {
block_10_5, block_10_5, block_10_5, block_10_5, block_10_5,
};
g.size_x = 32;
g.size_y = 16;
g.config = FlexboxConfig().Set(FlexboxConfig::Direction::Row);
flexbox_helper::Compute(g);
EXPECT_EQ(g.blocks.size(), 5u);
EXPECT_EQ(g.blocks[0].line, 0);
EXPECT_EQ(g.blocks[1].line, 0);
EXPECT_EQ(g.blocks[2].line, 0);
EXPECT_EQ(g.blocks[3].line, 1);
EXPECT_EQ(g.blocks[4].line, 1);
EXPECT_EQ(g.blocks[0].line_position, 0);
EXPECT_EQ(g.blocks[1].line_position, 1);
EXPECT_EQ(g.blocks[2].line_position, 2);
EXPECT_EQ(g.blocks[3].line_position, 0);
EXPECT_EQ(g.blocks[4].line_position, 1);
EXPECT_EQ(g.blocks[0].x, 0);
EXPECT_EQ(g.blocks[0].y, 0);
EXPECT_EQ(g.blocks[0].dim_x, 10);
EXPECT_EQ(g.blocks[0].dim_y, 5);
EXPECT_EQ(g.blocks[1].x, 10);
EXPECT_EQ(g.blocks[1].y, 0);
EXPECT_EQ(g.blocks[1].dim_x, 10);
EXPECT_EQ(g.blocks[1].dim_y, 5);
EXPECT_EQ(g.blocks[2].x, 20);
EXPECT_EQ(g.blocks[2].y, 0);
EXPECT_EQ(g.blocks[2].dim_x, 10);
EXPECT_EQ(g.blocks[2].dim_y, 5);
EXPECT_EQ(g.blocks[3].x, 0);
EXPECT_EQ(g.blocks[3].y, 5);
EXPECT_EQ(g.blocks[3].dim_x, 10);
EXPECT_EQ(g.blocks[3].dim_y, 5);
EXPECT_EQ(g.blocks[4].x, 10);
EXPECT_EQ(g.blocks[4].y, 5);
EXPECT_EQ(g.blocks[4].dim_x, 10);
EXPECT_EQ(g.blocks[4].dim_y, 5);
}
TEST(FlexboxHelperTest, BasicColumn) {
flexbox_helper::Block block_10_5;
block_10_5.min_size_x = 10;
block_10_5.min_size_y = 5;
flexbox_helper::Global g;
g.blocks = {
block_10_5, block_10_5, block_10_5, block_10_5, block_10_5,
};
g.size_x = 32;
g.size_y = 16;
g.config = FlexboxConfig().Set(FlexboxConfig::Direction::Column);
flexbox_helper::Compute(g);
EXPECT_EQ(g.blocks.size(), 5u);
EXPECT_EQ(g.blocks[0].line, 0);
EXPECT_EQ(g.blocks[1].line, 0);
EXPECT_EQ(g.blocks[2].line, 0);
EXPECT_EQ(g.blocks[3].line, 1);
EXPECT_EQ(g.blocks[4].line, 1);
EXPECT_EQ(g.blocks[0].line_position, 0);
EXPECT_EQ(g.blocks[1].line_position, 1);
EXPECT_EQ(g.blocks[2].line_position, 2);
EXPECT_EQ(g.blocks[3].line_position, 0);
EXPECT_EQ(g.blocks[4].line_position, 1);
EXPECT_EQ(g.blocks[0].x, 0);
EXPECT_EQ(g.blocks[0].y, 0);
EXPECT_EQ(g.blocks[0].dim_x, 10);
EXPECT_EQ(g.blocks[0].dim_y, 5);
EXPECT_EQ(g.blocks[1].x, 0);
EXPECT_EQ(g.blocks[1].y, 5);
EXPECT_EQ(g.blocks[1].dim_x, 10);
EXPECT_EQ(g.blocks[1].dim_y, 5);
EXPECT_EQ(g.blocks[2].x, 0);
EXPECT_EQ(g.blocks[2].y, 10);
EXPECT_EQ(g.blocks[2].dim_x, 10);
EXPECT_EQ(g.blocks[2].dim_y, 5);
EXPECT_EQ(g.blocks[3].x, 10);
EXPECT_EQ(g.blocks[3].y, 0);
EXPECT_EQ(g.blocks[3].dim_x, 10);
EXPECT_EQ(g.blocks[3].dim_y, 5);
EXPECT_EQ(g.blocks[4].x, 10);
EXPECT_EQ(g.blocks[4].y, 5);
EXPECT_EQ(g.blocks[4].dim_x, 10);
EXPECT_EQ(g.blocks[4].dim_y, 5);
}
TEST(FlexboxHelperTest, BasicRowInversed) {
flexbox_helper::Block block_10_5;
block_10_5.min_size_x = 10;
block_10_5.min_size_y = 5;
flexbox_helper::Global g;
g.blocks = {
block_10_5, block_10_5, block_10_5, block_10_5, block_10_5,
};
g.size_x = 32;
g.size_y = 16;
g.config = FlexboxConfig().Set(FlexboxConfig::Direction::RowInversed);
flexbox_helper::Compute(g);
EXPECT_EQ(g.blocks.size(), 5u);
EXPECT_EQ(g.blocks[0].line, 0);
EXPECT_EQ(g.blocks[1].line, 0);
EXPECT_EQ(g.blocks[2].line, 0);
EXPECT_EQ(g.blocks[3].line, 1);
EXPECT_EQ(g.blocks[4].line, 1);
EXPECT_EQ(g.blocks[0].line_position, 0);
EXPECT_EQ(g.blocks[1].line_position, 1);
EXPECT_EQ(g.blocks[2].line_position, 2);
EXPECT_EQ(g.blocks[3].line_position, 0);
EXPECT_EQ(g.blocks[4].line_position, 1);
EXPECT_EQ(g.blocks[0].x, 22);
EXPECT_EQ(g.blocks[0].y, 0);
EXPECT_EQ(g.blocks[0].dim_x, 10);
EXPECT_EQ(g.blocks[0].dim_y, 5);
EXPECT_EQ(g.blocks[1].x, 12);
EXPECT_EQ(g.blocks[1].y, 0);
EXPECT_EQ(g.blocks[1].dim_x, 10);
EXPECT_EQ(g.blocks[1].dim_y, 5);
EXPECT_EQ(g.blocks[2].x, 2);
EXPECT_EQ(g.blocks[2].y, 0);
EXPECT_EQ(g.blocks[2].dim_x, 10);
EXPECT_EQ(g.blocks[2].dim_y, 5);
EXPECT_EQ(g.blocks[3].x, 22);
EXPECT_EQ(g.blocks[3].y, 5);
EXPECT_EQ(g.blocks[3].dim_x, 10);
EXPECT_EQ(g.blocks[3].dim_y, 5);
EXPECT_EQ(g.blocks[4].x, 12);
EXPECT_EQ(g.blocks[4].y, 5);
EXPECT_EQ(g.blocks[4].dim_x, 10);
EXPECT_EQ(g.blocks[4].dim_y, 5);
}
TEST(FlexboxHelperTest, BasicColumnInversed) {
flexbox_helper::Block block_10_5;
block_10_5.min_size_x = 10;
block_10_5.min_size_y = 5;
flexbox_helper::Global g;
g.blocks = {
block_10_5, block_10_5, block_10_5, block_10_5, block_10_5,
};
g.size_x = 32;
g.size_y = 16;
g.config = FlexboxConfig().Set(FlexboxConfig::Direction::ColumnInversed);
flexbox_helper::Compute(g);
EXPECT_EQ(g.blocks.size(), 5u);
EXPECT_EQ(g.blocks[0].line, 0);
EXPECT_EQ(g.blocks[1].line, 0);
EXPECT_EQ(g.blocks[2].line, 0);
EXPECT_EQ(g.blocks[3].line, 1);
EXPECT_EQ(g.blocks[4].line, 1);
EXPECT_EQ(g.blocks[0].line_position, 0);
EXPECT_EQ(g.blocks[1].line_position, 1);
EXPECT_EQ(g.blocks[2].line_position, 2);
EXPECT_EQ(g.blocks[3].line_position, 0);
EXPECT_EQ(g.blocks[4].line_position, 1);
EXPECT_EQ(g.blocks[0].x, 0);
EXPECT_EQ(g.blocks[0].y, 11);
EXPECT_EQ(g.blocks[0].dim_x, 10);
EXPECT_EQ(g.blocks[0].dim_y, 5);
EXPECT_EQ(g.blocks[1].x, 0);
EXPECT_EQ(g.blocks[1].y, 6);
EXPECT_EQ(g.blocks[1].dim_x, 10);
EXPECT_EQ(g.blocks[1].dim_y, 5);
EXPECT_EQ(g.blocks[2].x, 0);
EXPECT_EQ(g.blocks[2].y, 1);
EXPECT_EQ(g.blocks[2].dim_x, 10);
EXPECT_EQ(g.blocks[2].dim_y, 5);
EXPECT_EQ(g.blocks[3].x, 10);
EXPECT_EQ(g.blocks[3].y, 11);
EXPECT_EQ(g.blocks[3].dim_x, 10);
EXPECT_EQ(g.blocks[3].dim_y, 5);
EXPECT_EQ(g.blocks[4].x, 10);
EXPECT_EQ(g.blocks[4].y, 6);
EXPECT_EQ(g.blocks[4].dim_x, 10);
EXPECT_EQ(g.blocks[4].dim_y, 5);
}
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -0,0 +1,437 @@
#include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl, TestPartResult
#include <string> // for allocator
#include "ftxui/dom/elements.hpp" // for text, flexbox
#include "ftxui/dom/flexbox_config.hpp" // for FlexboxConfig, FlexboxConfig::Direction, FlexboxConfig::AlignContent, FlexboxConfig::JustifyContent, FlexboxConfig::Direction::Column, FlexboxConfig::AlignItems, FlexboxConfig::JustifyContent::SpaceAround, FlexboxConfig::AlignContent::Center, FlexboxConfig::AlignContent::FlexEnd, FlexboxConfig::AlignContent::SpaceAround, FlexboxConfig::AlignContent::SpaceBetween, FlexboxConfig::AlignContent::SpaceEvenly, FlexboxConfig::AlignItems::Center, FlexboxConfig::AlignItems::FlexEnd, FlexboxConfig::Direction::ColumnInversed, FlexboxConfig::Direction::Row, FlexboxConfig::Direction::RowInversed, FlexboxConfig::JustifyContent::Center, FlexboxConfig::JustifyContent::SpaceBetween, ftxui
#include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/screen.hpp" // for Screen
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST
using namespace ftxui;
TEST(FlexboxTest, BasicRow) {
auto root = flexbox(
{
text("aaa"),
text("bbb"),
text("cccc"),
text("dddd"),
},
FlexboxConfig().Set(FlexboxConfig::Direction::Row));
Screen screen(7, 4);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
"aaabbb \r\n"
"cccc \r\n"
"dddd \r\n"
" ");
}
TEST(FlexboxTest, BasicRowInversed) {
auto root = flexbox(
{
text("aaa"),
text("bbb"),
text("cccc"),
text("dddd"),
},
FlexboxConfig().Set(FlexboxConfig::Direction::RowInversed));
Screen screen(7, 4);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
" bbbaaa\r\n"
" cccc\r\n"
" dddd\r\n"
" ");
}
TEST(FlexboxTest, BasicColumn) {
auto root = flexbox(
{
text("aaa"),
text("bbb"),
text("cccc"),
text("dddd"),
text("e"),
},
FlexboxConfig().Set(FlexboxConfig::Direction::Column));
Screen screen(8, 3);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
"aaa dddd\r\n"
"bbb e \r\n"
"cccc ");
}
TEST(FlexboxTest, BasicColumnInversed) {
auto root = flexbox(
{
text("aaa"),
text("bbb"),
text("cccc"),
text("dddd"),
text("e"),
},
FlexboxConfig().Set(FlexboxConfig::Direction::ColumnInversed));
Screen screen(8, 3);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
"cccc \r\n"
"bbb e \r\n"
"aaa dddd");
}
TEST(FlexboxTest, JustifyContentCenter) {
auto root = flexbox(
{
text("aaa"),
text("bbb"),
text("cccc"),
text("dddd"),
text("e"),
},
FlexboxConfig().Set(FlexboxConfig::JustifyContent::Center));
Screen screen(7, 4);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
"aaabbb \r\n"
" cccc \r\n"
" dddde \r\n"
" ");
}
TEST(FlexboxTest, JustifyContentSpaceBetween) {
auto root = flexbox(
{
text("aaa"),
text("bbb"),
text("cccc"),
text("dddd"),
text("e"),
},
FlexboxConfig().Set(FlexboxConfig::JustifyContent::SpaceBetween));
Screen screen(7, 4);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
"aaa bbb\r\n"
"cccc \r\n"
"dddd e\r\n"
" ");
}
TEST(FlexboxTest, JustifyContentSpaceAround) {
auto root = flexbox(
{
text("aa"),
text("bb"),
text("ccc"),
text("dddddddddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig().Set(FlexboxConfig::JustifyContent::SpaceAround));
Screen screen(15, 4);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
" aa bb ccc \r\n"
"ddddddddddddee \r\n"
" ff ggg \r\n"
" ");
}
TEST(FlexboxTest, JustifyContentSpaceEvenly) {
auto root = flexbox(
{
text("aa"),
text("bb"),
text("ccc"),
text("dddddddddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig().Set(FlexboxConfig::JustifyContent::SpaceAround));
Screen screen(15, 4);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
" aa bb ccc \r\n"
"ddddddddddddee \r\n"
" ff ggg \r\n"
" ");
}
TEST(FlexboxTest, AlignItemsFlexEnd) {
auto root = flexbox(
{
text("aa"),
text("bb"),
text("ccc"),
text("ddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig()
.Set(FlexboxConfig::Direction::Column)
.Set(FlexboxConfig::AlignItems::FlexEnd));
Screen screen(15, 5);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
" aa ff \r\n"
" bbggg \r\n"
" ccc \r\n"
"ddddd \r\n"
" ee ");
}
TEST(FlexboxTest, AlignItemsCenter) {
auto root = flexbox(
{
text("aa"),
text("bb"),
text("ccc"),
text("ddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig()
.Set(FlexboxConfig::Direction::Column)
.Set(FlexboxConfig::AlignItems::Center));
Screen screen(15, 5);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
" aa ff \r\n"
" bb ggg \r\n"
" ccc \r\n"
"ddddd \r\n"
" ee ");
}
TEST(FlexboxTest, AlignContentFlexEnd) {
auto root = flexbox(
{
text("aa"),
text("bb"),
text("ccc"),
text("ddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig().Set(FlexboxConfig::AlignContent::FlexEnd));
Screen screen(10, 5);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
" \r\n"
" \r\n"
"aabbccc \r\n"
"dddddeeff \r\n"
"ggg ");
}
TEST(FlexboxTest, AlignContentCenter) {
auto root = flexbox(
{
text("aa"),
text("bb"),
text("ccc"),
text("ddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig().Set(FlexboxConfig::AlignContent::Center));
Screen screen(10, 5);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
" \r\n"
"aabbccc \r\n"
"dddddeeff \r\n"
"ggg \r\n"
" ");
}
TEST(FlexboxTest, AlignContentSpaceBetween) {
auto root = flexbox(
{
text("aa"),
text("bbb"),
text("ccc"),
text("ddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig().Set(FlexboxConfig::AlignContent::SpaceBetween));
Screen screen(7, 10);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
"aabbb \r\n"
" \r\n"
" \r\n"
"ccc \r\n"
" \r\n"
" \r\n"
"dddddee\r\n"
" \r\n"
" \r\n"
"ffggg ");
}
TEST(FlexboxTest, AlignContentSpaceAround) {
auto root = flexbox(
{
text("aa"),
text("bbb"),
text("ccc"),
text("ddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig().Set(FlexboxConfig::AlignContent::SpaceAround));
Screen screen(7, 10);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
"aabbb \r\n"
" \r\n"
"ccc \r\n"
" \r\n"
" \r\n"
"dddddee\r\n"
" \r\n"
" \r\n"
"ffggg \r\n"
" ");
}
TEST(FlexboxTest, AlignContentSpaceEvenly) {
auto root = flexbox(
{
text("aa"),
text("bbb"),
text("ccc"),
text("ddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig().Set(FlexboxConfig::AlignContent::SpaceEvenly));
Screen screen(7, 10);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
" \r\n"
"aabbb \r\n"
" \r\n"
"ccc \r\n"
" \r\n"
"dddddee\r\n"
" \r\n"
"ffggg \r\n"
" \r\n"
" ");
}
TEST(FlexboxTest, GapX) {
auto root = flexbox(
{
text("aa"),
text("bbb"),
text("ccc"),
text("ddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig().SetGap(1, 0));
Screen screen(7, 10);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
"aa bbb \r\n"
"ccc \r\n"
"ddddd \r\n"
"ee ff \r\n"
"ggg \r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
" ");
}
TEST(FlexboxTest, GapX2) {
auto root = flexbox(
{
text("aa"),
text("bbb"),
text("ccc"),
text("ddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig().SetGap(2, 0));
Screen screen(7, 10);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
"aa bbb\r\n"
"ccc \r\n"
"ddddd \r\n"
"ee ff \r\n"
"ggg \r\n"
" \r\n"
" \r\n"
" \r\n"
" \r\n"
" ");
}
TEST(FlexboxTest, GapY) {
auto root = flexbox(
{
text("aa"),
text("bbb"),
text("ccc"),
text("ddddd"),
text("ee"),
text("ff"),
text("ggg"),
},
FlexboxConfig().SetGap(0, 1));
Screen screen(7, 10);
Render(screen, root);
EXPECT_EQ(screen.ToString(),
"aabbb \r\n"
" \r\n"
"ccc \r\n"
" \r\n"
"dddddee\r\n"
" \r\n"
"ffggg \r\n"
" \r\n"
" \r\n"
" ");
}
// Copyright 2021 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -1,10 +1,10 @@
#include <algorithm> // for max, min #include <algorithm> // for max, min
#include <memory> // for make_shared, shared_ptr, __shared_ptr_access #include <memory> // for make_shared, __shared_ptr_access
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector, __alloc_traits<>::value_type #include <vector> // for __alloc_traits<>::value_type
#include "ftxui/dom/elements.hpp" // for Element, unpack, focus, frame, select, xframe, yframe #include "ftxui/dom/elements.hpp" // for Element, unpack, Elements, focus, frame, select, xframe, yframe
#include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/node.hpp" // for Node, Elements
#include "ftxui/dom/requirement.hpp" // for Requirement, Requirement::FOCUSED, Requirement::SELECTED #include "ftxui/dom/requirement.hpp" // for Requirement, Requirement::FOCUSED, Requirement::SELECTED
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box
#include "ftxui/screen/screen.hpp" // for Screen, Screen::Cursor #include "ftxui/screen/screen.hpp" // for Screen, Screen::Cursor

View File

@ -1,12 +1,12 @@
#include <gtest/gtest-message.h> // for Message #include <gtest/gtest-message.h> // for Message
#include <gtest/gtest-test-part.h> // for TestPartResult #include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl, TestPartResult
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/elements.hpp" // for gauge #include "ftxui/dom/elements.hpp" // for gauge
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
#include "gtest/gtest_pred_impl.h" // for Test, SuiteApiResolver, EXPECT_EQ #include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST
using namespace ftxui; using namespace ftxui;
using namespace ftxui; using namespace ftxui;

View File

@ -5,10 +5,10 @@
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/dom/elements.hpp" // for text, operator|, Element, flex, flex_grow, Elements, flex_shrink, vtext, gridbox, vbox, border #include "ftxui/dom/elements.hpp" // for text, operator|, Element, flex, flex_grow, Elements, flex_shrink, vtext, gridbox, vbox, border
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST #include "gtest/gtest_pred_impl.h" // for Test, TEST, EXPECT_EQ
using namespace ftxui; using namespace ftxui;
@ -24,6 +24,14 @@ Element cell(const char* t) {
} }
} // namespace } // namespace
TEST(GridboxTest, UnfilledRectangular) {
auto root = gridbox({
{text("1"), text("2"), text("3"), text("4")},
{},
{},
});
}
TEST(GridboxTest, DifferentSize) { TEST(GridboxTest, DifferentSize) {
auto root = gridbox({ auto root = gridbox({
{cell("1"), cell("22"), cell("333")}, {cell("1"), cell("22"), cell("333")},

View File

@ -4,8 +4,8 @@
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/dom/elements.hpp" // for text, operator|, Element, flex_grow, flex_shrink, hbox #include "ftxui/dom/elements.hpp" // for text, operator|, Element, flex_grow, flex_shrink, hbox
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST #include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST

View File

@ -1,83 +0,0 @@
#include <algorithm> // for max
#include <memory> // for __shared_ptr_access, make_shared, shared_ptr
#include <utility> // for move
#include <vector> // for vector
#include "ftxui/dom/elements.hpp" // for Element, Elements, hflow
#include "ftxui/dom/node.hpp" // for Node
#include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/box.hpp" // for Box
namespace ftxui {
class HFlow : public Node {
public:
HFlow(Elements children) : Node(std::move(children)) {}
void ComputeRequirement() override {
requirement_.min_x = 1;
requirement_.min_y = 1;
requirement_.flex_grow_x = 1;
requirement_.flex_grow_y = 1;
requirement_.flex_shrink_x = 0;
requirement_.flex_shrink_y = 0;
for (auto& child : children_)
child->ComputeRequirement();
}
void SetBox(Box box) override {
Node::SetBox(box);
// The position of the first component.
int x = box.x_min;
int y = box.y_min;
int y_next = y; // The position of next row of elements.
for (auto& child : children_) {
Requirement requirement = child->requirement();
// Does it fit the end of the row?
if (x + requirement.min_x > box.x_max) {
// No? Use the next row.
x = box.x_min;
y = y_next;
}
// Does the current row big enough to contain the element?
if (y + requirement.min_y > box.y_max + 1)
break; // No? Ignore the element.
Box children_box;
children_box.x_min = x;
children_box.x_max = x + requirement.min_x - 1;
children_box.y_min = y;
children_box.y_max = y + requirement.min_y - 1;
child->SetBox(children_box);
x = x + requirement.min_x;
y_next = std::max(y_next, y + requirement.min_y);
}
}
};
/// @brief A container displaying elements horizontally one by one.
/// @param children The elements in the container
/// @return The container.
///
/// #### Example
///
/// ```cpp
/// hbox({
/// text("Left"),
/// text("Right"),
/// });
/// ```
Element hflow(Elements children) {
return std::make_shared<HFlow>(std::move(children));
}
} // namespace ftxui
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.

View File

@ -1,7 +1,7 @@
#include <utility> #include <utility> // for move
#include "ftxui/dom/node.hpp" #include "ftxui/dom/node.hpp"
#include "ftxui/screen/screen.hpp" #include "ftxui/screen/screen.hpp" // for Screen
namespace ftxui { namespace ftxui {
@ -29,6 +29,12 @@ void Node::Render(Screen& screen) {
child->Render(screen); child->Render(screen);
} }
void Node::Check(Status* status) {
for (auto& child : children_)
child->Check(status);
status->need_iteration |= (status->iteration == 0);
}
/// @brief Display an element on a ftxui::Screen. /// @brief Display an element on a ftxui::Screen.
/// @ingroup dom /// @ingroup dom
void Render(Screen& screen, const Element& element) { void Render(Screen& screen, const Element& element) {
@ -38,20 +44,29 @@ void Render(Screen& screen, const Element& element) {
/// @brief Display an element on a ftxui::Screen. /// @brief Display an element on a ftxui::Screen.
/// @ingroup dom /// @ingroup dom
void Render(Screen& screen, Node* node) { void Render(Screen& screen, Node* node) {
// Step 1: Find what dimension this elements wants to be.
node->ComputeRequirement();
Box box; Box box;
box.x_min = 0; box.x_min = 0;
box.y_min = 0; box.y_min = 0;
box.x_max = screen.dimx() - 1; box.x_max = screen.dimx() - 1;
box.y_max = screen.dimy() - 1; box.y_max = screen.dimy() - 1;
Node::Status status;
node->Check(&status);
while (status.need_iteration && status.iteration < 20) {
// Step 1: Find what dimension this elements wants to be.
node->ComputeRequirement();
// Step 2: Assign a dimension to the element. // Step 2: Assign a dimension to the element.
node->SetBox(box); node->SetBox(box);
screen.stencil = box;
// Check if the element needs another iteration of the layout algorithm.
status.need_iteration = false;
status.iteration++;
node->Check(&status);
}
// Step 3: Draw the element. // Step 3: Draw the element.
screen.stencil = box;
node->Render(screen); node->Render(screen);
// Step 4: Apply shaders // Step 4: Apply shaders

View File

@ -1,5 +1,5 @@
#include <memory> // for __shared_ptr_access #include <memory> // for __shared_ptr_access
#include <vector> // for __alloc_traits<>::value_type, vector #include <vector> // for __alloc_traits<>::value_type
#include "ftxui/dom/node_decorator.hpp" #include "ftxui/dom/node_decorator.hpp"
#include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/dom/requirement.hpp" // for Requirement

View File

@ -1,38 +1,71 @@
#include <sstream> // for basic_istream, wstringstream #include <sstream> // for basic_istream, stringstream
#include <string> // for allocator, char_traits, getline, operator+, wstring, basic_string #include <string> // for string, allocator, getline
#include <utility> // for move
#include "ftxui/dom/deprecated.hpp" // for text, paragraph #include "ftxui/dom/elements.hpp" // for flexbox, Element, text, Elements, operator|, xflex, paragraph, paragraphAlignCenter, paragraphAlignJustify, paragraphAlignLeft, paragraphAlignRight
#include "ftxui/dom/elements.hpp" // for Elements #include "ftxui/dom/flexbox_config.hpp" // for FlexboxConfig, FlexboxConfig::JustifyContent, FlexboxConfig::JustifyContent::Center, FlexboxConfig::JustifyContent::FlexEnd, FlexboxConfig::JustifyContent::SpaceBetween
namespace ftxui { namespace ftxui {
/// @brief Return a vector of ftxui::text for every word of the string. This is namespace {
/// useful combined with ftxui::hflow. Elements Split(std::string the_text) {
/// @param the_text The string to be splitted.
/// @ingroup dom
/// @see hflow.
Elements paragraph(std::wstring the_text) {
Elements output;
std::wstringstream ss(the_text);
std::wstring word;
while (std::getline(ss, word, L' '))
output.push_back(text(word + L' '));
return output;
}
/// @brief Return a vector of ftxui::text for every word of the string. This is
/// useful combined with ftxui::hflow.
/// @param the_text The string to be splitted.
/// @ingroup dom
/// @see hflow.
Elements paragraph(std::string the_text) {
Elements output; Elements output;
std::stringstream ss(the_text); std::stringstream ss(the_text);
std::string word; std::string word;
while (std::getline(ss, word, ' ')) while (std::getline(ss, word, ' '))
output.push_back(text(word + ' ')); output.push_back(text(word));
return output; return output;
} }
} // namespace
/// @brief Return an element drawing the paragraph on multiple lines.
/// @ingroup dom
/// @see flexbox.
Element paragraph(std::string the_text) {
return paragraphAlignLeft(std::move(the_text));
}
/// @brief Return an element drawing the paragraph on multiple lines, aligned on
/// the left.
/// @ingroup dom
/// @see flexbox.
Element paragraphAlignLeft(std::string the_text) {
static const auto config = FlexboxConfig().SetGap(1, 0);
return flexbox(Split(std::move(the_text)), config);
}
/// @brief Return an element drawing the paragraph on multiple lines, aligned on
/// the right.
/// @ingroup dom
/// @see flexbox.
Element paragraphAlignRight(std::string the_text) {
static const auto config =
FlexboxConfig().SetGap(1, 0).Set(FlexboxConfig::JustifyContent::FlexEnd);
return flexbox(Split(std::move(the_text)), config);
}
/// @brief Return an element drawing the paragraph on multiple lines, aligned on
/// the center.
/// @ingroup dom
/// @see flexbox.
Element paragraphAlignCenter(std::string the_text) {
static const auto config =
FlexboxConfig().SetGap(1, 0).Set(FlexboxConfig::JustifyContent::Center);
return flexbox(Split(std::move(the_text)), config);
}
/// @brief Return an element drawing the paragraph on multiple lines, aligned
/// using a justified alignment.
/// the center.
/// @ingroup dom
/// @see flexbox.
Element paragraphAlignJustify(std::string the_text) {
static const auto config = FlexboxConfig().SetGap(1, 0).Set(
FlexboxConfig::JustifyContent::SpaceBetween);
Elements words = Split(std::move(the_text));
words.push_back(text("") | xflex);
return flexbox(std::move(words), config);
}
} // namespace ftxui } // namespace ftxui

View File

@ -2,10 +2,10 @@
#include <algorithm> // for min, max #include <algorithm> // for min, max
#include <memory> // for make_shared, __shared_ptr_access #include <memory> // for make_shared, __shared_ptr_access
#include <utility> // for move #include <utility> // for move
#include <vector> // for __alloc_traits<>::value_type, vector #include <vector> // for __alloc_traits<>::value_type
#include "ftxui/dom/elements.hpp" // for Constraint, Direction, EQUAL, GREATER_THAN, LESS_THAN, WIDTH, unpack, Decorator, Element, size #include "ftxui/dom/elements.hpp" // for Constraint, Direction, EQUAL, GREATER_THAN, LESS_THAN, WIDTH, unpack, Decorator, Element, size
#include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/node.hpp" // for Node, Elements
#include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/box.hpp" // for Box #include "ftxui/screen/box.hpp" // for Box

View File

@ -1,6 +1,6 @@
#include <stddef.h> // for size_t #include <stddef.h> // for size_t
#include <memory> // for allocator, allocator_traits<>::value_type #include <memory> // for allocator, allocator_traits<>::value_type
#include <string> // for string #include <string> // for basic_string, string
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector, __alloc_traits<>::value_type #include <vector> // for vector, __alloc_traits<>::value_type

View File

@ -3,9 +3,9 @@
#include <memory> // for allocator #include <memory> // for allocator
#include "ftxui/dom/elements.hpp" // for LIGHT, flex, center, EMPTY, DOUBLE #include "ftxui/dom/elements.hpp" // for LIGHT, flex, center, EMPTY, DOUBLE
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/dom/table.hpp" #include "ftxui/dom/table.hpp"
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST #include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST

View File

@ -3,8 +3,8 @@
#include <string> // for allocator, string #include <string> // for allocator, string
#include "ftxui/dom/elements.hpp" // for text, operator|, border, Element #include "ftxui/dom/elements.hpp" // for text, operator|, border, Element
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST #include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST

View File

@ -1,12 +1,13 @@
#include <algorithm> // for min #include <algorithm> // for min
#include <functional> // for function #include <functional> // for function
#include <memory> // for __shared_ptr_access #include <memory> // for __shared_ptr_access, make_unique
#include <utility> // for move #include <utility> // for move
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/dom/elements.hpp" // for Element, Decorator, Elements, operator|, Fit, nothing #include "ftxui/dom/elements.hpp" // for Element, Decorator, Elements, operator|, Fit, emptyElement, nothing
#include "ftxui/dom/node.hpp" // for Node #include "ftxui/dom/node.hpp" // for Node, Node::Status
#include "ftxui/dom/requirement.hpp" // for Requirement #include "ftxui/dom/requirement.hpp" // for Requirement
#include "ftxui/screen/box.hpp" // for Box
#include "ftxui/screen/screen.hpp" // for Full #include "ftxui/screen/screen.hpp" // for Full
#include "ftxui/screen/terminal.hpp" // for Dimensions #include "ftxui/screen/terminal.hpp" // for Dimensions
@ -69,10 +70,39 @@ Element operator|(Element element, Decorator decorator) {
/// @see Fixed /// @see Fixed
/// @see Full /// @see Full
Dimensions Dimension::Fit(Element& e) { Dimensions Dimension::Fit(Element& e) {
Dimensions fullsize = Dimension::Full();
Box box;
box.x_min = 0;
box.y_min = 0;
box.x_max = fullsize.dimx;
box.y_max = fullsize.dimy;
Node::Status status;
e->Check(&status);
while (status.need_iteration && status.iteration < 20) {
e->ComputeRequirement(); e->ComputeRequirement();
Dimensions size = Dimension::Full();
return {std::min(e->requirement().min_x, size.dimx), // Don't give the element more space than it needs:
std::min(e->requirement().min_y, size.dimy)}; box.x_max = std::min(box.x_max, e->requirement().min_x);
box.y_max = std::min(box.y_max, e->requirement().min_y);
e->SetBox(box);
status.need_iteration = false;
status.iteration++;
e->Check(&status);
if (!status.need_iteration)
break;
// Increase the size of the box until it fits, but not more than the with of
// the terminal emulator:
box.x_max = std::min(e->requirement().min_x, fullsize.dimx);
box.y_max = std::min(e->requirement().min_y, fullsize.dimy);
}
return {
box.x_max,
box.y_max,
};
} }
/// An element of size 0x0 drawing nothing. /// An element of size 0x0 drawing nothing.

View File

@ -5,8 +5,8 @@
#include <vector> // for vector #include <vector> // for vector
#include "ftxui/dom/elements.hpp" // for vtext, operator|, Element, flex_grow, flex_shrink, vbox #include "ftxui/dom/elements.hpp" // for vtext, operator|, Element, flex_grow, flex_shrink, vbox
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
#include "ftxui/dom/node.hpp" // for Render #include "ftxui/dom/node.hpp" // for Render
#include "ftxui/screen/box.hpp" // for ftxui
#include "ftxui/screen/screen.hpp" // for Screen #include "ftxui/screen/screen.hpp" // for Screen
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST #include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST

View File

@ -24,6 +24,19 @@ bool Box::Contain(int x, int y) {
y_max >= y; y_max >= y;
} }
/// @return whether |other| is the same as |this|
/// @ingroup screen
bool Box::operator==(const Box& other) const {
return (x_min == other.x_min) && (x_max == other.x_max) &&
(y_min == other.y_min) && (y_max == other.y_max);
}
/// @return whether |other| and |this| are different.
/// @ingroup screen
bool Box::operator!=(const Box& other) const {
return !operator==(other);
}
} // namespace ftxui } // namespace ftxui
// Copyright 2020 Arthur Sonzogni. All rights reserved. // Copyright 2020 Arthur Sonzogni. All rights reserved.