mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-18 00:48:09 +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:
@@ -1,9 +1,9 @@
|
||||
#include <benchmark/benchmark.h>
|
||||
|
||||
#include "ftxui/dom/elements.hpp" // for separator, gauge, operator|, text, Element, blink, inverted, hbox, vbox, border
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/box.hpp" // for ftxui
|
||||
#include "ftxui/screen/screen.hpp" // for Screen
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#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-message.h> // for Message
|
||||
#include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl, TestPartResult
|
||||
#include <memory> // for allocator
|
||||
|
||||
#include "ftxui/dom/elements.hpp" // for gauge
|
||||
#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 "ftxui/dom/elements.hpp" // for gauge
|
||||
#include "ftxui/dom/flexbox_config.hpp" // for 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;
|
||||
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/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 "ftxui/dom/flexbox_config.hpp" // for ftxui
|
||||
#include "ftxui/dom/node.hpp" // for Render
|
||||
#include "ftxui/screen/screen.hpp" // for Screen
|
||||
#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,10 +4,10 @@
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/dom/elements.hpp" // for text, operator|, Element, flex_grow, flex_shrink, hbox
|
||||
#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 "ftxui/dom/flexbox_config.hpp" // for 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;
|
||||
using namespace ftxui;
|
||||
|
@@ -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;
|
||||
|
||||
// Step 2: Assign a dimension to the element.
|
||||
node->SetBox(box);
|
||||
screen.stencil = box;
|
||||
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);
|
||||
|
||||
// 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/node.hpp" // for Render
|
||||
#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
|
||||
|
||||
|
@@ -2,11 +2,11 @@
|
||||
#include <gtest/gtest-test-part.h> // for SuiteApiResolver, TestFactoryImpl, TestPartResult
|
||||
#include <string> // for allocator, string
|
||||
|
||||
#include "ftxui/dom/elements.hpp" // for text, operator|, border, Element
|
||||
#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 "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/screen.hpp" // for Screen
|
||||
#include "gtest/gtest_pred_impl.h" // for Test, EXPECT_EQ, TEST
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
|
@@ -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) {
|
||||
e->ComputeRequirement();
|
||||
Dimensions size = Dimension::Full();
|
||||
return {std::min(e->requirement().min_x, size.dimx),
|
||||
std::min(e->requirement().min_y, size.dimy)};
|
||||
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();
|
||||
|
||||
// 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,10 +5,10 @@
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/dom/elements.hpp" // for vtext, operator|, Element, flex_grow, flex_shrink, vbox
|
||||
#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 "ftxui/dom/flexbox_config.hpp" // for 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;
|
||||
|
||||
|
Reference in New Issue
Block a user