mirror of
				https://github.com/ArthurSonzogni/FTXUI.git
				synced 2025-11-04 13:38:14 +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