mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-22 18:59:59 +08:00
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:
parent
f7c6bf91a7
commit
602392c43d
20
CHANGELOG.md
20
CHANGELOG.md
@ -4,8 +4,24 @@ Changelog
|
||||
unreleased (development)
|
||||
------------------------
|
||||
|
||||
# Component:
|
||||
- Bugfix: Input shouldn't take focus when hovered by the mouse.
|
||||
### Features:
|
||||
- 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
|
||||
------
|
||||
|
@ -38,6 +38,7 @@ add_library(screen
|
||||
|
||||
add_library(dom
|
||||
include/ftxui/dom/elements.hpp
|
||||
include/ftxui/dom/flexbox_config.hpp
|
||||
include/ftxui/dom/node.hpp
|
||||
include/ftxui/dom/requirement.hpp
|
||||
include/ftxui/dom/take_any_args.hpp
|
||||
@ -52,12 +53,15 @@ add_library(dom
|
||||
src/ftxui/dom/dbox.cpp
|
||||
src/ftxui/dom/dim.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/gauge.cpp
|
||||
src/ftxui/dom/graph.cpp
|
||||
src/ftxui/dom/gridbox.cpp
|
||||
src/ftxui/dom/hbox.cpp
|
||||
src/ftxui/dom/hflow.cpp
|
||||
src/ftxui/dom/inverted.cpp
|
||||
src/ftxui/dom/node.cpp
|
||||
src/ftxui/dom/node_decorator.cpp
|
||||
|
@ -19,10 +19,12 @@ add_executable(tests
|
||||
src/ftxui/component/screen_interactive_test.cpp
|
||||
src/ftxui/component/terminal_input_parser_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/table_test.cpp
|
||||
src/ftxui/dom/gridbox_test.cpp
|
||||
src/ftxui/dom/hbox_test.cpp
|
||||
src/ftxui/dom/table_test.cpp
|
||||
src/ftxui/dom/text_test.cpp
|
||||
src/ftxui/dom/vbox_test.cpp
|
||||
src/ftxui/screen/string_test.cpp
|
||||
|
@ -5,6 +5,7 @@ example(checkbox)
|
||||
example(checkbox_in_frame)
|
||||
example(composition)
|
||||
example(dropdown)
|
||||
example(flexbox)
|
||||
example(gallery)
|
||||
example(homescreen)
|
||||
example(input)
|
||||
|
@ -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/dom/elements.hpp"
|
||||
#include "ftxui/component/component.hpp"
|
||||
#include "ftxui/dom/elements.hpp" // for operator|, Element, size, border, frame, vscroll_indicator, HEIGHT, LESS_THAN
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
@ -19,3 +25,7 @@ int main(int argc, const char* argv[]) {
|
||||
auto screen = ScreenInteractive::TerminalOutput();
|
||||
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.
|
||||
|
192
examples/component/flexbox.cpp
Normal file
192
examples/component/flexbox.cpp
Normal 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.
|
@ -1,27 +1,33 @@
|
||||
#include <stddef.h> // for size_t
|
||||
#include <array> // for array
|
||||
#include <chrono> // for operator""s, chrono_literals
|
||||
#include <cmath> // for sin
|
||||
#include <functional> // for ref, reference_wrapper, function
|
||||
#include <memory> // for allocator, shared_ptr, __shared_ptr_access
|
||||
#include <string> // for 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 <utility> // for move
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/component/captured_mouse.hpp" // for ftxui
|
||||
#include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Menu, Radiobox, Tab, Toggle
|
||||
#include "ftxui/component/component.hpp" // for Checkbox, Renderer, Horizontal, Vertical, Input, Menu, Radiobox, ResizableSplitLeft, Tab, Toggle
|
||||
#include "ftxui/component/component_base.hpp" // for ComponentBase
|
||||
#include "ftxui/component/component_options.hpp" // for InputOption
|
||||
#include "ftxui/component/event.hpp" // for Event, Event::Custom
|
||||
#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/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/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::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;
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
auto screen = ScreenInteractive::Fullscreen();
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// HTOP
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int shift = 0;
|
||||
|
||||
auto my_graph = [&shift](int width, int height) {
|
||||
@ -92,6 +98,10 @@ int main(int argc, const char* argv[]) {
|
||||
flex | border;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Compiler
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
const std::vector<std::string> compiler_entries = {
|
||||
"gcc",
|
||||
"clang",
|
||||
@ -248,6 +258,9 @@ int main(int argc, const char* argv[]) {
|
||||
flex_grow | border;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Spiner
|
||||
// ---------------------------------------------------------------------------
|
||||
auto spinner_tab_renderer = Renderer([&] {
|
||||
Elements entries;
|
||||
for (int i = 0; i < 22; ++i) {
|
||||
@ -257,6 +270,9 @@ int main(int argc, const char* argv[]) {
|
||||
return hflow(std::move(entries)) | border;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Colors
|
||||
// ---------------------------------------------------------------------------
|
||||
auto color_tab_renderer = Renderer([] {
|
||||
return hbox({
|
||||
vbox({
|
||||
@ -301,6 +317,9 @@ int main(int argc, const char* argv[]) {
|
||||
hcenter | border;
|
||||
});
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Gauges
|
||||
// ---------------------------------------------------------------------------
|
||||
auto render_gauge = [&shift](int delta) {
|
||||
float progress = (shift + delta) % 1000 / 1000.f;
|
||||
return hbox({
|
||||
@ -333,9 +352,84 @@ int main(int argc, const char* argv[]) {
|
||||
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,
|
||||
¶graph_renderer_split_position);
|
||||
auto paragraph_renderer_group_renderer =
|
||||
Renderer(paragraph_renderer_group,
|
||||
[&] { return paragraph_renderer_group->Render() | border; });
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// Tabs
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
int tab_index = 0;
|
||||
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_content = Container::Tab(
|
||||
@ -345,6 +439,7 @@ int main(int argc, const char* argv[]) {
|
||||
spinner_tab_renderer,
|
||||
gauge_component,
|
||||
compiler_renderer,
|
||||
paragraph_renderer_group_renderer,
|
||||
},
|
||||
&tab_index);
|
||||
|
||||
|
@ -11,6 +11,7 @@ example(gauge)
|
||||
example(graph)
|
||||
example(gridbox)
|
||||
example(hflow)
|
||||
example(vflow)
|
||||
example(html_like)
|
||||
example(package_manager)
|
||||
example(paragraph)
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include <ftxui/dom/elements.hpp> // for text, operator|, vbox, border, Element, Fit, hbox
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <iostream>
|
||||
#include <ftxui/dom/elements.hpp> // for operator|, text, Element, Fit, borderDouble, borderHeavy, borderLight, borderRounded, vbox
|
||||
#include <ftxui/screen/screen.hpp> // for Screen
|
||||
#include <iostream> // for endl, cout, ostream
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include <utility> // for move
|
||||
#include <vector> // for vector, allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
#include "ftxui/screen/color.hpp" // for Color, Color::Palette256
|
||||
|
||||
using namespace ftxui;
|
||||
|
@ -3,8 +3,8 @@
|
||||
#include <memory> // for allocator
|
||||
#include <utility> // for move
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
#include "ftxui/screen/color.hpp" // for Color
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
@ -3,8 +3,8 @@
|
||||
#include <memory> // for allocator
|
||||
#include <utility> // for move
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
#include "ftxui/screen/color.hpp" // for Color
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -5,8 +5,8 @@
|
||||
#include <string> // for allocator, operator+, char_traits, operator<<, string, to_string, basic_string
|
||||
#include <thread> // for sleep_for
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -1,16 +1,16 @@
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <ftxui/dom/elements.hpp>
|
||||
#include <ftxui/screen/screen.hpp>
|
||||
#include <functional>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#include <chrono> // for operator""s, chrono_literals
|
||||
#include <cmath> // for sin
|
||||
#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> // for Full, Screen
|
||||
#include <functional> // for ref, reference_wrapper
|
||||
#include <iostream> // for cout, ostream
|
||||
#include <string> // for operator<<, string
|
||||
#include <thread> // for sleep_for
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/dom/node.hpp"
|
||||
#include "ftxui/screen/box.hpp"
|
||||
#include "ftxui/screen/color.hpp"
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/color.hpp" // for Color, Color::BlueLight, Color::RedLight, Color::YellowLight
|
||||
|
||||
class Graph {
|
||||
public:
|
||||
|
@ -1,10 +1,10 @@
|
||||
#include <stdio.h> // for getchar
|
||||
#include <ftxui/dom/elements.hpp> // for filler, text, hbox, vbox
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
#include <ftxui/dom/elements.hpp> // for Elements, gridbox, Fit, operator|, text, border, Element
|
||||
#include <ftxui/screen/screen.hpp> // for Screen
|
||||
#include <memory> // for allocator, shared_ptr
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -1,11 +1,12 @@
|
||||
#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/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
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
@ -44,6 +45,7 @@ int main(int argc, const char* argv[]) {
|
||||
auto screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
|
||||
Render(screen, document);
|
||||
screen.Print();
|
||||
getchar();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -44,7 +44,7 @@ int main(int argc, const char* argv[]) {
|
||||
paragraph(" A spinner "), spinner(6, i / 10)) |
|
||||
border;
|
||||
|
||||
auto screen = Screen::Create(Dimension::Full());
|
||||
auto screen = Screen::Create(Dimension::Fit(document));
|
||||
Render(screen, document);
|
||||
std::cout << reset_position;
|
||||
screen.Print();
|
||||
|
@ -9,8 +9,8 @@
|
||||
#include <utility> // for move
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#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
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
@ -1,35 +1,50 @@
|
||||
#include <stdio.h> // for getchar
|
||||
#include <ftxui/dom/elements.hpp> // for operator|, hflow, paragraph, border, Element, hbox, flex, vbox
|
||||
#include <chrono> // for operator""s, chrono_literals
|
||||
#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/screen/box.hpp" // for ftxui
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
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.)";
|
||||
|
||||
std::string reset_position;
|
||||
for (int i = 0;; ++i) {
|
||||
auto document = vbox({
|
||||
hflow(paragraph(p)),
|
||||
separator(),
|
||||
hflow(paragraph(p)),
|
||||
separator(),
|
||||
hbox({
|
||||
hflow(paragraph(p)) | border,
|
||||
hflow(paragraph(p)) | border,
|
||||
hflow(paragraph(p)) | border,
|
||||
}) | flex,
|
||||
hbox({
|
||||
hflow(paragraph(p)) | border,
|
||||
hflow(paragraph(p)) | border,
|
||||
}) | flex,
|
||||
hbox({
|
||||
hflow(paragraph(p)) | border,
|
||||
}) | flex,
|
||||
});
|
||||
hflow(paragraph(p)),
|
||||
separator(),
|
||||
hflow(paragraph(p)),
|
||||
}),
|
||||
}) |
|
||||
border;
|
||||
|
||||
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);
|
||||
std::cout << reset_position;
|
||||
screen.Print();
|
||||
getchar();
|
||||
reset_position = screen.ResetPosition();
|
||||
|
||||
std::this_thread::sleep_for(0.01s);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include <string> // for string, to_string
|
||||
#include <utility> // for move
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -7,8 +7,8 @@
|
||||
#include <utility> // for move
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
#include "ftxui/screen/color.hpp" // for Color, Color::Blue
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -2,8 +2,8 @@
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
@ -5,8 +5,8 @@
|
||||
#include <string> // for basic_string, allocator, string
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#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
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
|
@ -3,8 +3,8 @@
|
||||
#include <ftxui/screen/screen.hpp> // for Full, Screen
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
|
||||
int main(int argc, const char* argv[]) {
|
||||
using namespace ftxui;
|
||||
|
52
examples/dom/vflow.cpp
Normal file
52
examples/dom/vflow.cpp
Normal 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.
|
@ -1,10 +1,10 @@
|
||||
#include <ftxui/dom/elements.hpp>
|
||||
#include <ftxui/screen/screen.hpp>
|
||||
#include <vector>
|
||||
#include <ftxui/dom/elements.hpp> // for operator|, color, Element, bgcolor, graph, border
|
||||
#include <ftxui/screen/screen.hpp> // for Fixed, Screen
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/dom/node.hpp"
|
||||
#include "ftxui/screen/box.hpp"
|
||||
#include "ftxui/screen/color.hpp"
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/color.hpp" // for Color, Color::DarkBlue, Color::Green, Color::Red
|
||||
|
||||
int main(void) {
|
||||
using namespace ftxui;
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
#include "ftxui/dom/flexbox_config.hpp"
|
||||
#include "ftxui/dom/node.hpp"
|
||||
#include "ftxui/screen/box.hpp"
|
||||
#include "ftxui/screen/color.hpp"
|
||||
@ -49,7 +50,11 @@ Decorator borderStyled(BorderStyle);
|
||||
Decorator borderWith(Pixel);
|
||||
Element window(Element title, Element content);
|
||||
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 emptyElement();
|
||||
|
||||
@ -69,8 +74,11 @@ Element bgcolor(Color, Element);
|
||||
Element hbox(Elements);
|
||||
Element vbox(Elements);
|
||||
Element dbox(Elements);
|
||||
Element flexbox(Elements, FlexboxConfig config = FlexboxConfig());
|
||||
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 ---
|
||||
// Define how to share the remaining space when not all of it is used inside a
|
||||
|
115
include/ftxui/dom/flexbox_config.hpp
Normal file
115
include/ftxui/dom/flexbox_config.hpp
Normal 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 aren’t 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 container’s 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.
|
@ -35,6 +35,15 @@ class Node {
|
||||
// Step 3: Draw this element.
|
||||
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:
|
||||
Elements children_;
|
||||
Requirement requirement_;
|
||||
|
@ -28,7 +28,7 @@ struct Requirement {
|
||||
|
||||
} // 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.
|
||||
// Use of this source code is governed by the MIT license that can be found in
|
||||
|
@ -11,6 +11,8 @@ struct Box {
|
||||
|
||||
static Box Intersection(Box a, Box b);
|
||||
bool Contain(int x, int y);
|
||||
bool operator==(const Box& other) const;
|
||||
bool operator!=(const Box& other) const;
|
||||
};
|
||||
|
||||
} // namespace ftxui
|
||||
|
25
iwyu.imp
25
iwyu.imp
@ -1,12 +1,17 @@
|
||||
[
|
||||
{ symbol: [ "char_traits", private, "<string>", public ] },
|
||||
{ symbol: [ "ECHO", private, "<termios.h>", public ] },
|
||||
{ symbol: [ "ICANON", private, "<termios.h>", 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 ] },
|
||||
{ include: ["<ext/alloc_traits.h>", private, "<vector>", public] },
|
||||
{ include: ["<bits/termios-c_cc.h>", "private", "<termios.h>", "public"]},
|
||||
{ include: ["<bits/termios-c_lflag.h>", "private", "<termios.h>", "public"]},
|
||||
{ include: ["<bits/termios-struct.h>", "private", "<termios.h>", "public"]},
|
||||
{ include: ["<bits/termios-tcflow.h>", "private", "<termios.h>", "public"]},
|
||||
{ include: ["<ext/alloc_traits.h>", "private", "<vector>", "public"] },
|
||||
{ symbol: [ "ftxui", "private", "", "public" ] },
|
||||
{ symbol: [ "char_traits", "private", "<string>", "public" ] },
|
||||
{ symbol: [ "ECHO", "private", "<termios.h>", "public" ] },
|
||||
{ symbol: [ "ICANON", "private", "<termios.h>", "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" ] },
|
||||
]
|
||||
|
@ -1,5 +1,5 @@
|
||||
#include <stddef.h> // for size_t
|
||||
#include <algorithm> // for find_if, max
|
||||
#include <algorithm> // for find_if
|
||||
#include <cassert> // for assert
|
||||
#include <iterator> // for begin, end
|
||||
#include <utility> // for move
|
||||
@ -7,7 +7,7 @@
|
||||
|
||||
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface
|
||||
#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/screen_interactive.hpp" // for Component, ScreenInteractive
|
||||
#include "ftxui/dom/elements.hpp" // for text, Element
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
#include "ftxui/component/component.hpp" // for Horizontal, Vertical, Tab
|
||||
#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/dom/elements.hpp" // for text, Elements, operator|, reflect, Element, hbox, vbox
|
||||
#include "ftxui/screen/box.hpp" // for Box
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include <cmath>
|
||||
#include <algorithm> // for max, min
|
||||
#include <memory> // for __shared_ptr_access
|
||||
#include <string> // for string
|
||||
#include <utility> // for move
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include <iostream> // for cout, ostream, basic_ostream, operator<<, endl, flush
|
||||
#include <stack> // for stack
|
||||
#include <thread> // for thread
|
||||
#include <utility> // for move
|
||||
#include <utility> // for swap, move
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse, CapturedMouseInterface
|
||||
@ -18,7 +18,7 @@
|
||||
#include "ftxui/component/terminal_input_parser.hpp" // for TerminalInputParser
|
||||
#include "ftxui/dom/node.hpp" // for Node, Render
|
||||
#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)
|
||||
#define DEFINE_CONSOLEV2_PROPERTIES
|
||||
@ -32,7 +32,7 @@
|
||||
#endif
|
||||
#else
|
||||
#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
|
||||
#endif
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#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/screen/box.hpp" // for ftxui
|
||||
#include "ftxui/screen/screen.hpp" // for Screen
|
||||
|
||||
using namespace ftxui;
|
||||
|
@ -23,7 +23,6 @@ class Blink : public NodeDecorator {
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/// @brief The text drawn alternates in between visible and hidden.
|
||||
/// @ingroup dom
|
||||
Element blink(Element child) {
|
||||
|
@ -1,12 +1,12 @@
|
||||
#include <algorithm> // for max
|
||||
#include <iterator> // for begin, end
|
||||
#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 <vector> // for vector, __alloc_traits<>::value_type
|
||||
|
||||
#include "ftxui/dom/elements.hpp" // for unpack, Element, Decorator, Elements, border, borderWith, window
|
||||
#include "ftxui/dom/node.hpp" // for Node
|
||||
#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, Elements
|
||||
#include "ftxui/dom/requirement.hpp" // for Requirement
|
||||
#include "ftxui/screen/box.hpp" // for Box
|
||||
#include "ftxui/screen/screen.hpp" // for Pixel, Screen
|
||||
|
@ -25,4 +25,4 @@ void Compute(std::vector<Element>* elements, int target_size);
|
||||
|
||||
// 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.
|
||||
// the LICENSE file.line.
|
||||
|
@ -1,9 +1,9 @@
|
||||
#include <memory> // for make_shared, __shared_ptr_access
|
||||
#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/node.hpp" // for Node
|
||||
#include "ftxui/dom/node.hpp" // for Elements, Node
|
||||
#include "ftxui/dom/requirement.hpp" // for Requirement
|
||||
#include "ftxui/screen/box.hpp" // for Box
|
||||
|
||||
|
239
src/ftxui/dom/flexbox.cpp
Normal file
239
src/ftxui/dom/flexbox.cpp
Normal 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.
|
40
src/ftxui/dom/flexbox_config.cpp
Normal file
40
src/ftxui/dom/flexbox_config.cpp
Normal 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.
|
325
src/ftxui/dom/flexbox_helper.cpp
Normal file
325
src/ftxui/dom/flexbox_helper.cpp
Normal 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.
|
45
src/ftxui/dom/flexbox_helper.hpp
Normal file
45
src/ftxui/dom/flexbox_helper.hpp
Normal 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.
|
233
src/ftxui/dom/flexbox_helper_test.cpp
Normal file
233
src/ftxui/dom/flexbox_helper_test.cpp
Normal 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.
|
437
src/ftxui/dom/flexbox_test.cpp
Normal file
437
src/ftxui/dom/flexbox_test.cpp
Normal 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.
|
@ -1,10 +1,10 @@
|
||||
#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 <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/node.hpp" // for Node
|
||||
#include "ftxui/dom/elements.hpp" // for Element, unpack, Elements, focus, frame, select, xframe, yframe
|
||||
#include "ftxui/dom/node.hpp" // for Node, Elements
|
||||
#include "ftxui/dom/requirement.hpp" // for Requirement, Requirement::FOCUSED, Requirement::SELECTED
|
||||
#include "ftxui/screen/box.hpp" // for Box
|
||||
#include "ftxui/screen/screen.hpp" // for Screen, Screen::Cursor
|
||||
|
@ -1,12 +1,12 @@
|
||||
#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 "ftxui/dom/elements.hpp" // for gauge
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
#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;
|
||||
|
@ -5,10 +5,10 @@
|
||||
#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/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
#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;
|
||||
|
||||
@ -24,6 +24,14 @@ Element cell(const char* t) {
|
||||
}
|
||||
} // namespace
|
||||
|
||||
TEST(GridboxTest, UnfilledRectangular) {
|
||||
auto root = gridbox({
|
||||
{text("1"), text("2"), text("3"), text("4")},
|
||||
{},
|
||||
{},
|
||||
});
|
||||
}
|
||||
|
||||
TEST(GridboxTest, DifferentSize) {
|
||||
auto root = gridbox({
|
||||
{cell("1"), cell("22"), cell("333")},
|
||||
|
@ -4,8 +4,8 @@
|
||||
#include <vector> // for vector
|
||||
|
||||
#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/screen/box.hpp" // for ftxui
|
||||
#include "ftxui/screen/screen.hpp" // for Screen
|
||||
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST
|
||||
|
||||
|
@ -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.
|
@ -1,7 +1,7 @@
|
||||
#include <utility>
|
||||
#include <utility> // for move
|
||||
|
||||
#include "ftxui/dom/node.hpp"
|
||||
#include "ftxui/screen/screen.hpp"
|
||||
#include "ftxui/screen/screen.hpp" // for Screen
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
@ -29,6 +29,12 @@ void Node::Render(Screen& 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.
|
||||
/// @ingroup dom
|
||||
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.
|
||||
/// @ingroup dom
|
||||
void Render(Screen& screen, Node* node) {
|
||||
// Step 1: Find what dimension this elements wants to be.
|
||||
node->ComputeRequirement();
|
||||
|
||||
Box box;
|
||||
box.x_min = 0;
|
||||
box.y_min = 0;
|
||||
box.x_max = screen.dimx() - 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.
|
||||
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.
|
||||
screen.stencil = box;
|
||||
node->Render(screen);
|
||||
|
||||
// Step 4: Apply shaders
|
||||
|
@ -1,5 +1,5 @@
|
||||
#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/requirement.hpp" // for Requirement
|
||||
|
@ -1,38 +1,71 @@
|
||||
#include <sstream> // for basic_istream, wstringstream
|
||||
#include <string> // for allocator, char_traits, getline, operator+, wstring, basic_string
|
||||
#include <sstream> // for basic_istream, stringstream
|
||||
#include <string> // for string, allocator, getline
|
||||
#include <utility> // for move
|
||||
|
||||
#include "ftxui/dom/deprecated.hpp" // for text, paragraph
|
||||
#include "ftxui/dom/elements.hpp" // for Elements
|
||||
#include "ftxui/dom/elements.hpp" // for flexbox, Element, text, Elements, operator|, xflex, paragraph, paragraphAlignCenter, paragraphAlignJustify, paragraphAlignLeft, paragraphAlignRight
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for FlexboxConfig, FlexboxConfig::JustifyContent, FlexboxConfig::JustifyContent::Center, FlexboxConfig::JustifyContent::FlexEnd, FlexboxConfig::JustifyContent::SpaceBetween
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
/// @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::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) {
|
||||
namespace {
|
||||
Elements Split(std::string the_text) {
|
||||
Elements output;
|
||||
std::stringstream ss(the_text);
|
||||
std::string word;
|
||||
while (std::getline(ss, word, ' '))
|
||||
output.push_back(text(word + ' '));
|
||||
output.push_back(text(word));
|
||||
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
|
||||
|
||||
|
@ -2,10 +2,10 @@
|
||||
#include <algorithm> // for min, max
|
||||
#include <memory> // for make_shared, __shared_ptr_access
|
||||
#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/node.hpp" // for Node
|
||||
#include "ftxui/dom/node.hpp" // for Node, Elements
|
||||
#include "ftxui/dom/requirement.hpp" // for Requirement
|
||||
#include "ftxui/screen/box.hpp" // for Box
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <stddef.h> // for size_t
|
||||
#include <memory> // for allocator, allocator_traits<>::value_type
|
||||
#include <string> // for string
|
||||
#include <string> // for basic_string, string
|
||||
#include <utility> // for move
|
||||
#include <vector> // for vector, __alloc_traits<>::value_type
|
||||
|
||||
|
@ -3,9 +3,9 @@
|
||||
#include <memory> // for allocator
|
||||
|
||||
#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/table.hpp"
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
#include "ftxui/screen/screen.hpp" // for Screen
|
||||
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST
|
||||
|
||||
|
@ -3,8 +3,8 @@
|
||||
#include <string> // for allocator, string
|
||||
|
||||
#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/screen/box.hpp" // for ftxui
|
||||
#include "ftxui/screen/screen.hpp" // for Screen
|
||||
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST
|
||||
|
||||
|
@ -1,12 +1,13 @@
|
||||
#include <algorithm> // for min
|
||||
#include <functional> // for function
|
||||
#include <memory> // for __shared_ptr_access
|
||||
#include <memory> // for __shared_ptr_access, make_unique
|
||||
#include <utility> // for move
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/dom/elements.hpp" // for Element, Decorator, Elements, operator|, Fit, nothing
|
||||
#include "ftxui/dom/node.hpp" // for Node
|
||||
#include "ftxui/dom/elements.hpp" // for Element, Decorator, Elements, operator|, Fit, emptyElement, nothing
|
||||
#include "ftxui/dom/node.hpp" // for Node, Node::Status
|
||||
#include "ftxui/dom/requirement.hpp" // for Requirement
|
||||
#include "ftxui/screen/box.hpp" // for Box
|
||||
#include "ftxui/screen/screen.hpp" // for Full
|
||||
#include "ftxui/screen/terminal.hpp" // for Dimensions
|
||||
|
||||
@ -69,10 +70,39 @@ Element operator|(Element element, Decorator decorator) {
|
||||
/// @see Fixed
|
||||
/// @see Full
|
||||
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();
|
||||
Dimensions size = Dimension::Full();
|
||||
return {std::min(e->requirement().min_x, size.dimx),
|
||||
std::min(e->requirement().min_y, size.dimy)};
|
||||
|
||||
// Don't give the element more space than it needs:
|
||||
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.
|
||||
|
@ -5,8 +5,8 @@
|
||||
#include <vector> // for vector
|
||||
|
||||
#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/screen/box.hpp" // for ftxui
|
||||
#include "ftxui/screen/screen.hpp" // for Screen
|
||||
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST
|
||||
|
||||
|
@ -24,6 +24,19 @@ bool Box::Contain(int x, int 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
|
||||
|
||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||
|
Loading…
Reference in New Issue
Block a user