mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2025-09-17 16:38:09 +08:00
@@ -14,10 +14,11 @@
|
||||
namespace ftxui {
|
||||
|
||||
static std::string simple_border_charset[6][6] = {
|
||||
{"┌", "┐", "└", "┘", "─", "│"},
|
||||
{"┏", "┓", "┗", "┛", "━", "┃"},
|
||||
{"╔", "╗", "╚", "╝", "═", "║"},
|
||||
{"╭", "╮", "╰", "╯", "─", "│"},
|
||||
{"┌", "┐", "└", "┘", "─", "│"}, //
|
||||
{"┏", "┓", "┗", "┛", "━", "┃"}, //
|
||||
{"╔", "╗", "╚", "╝", "═", "║"}, //
|
||||
{"╭", "╮", "╰", "╯", "─", "│"}, //
|
||||
{" ", " ", " ", " ", " ", " "}, //
|
||||
};
|
||||
|
||||
// For reference, here is the charset for normal border:
|
||||
@@ -124,6 +125,7 @@ class Border : public Node {
|
||||
/// @see borderLight
|
||||
/// @see borderDouble
|
||||
/// @see borderHeavy
|
||||
/// @see borderEmpty
|
||||
/// @see borderRounded
|
||||
///
|
||||
/// Add a border around an element
|
||||
@@ -174,6 +176,7 @@ Decorator borderStyled(BorderStyle style) {
|
||||
/// @see borderDouble
|
||||
/// @see borderHeavy
|
||||
/// @see borderRounded
|
||||
/// @see borderEmpty
|
||||
/// @see borderStyled
|
||||
/// @see borderWith
|
||||
///
|
||||
@@ -192,9 +195,9 @@ Decorator borderStyled(BorderStyle style) {
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// ┌──────────────┐
|
||||
/// │The element │
|
||||
/// └──────────────┘
|
||||
/// ┌──────────────┐
|
||||
/// │The element │
|
||||
/// └──────────────┘
|
||||
/// ```
|
||||
Element borderLight(Element child) {
|
||||
return std::make_shared<Border>(unpack(std::move(child)), LIGHT);
|
||||
@@ -207,6 +210,7 @@ Element borderLight(Element child) {
|
||||
/// @see borderDouble
|
||||
/// @see borderHeavy
|
||||
/// @see borderRounded
|
||||
/// @see borderEmpty
|
||||
/// @see borderStyled
|
||||
/// @see borderWith
|
||||
///
|
||||
@@ -225,9 +229,9 @@ Element borderLight(Element child) {
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// ┏━━━━━━━━━━━━━━┓
|
||||
/// ┃The element ┃
|
||||
/// ┗━━━━━━━━━━━━━━┛
|
||||
/// ┏━━━━━━━━━━━━━━┓
|
||||
/// ┃The element ┃
|
||||
/// ┗━━━━━━━━━━━━━━┛
|
||||
/// ```
|
||||
Element borderHeavy(Element child) {
|
||||
return std::make_shared<Border>(unpack(std::move(child)), HEAVY);
|
||||
@@ -240,6 +244,7 @@ Element borderHeavy(Element child) {
|
||||
/// @see borderDouble
|
||||
/// @see borderHeavy
|
||||
/// @see borderRounded
|
||||
/// @see borderEmpty
|
||||
/// @see borderStyled
|
||||
/// @see borderWith
|
||||
///
|
||||
@@ -258,9 +263,9 @@ Element borderHeavy(Element child) {
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// ╔══════════════╗
|
||||
/// ║The element ║
|
||||
/// ╚══════════════╝
|
||||
/// ╔══════════════╗
|
||||
/// ║The element ║
|
||||
/// ╚══════════════╝
|
||||
/// ```
|
||||
Element borderDouble(Element child) {
|
||||
return std::make_shared<Border>(unpack(std::move(child)), DOUBLE);
|
||||
@@ -273,6 +278,7 @@ Element borderDouble(Element child) {
|
||||
/// @see borderDouble
|
||||
/// @see borderHeavy
|
||||
/// @see borderRounded
|
||||
/// @see borderEmpty
|
||||
/// @see borderStyled
|
||||
/// @see borderWith
|
||||
///
|
||||
@@ -291,14 +297,48 @@ Element borderDouble(Element child) {
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// ╭──────────────╮
|
||||
/// │The element │
|
||||
/// ╰──────────────╯
|
||||
/// ╭──────────────╮
|
||||
/// │The element │
|
||||
/// ╰──────────────╯
|
||||
/// ```
|
||||
Element borderRounded(Element child) {
|
||||
return std::make_shared<Border>(unpack(std::move(child)), ROUNDED);
|
||||
}
|
||||
|
||||
/// @brief Draw an empty border around the element.
|
||||
/// @ingroup dom
|
||||
/// @see border
|
||||
/// @see borderLight
|
||||
/// @see borderDouble
|
||||
/// @see borderHeavy
|
||||
/// @see borderRounded
|
||||
/// @see borderEmpty
|
||||
/// @see borderStyled
|
||||
/// @see borderWith
|
||||
///
|
||||
/// Add a border around an element
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```cpp
|
||||
/// // Use 'borderRounded' as a function...
|
||||
/// Element document = borderRounded(text("The element"));
|
||||
///
|
||||
/// // ...Or as a 'pipe'.
|
||||
/// Element document = text("The element") | borderRounded;
|
||||
/// ```
|
||||
///
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
///
|
||||
/// The element
|
||||
///
|
||||
/// ```
|
||||
Element borderEmpty(Element child) {
|
||||
return std::make_shared<Border>(unpack(std::move(child)), EMPTY);
|
||||
}
|
||||
|
||||
/// @brief Draw window with a title and a border around the element.
|
||||
/// @param title The title of the window.
|
||||
/// @param content The element to be wrapped.
|
||||
|
@@ -10,7 +10,7 @@ namespace ftxui {
|
||||
/// @return The centered element.
|
||||
/// @ingroup dom
|
||||
Element hcenter(Element child) {
|
||||
return hbox(filler(), std::move(child), filler()) | xflex_grow;
|
||||
return hbox(filler(), std::move(child), filler());
|
||||
}
|
||||
|
||||
/// @brief Center an element vertically.
|
||||
@@ -18,7 +18,7 @@ Element hcenter(Element child) {
|
||||
/// @return The centered element.
|
||||
/// @ingroup dom
|
||||
Element vcenter(Element child) {
|
||||
return vbox(filler(), std::move(child), filler()) | yflex_grow;
|
||||
return vbox(filler(), std::move(child), filler());
|
||||
}
|
||||
|
||||
/// @brief Center an element horizontally and vertically.
|
||||
@@ -26,7 +26,7 @@ Element vcenter(Element child) {
|
||||
/// @return The centered element.
|
||||
/// @ingroup dom
|
||||
Element center(Element child) {
|
||||
return hcenter(vcenter(std::move(child))) | flex_grow;
|
||||
return hcenter(vcenter(std::move(child)));
|
||||
}
|
||||
|
||||
/// @brief Align an element on the right side.
|
||||
@@ -34,7 +34,7 @@ Element center(Element child) {
|
||||
/// @return The right aligned element.
|
||||
/// @ingroup dom
|
||||
Element align_right(Element child) {
|
||||
return hbox(filler(), std::move(child)) | flex_grow;
|
||||
return hbox(filler(), std::move(child));
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
@@ -1,10 +1,15 @@
|
||||
#include <algorithm> // For std::max
|
||||
#include <algorithm> // for max
|
||||
#include <memory> // for make_shared, __shared_ptr_access
|
||||
#include <string> // for string
|
||||
#include <utility> // for move
|
||||
#include <vector> // for __alloc_traits<>::value_type
|
||||
|
||||
#include "ftxui/dom/elements.hpp"
|
||||
#include "ftxui/dom/node.hpp"
|
||||
#include "ftxui/dom/elements.hpp" // for Element, vscroll_indicator
|
||||
#include "ftxui/dom/node.hpp" // for Node, Elements
|
||||
#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator
|
||||
#include "ftxui/screen/box.hpp"
|
||||
#include "ftxui/screen/screen.hpp"
|
||||
#include "ftxui/dom/requirement.hpp" // for Requirement
|
||||
#include "ftxui/screen/box.hpp" // for Box
|
||||
#include "ftxui/screen/screen.hpp" // for Screen, Pixel
|
||||
|
||||
namespace ftxui {
|
||||
|
||||
@@ -58,3 +63,7 @@ Element vscroll_indicator(Element child) {
|
||||
}
|
||||
|
||||
} // 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.
|
||||
|
@@ -12,15 +12,36 @@ namespace ftxui {
|
||||
using ftxui::Screen;
|
||||
|
||||
const std::string charset[][2] = {
|
||||
{"│", "─"},
|
||||
{"┃", "━"},
|
||||
{"║", "═"},
|
||||
{"│", "─"},
|
||||
{"│", "─"}, //
|
||||
{"┃", "━"}, //
|
||||
{"║", "═"}, //
|
||||
{"│", "─"}, //
|
||||
{" ", " "}, //
|
||||
};
|
||||
|
||||
class Separator : public Node {
|
||||
public:
|
||||
Separator(BorderStyle style) : style_(style) {}
|
||||
Separator(std::string value) : value_(value) {}
|
||||
|
||||
void ComputeRequirement() override {
|
||||
requirement_.min_x = 1;
|
||||
requirement_.min_y = 1;
|
||||
}
|
||||
|
||||
void Render(Screen& screen) override {
|
||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||
screen.PixelAt(x, y).character = value_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string value_;
|
||||
};
|
||||
|
||||
class SeparatorAuto : public Node {
|
||||
public:
|
||||
SeparatorAuto(BorderStyle style) : style_(style) {}
|
||||
|
||||
void ComputeRequirement() override {
|
||||
requirement_.min_x = 1;
|
||||
@@ -43,9 +64,9 @@ class Separator : public Node {
|
||||
BorderStyle style_;
|
||||
};
|
||||
|
||||
class SeparatorWithPixel : public Separator {
|
||||
class SeparatorWithPixel : public SeparatorAuto {
|
||||
public:
|
||||
SeparatorWithPixel(Pixel pixel) : Separator(LIGHT), pixel_(pixel) {}
|
||||
SeparatorWithPixel(Pixel pixel) : SeparatorAuto(LIGHT), pixel_(pixel) {}
|
||||
void Render(Screen& screen) override {
|
||||
for (int y = box_.y_min; y <= box_.y_max; ++y) {
|
||||
for (int x = box_.x_min; x <= box_.x_max; ++x) {
|
||||
@@ -58,152 +79,258 @@ class SeparatorWithPixel : public Separator {
|
||||
Pixel pixel_;
|
||||
};
|
||||
|
||||
/// @brief Draw a vertical or horizontal separator in between two elements.
|
||||
/// @brief Draw a vertical or horizontal separation in between two other
|
||||
/// elements.
|
||||
/// @ingroup dom
|
||||
/// @see separator
|
||||
/// @see separatorLight
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorDouble
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorEmpty
|
||||
/// @see separatorRounded
|
||||
/// @see separatorStyled
|
||||
/// @see separatorCharacter
|
||||
///
|
||||
/// Add a visual separation in between two elements.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```cpp
|
||||
/// // Use 'border' as a function...
|
||||
/// Element document = vbox({
|
||||
/// text("Up"),
|
||||
/// text("up"),
|
||||
/// separator(),
|
||||
/// text("Down"),
|
||||
/// })
|
||||
/// text("down"),
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// Up
|
||||
/// up
|
||||
/// ────
|
||||
/// Down
|
||||
/// down
|
||||
/// ```
|
||||
Element separator() {
|
||||
return std::make_shared<Separator>(LIGHT);
|
||||
return std::make_shared<SeparatorAuto>(LIGHT);
|
||||
}
|
||||
|
||||
/// @brief Draw a vertical or horizontal separator in between two elements.
|
||||
/// @brief Draw a vertical or horizontal separation in between two other
|
||||
/// elements.
|
||||
/// @param style the style of the separator.
|
||||
/// @ingroup dom
|
||||
/// @see separator
|
||||
/// @see separatorLight
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorDouble
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorEmpty
|
||||
/// @see separatorRounded
|
||||
/// @see separatorStyled
|
||||
/// @see separatorCharacter
|
||||
///
|
||||
/// Add a visual separation in between two elements.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```cpp
|
||||
/// // Use 'border' as a function...
|
||||
/// Element document = vbox({
|
||||
/// text("Up"),
|
||||
/// separatorStyled(BorderStyle::LIGHT),
|
||||
/// text("Down"),
|
||||
/// })
|
||||
/// text("up"),
|
||||
/// separatorStyled(DOUBLE),
|
||||
/// text("down"),
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// Up
|
||||
/// ────
|
||||
/// Down
|
||||
/// up
|
||||
/// ════
|
||||
/// down
|
||||
/// ```
|
||||
Element separatorStyled(BorderStyle style) {
|
||||
return std::make_shared<Separator>(style);
|
||||
return std::make_shared<SeparatorAuto>(style);
|
||||
}
|
||||
|
||||
/// @brief Draw a vertical or horizontal light separator in between two
|
||||
/// elements.
|
||||
/// @brief Draw a vertical or horizontal separation in between two other
|
||||
/// elements, using the LIGHT style.
|
||||
/// @ingroup dom
|
||||
/// @see separator
|
||||
/// @see separatorLight
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorDouble
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorEmpty
|
||||
/// @see separatorRounded
|
||||
/// @see separatorStyled
|
||||
/// @see separatorCharacter
|
||||
///
|
||||
/// Add a visual separation in between two elements.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```cpp
|
||||
/// // Use 'border' as a function...
|
||||
/// Element document = vbox({
|
||||
/// text("Up"),
|
||||
/// text("up"),
|
||||
/// separatorLight(),
|
||||
/// text("Down"),
|
||||
/// })
|
||||
/// text("down"),
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// Up
|
||||
/// up
|
||||
/// ────
|
||||
/// Down
|
||||
/// down
|
||||
/// ```
|
||||
Element separatorLight() {
|
||||
return std::make_shared<Separator>(LIGHT);
|
||||
return std::make_shared<SeparatorAuto>(LIGHT);
|
||||
}
|
||||
|
||||
/// @brief Draw a vertical or horizontal heavy separator in between two
|
||||
/// elements.
|
||||
/// @brief Draw a vertical or horizontal separation in between two other
|
||||
/// elements, using the HEAVY style.
|
||||
/// @ingroup dom
|
||||
/// @see separator
|
||||
/// @see separatorLight
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorDouble
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorEmpty
|
||||
/// @see separatorRounded
|
||||
/// @see separatorStyled
|
||||
/// @see separatorCharacter
|
||||
///
|
||||
/// Add a visual separation in between two elements.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```cpp
|
||||
/// // Use 'border' as a function...
|
||||
/// Element document = vbox({
|
||||
/// text("Up"),
|
||||
/// text("up"),
|
||||
/// separatorHeavy(),
|
||||
/// text("Down"),
|
||||
/// })
|
||||
/// text("down"),
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// Up
|
||||
/// up
|
||||
/// ━━━━
|
||||
/// Down
|
||||
/// down
|
||||
/// ```
|
||||
Element separatorHeavy() {
|
||||
return std::make_shared<Separator>(HEAVY);
|
||||
return std::make_shared<SeparatorAuto>(HEAVY);
|
||||
}
|
||||
|
||||
/// @brief Draw a vertical or horizontal double separator in between two
|
||||
/// elements.
|
||||
/// @brief Draw a vertical or horizontal separation in between two other
|
||||
/// elements, using the DOUBLE style.
|
||||
/// @ingroup dom
|
||||
/// @see separator
|
||||
/// @see separatorLight
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorDouble
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorEmpty
|
||||
/// @see separatorRounded
|
||||
/// @see separatorStyled
|
||||
/// @see separatorCharacter
|
||||
///
|
||||
/// Add a visual separation in between two elements.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```cpp
|
||||
/// // Use 'border' as a function...
|
||||
/// Element document = vbox({
|
||||
/// text("Up"),
|
||||
/// text("up"),
|
||||
/// separatorDouble(),
|
||||
/// text("Down"),
|
||||
/// })
|
||||
/// text("down"),
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// Up
|
||||
/// up
|
||||
/// ════
|
||||
/// Down
|
||||
/// down
|
||||
/// ```
|
||||
Element separatorDouble() {
|
||||
return std::make_shared<Separator>(DOUBLE);
|
||||
return std::make_shared<SeparatorAuto>(DOUBLE);
|
||||
}
|
||||
|
||||
/// @brief Draw a vertical or horizontal separation in between two other
|
||||
/// elements, using the EMPTY style.
|
||||
/// @ingroup dom
|
||||
/// @see separator
|
||||
/// @see separatorLight
|
||||
/// @see separatorDouble
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorEmpty
|
||||
/// @see separatorRounded
|
||||
/// @see separatorStyled
|
||||
/// @see separatorCharacter
|
||||
///
|
||||
/// Add a visual separation in between two elements.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```cpp
|
||||
/// // Use 'border' as a function...
|
||||
/// Element document = vbox({
|
||||
/// text("up"),
|
||||
/// separator(),
|
||||
/// text("down"),
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// up
|
||||
///
|
||||
/// down
|
||||
/// ```
|
||||
Element separatorEmpty() {
|
||||
return std::make_shared<SeparatorAuto>(EMPTY);
|
||||
}
|
||||
|
||||
/// @brief Draw a vertical or horizontal separation in between two other
|
||||
/// elements.
|
||||
/// @param value the character to fill the separator area.
|
||||
/// @ingroup dom
|
||||
/// @see separator
|
||||
/// @see separatorLight
|
||||
/// @see separatorDouble
|
||||
/// @see separatorHeavy
|
||||
/// @see separatorEmpty
|
||||
/// @see separatorRounded
|
||||
/// @see separatorStyled
|
||||
/// @see separatorCharacter
|
||||
///
|
||||
/// Add a visual separation in between two elements.
|
||||
///
|
||||
/// ### Example
|
||||
///
|
||||
/// ```cpp
|
||||
/// // Use 'border' as a function...
|
||||
/// Element document = vbox({
|
||||
/// text("up"),
|
||||
/// separator(),
|
||||
/// text("down"),
|
||||
/// });
|
||||
/// ```
|
||||
///
|
||||
/// ### Output
|
||||
///
|
||||
/// ```bash
|
||||
/// up
|
||||
/// ────
|
||||
/// down
|
||||
/// ```
|
||||
Element separatorCharacter(std::string value) {
|
||||
return std::make_shared<Separator>(value);
|
||||
}
|
||||
|
||||
/// @brief Draw a separator in between two element filled with a given pixel.
|
||||
|
295
src/ftxui/dom/table.cpp
Normal file
295
src/ftxui/dom/table.cpp
Normal file
@@ -0,0 +1,295 @@
|
||||
#include "ftxui/dom/table.hpp"
|
||||
|
||||
#include <algorithm> // for max
|
||||
#include <memory> // for allocator, shared_ptr, allocator_traits<>::value_type
|
||||
#include <utility> // for move, swap
|
||||
|
||||
#include "ftxui/dom/elements.hpp" // for Element, operator|, text, separatorCharacter, Elements, BorderStyle, Decorator, emptyElement, size, gridbox, EQUAL, flex, flex_shrink, HEIGHT, WIDTH
|
||||
|
||||
namespace ftxui {
|
||||
namespace {
|
||||
|
||||
bool IsCell(int x, int y) {
|
||||
return x % 2 == 1 && y % 2 == 1;
|
||||
}
|
||||
|
||||
static std::string charset[6][6] = {
|
||||
{"┌", "┐", "└", "┘", "─", "│"}, //
|
||||
{"┏", "┓", "┗", "┛", "━", "┃"}, //
|
||||
{"╔", "╗", "╚", "╝", "═", "║"}, //
|
||||
{"╭", "╮", "╰", "╯", "─", "│"}, //
|
||||
{" ", " ", " ", " ", " ", " "}, //
|
||||
};
|
||||
|
||||
int Wrap(int input, int modulo) {
|
||||
input %= modulo;
|
||||
input += modulo;
|
||||
input %= modulo;
|
||||
return input;
|
||||
}
|
||||
|
||||
void Order(int& a, int& b) {
|
||||
if (a >= b)
|
||||
std::swap(a, b);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
Table::Table(std::vector<std::vector<std::string>> input) {
|
||||
input_dim_y_ = input.size();
|
||||
input_dim_x_ = 0;
|
||||
for (auto& row : input)
|
||||
input_dim_x_ = std::max(input_dim_x_, (int)row.size());
|
||||
|
||||
dim_y_ = 2 * input_dim_y_ + 1;
|
||||
dim_x_ = 2 * input_dim_x_ + 1;
|
||||
|
||||
// Reserve space.
|
||||
elements_.resize(dim_y_);
|
||||
for (int y = 0; y < dim_y_; ++y)
|
||||
elements_[y].resize(dim_x_);
|
||||
|
||||
// Transfert elements_ from |input| toward |elements_|.
|
||||
{
|
||||
int y = 1;
|
||||
for (auto& row : input) {
|
||||
int x = 1;
|
||||
for (auto& cell : row) {
|
||||
elements_[y][x] = text(cell);
|
||||
x += 2;
|
||||
}
|
||||
y += 2;
|
||||
}
|
||||
}
|
||||
|
||||
// Add empty element for the border.
|
||||
for (int y = 0; y < dim_y_; ++y) {
|
||||
for (int x = 0; x < dim_x_; ++x) {
|
||||
auto& element = elements_[y][x];
|
||||
|
||||
if (IsCell(x, y)) {
|
||||
if (!element)
|
||||
element = emptyElement();
|
||||
continue;
|
||||
}
|
||||
|
||||
element = emptyElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TableSelection Table::SelectRow(int index) {
|
||||
return SelectRectangle(0, -1, index, index);
|
||||
}
|
||||
|
||||
TableSelection Table::SelectRows(int row_min, int row_max) {
|
||||
return SelectRectangle(0, -1, row_min, row_max);
|
||||
}
|
||||
|
||||
TableSelection Table::SelectColumn(int index) {
|
||||
return SelectRectangle(index, index, 0, -1);
|
||||
}
|
||||
|
||||
TableSelection Table::SelectColumns(int column_min, int column_max) {
|
||||
return SelectRectangle(column_min, column_max, 0, -1);
|
||||
}
|
||||
|
||||
TableSelection Table::SelectCell(int column, int row) {
|
||||
return SelectRectangle(column, column, row, row);
|
||||
}
|
||||
|
||||
TableSelection Table::SelectRectangle(int column_min,
|
||||
int column_max,
|
||||
int row_min,
|
||||
int row_max) {
|
||||
column_min = Wrap(column_min, input_dim_x_);
|
||||
column_max = Wrap(column_max, input_dim_x_);
|
||||
Order(column_min, column_max);
|
||||
row_min = Wrap(row_min, input_dim_y_);
|
||||
row_max = Wrap(row_max, input_dim_y_);
|
||||
Order(row_min, row_max);
|
||||
|
||||
TableSelection output;
|
||||
output.table_ = this;
|
||||
output.x_min_ = 2 * column_min;
|
||||
output.x_max_ = 2 * column_max + 2;
|
||||
output.y_min_ = 2 * row_min;
|
||||
output.y_max_ = 2 * row_max + 2;
|
||||
return output;
|
||||
}
|
||||
|
||||
TableSelection Table::SelectAll() {
|
||||
TableSelection output;
|
||||
output.table_ = this;
|
||||
output.x_min_ = 0;
|
||||
output.x_max_ = dim_x_ - 1;
|
||||
output.y_min_ = 0;
|
||||
output.y_max_ = dim_y_ - 1;
|
||||
return output;
|
||||
}
|
||||
|
||||
Element Table::Render() {
|
||||
for (int y = 0; y < dim_y_; ++y) {
|
||||
for (int x = 0; x < dim_x_; ++x) {
|
||||
auto& it = elements_[y][x];
|
||||
|
||||
// Line
|
||||
if ((x + y) % 2 == 1) {
|
||||
it = std::move(it) | flex;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Cells
|
||||
if ((x % 2) == 1 && (y % 2) == 1) {
|
||||
it = std::move(it) | flex_shrink;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Corners
|
||||
it = std::move(it) | size(WIDTH, EQUAL, 0) | size(HEIGHT, EQUAL, 0);
|
||||
}
|
||||
}
|
||||
return gridbox(std::move(elements_));
|
||||
}
|
||||
|
||||
void TableSelection::Decorate(Decorator decorator) {
|
||||
for (int y = y_min_; y <= y_max_; ++y) {
|
||||
for (int x = x_min_; x <= x_max_; ++x) {
|
||||
Element& e = table_->elements_[y][x];
|
||||
e = std::move(e) | decorator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableSelection::DecorateCells(Decorator decorator) {
|
||||
for (int y = y_min_; y <= y_max_; ++y) {
|
||||
for (int x = x_min_; x <= x_max_; ++x) {
|
||||
if (y % 2 && x % 2) {
|
||||
Element& e = table_->elements_[y][x];
|
||||
e = std::move(e) | decorator;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableSelection::DecorateAlternateColumn(Decorator decorator,
|
||||
int modulo,
|
||||
int shift) {
|
||||
for (int y = y_min_; y <= y_max_; ++y) {
|
||||
for (int x = x_min_; x <= x_max_; ++x) {
|
||||
if (y % 2 && (x / 2) % modulo == shift) {
|
||||
Element& e = table_->elements_[y][x];
|
||||
e = std::move(e) | decorator;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableSelection::DecorateAlternateRow(Decorator decorator,
|
||||
int modulo,
|
||||
int shift) {
|
||||
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
||||
for (int x = x_min_; x <= x_max_; ++x) {
|
||||
if (y % 2 && (y / 2) % modulo == shift) {
|
||||
Element& e = table_->elements_[y][x];
|
||||
e = std::move(e) | decorator;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableSelection::DecorateCellsAlternateColumn(Decorator decorator,
|
||||
int modulo,
|
||||
int shift) {
|
||||
for (int y = y_min_; y <= y_max_; ++y) {
|
||||
for (int x = x_min_; x <= x_max_; ++x) {
|
||||
if (y % 2 && x % 2 && ((x / 2) % modulo == shift)) {
|
||||
Element& e = table_->elements_[y][x];
|
||||
e = std::move(e) | decorator;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableSelection::DecorateCellsAlternateRow(Decorator decorator,
|
||||
int modulo,
|
||||
int shift) {
|
||||
for (int y = y_min_; y <= y_max_; ++y) {
|
||||
for (int x = x_min_; x <= x_max_; ++x) {
|
||||
if (y % 2 && x % 2 && ((y / 2) % modulo == shift)) {
|
||||
Element& e = table_->elements_[y][x];
|
||||
e = std::move(e) | decorator;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableSelection::Border(BorderStyle style) {
|
||||
BorderLeft(style);
|
||||
BorderRight(style);
|
||||
BorderTop(style);
|
||||
BorderBottom(style);
|
||||
|
||||
table_->elements_[y_min_][x_min_] = text(charset[style][0]);
|
||||
table_->elements_[y_min_][x_max_] = text(charset[style][1]);
|
||||
table_->elements_[y_max_][x_min_] = text(charset[style][2]);
|
||||
table_->elements_[y_max_][x_max_] = text(charset[style][3]);
|
||||
}
|
||||
|
||||
void TableSelection::Separator(BorderStyle style) {
|
||||
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
||||
for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
|
||||
if (y % 2 == 0 || x % 2 == 0) {
|
||||
Element& e = table_->elements_[y][x];
|
||||
e = (y % 2) ? separatorCharacter(charset[style][5])
|
||||
: separatorCharacter(charset[style][4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableSelection::SeparatorVertical(BorderStyle style) {
|
||||
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
||||
for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
|
||||
if (x % 2 == 0) {
|
||||
table_->elements_[y][x] = text(charset[style][5]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableSelection::SeparatorHorizontal(BorderStyle style) {
|
||||
for (int y = y_min_ + 1; y <= y_max_ - 1; ++y) {
|
||||
for (int x = x_min_ + 1; x <= x_max_ - 1; ++x) {
|
||||
if (y % 2 == 0) {
|
||||
table_->elements_[y][x] = text(charset[style][4]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TableSelection::BorderLeft(BorderStyle style) {
|
||||
for (int y = y_min_; y <= y_max_; y++)
|
||||
table_->elements_[y][x_min_] = separatorCharacter(charset[style][5]);
|
||||
}
|
||||
|
||||
void TableSelection::BorderRight(BorderStyle style) {
|
||||
for (int y = y_min_; y <= y_max_; y++)
|
||||
table_->elements_[y][x_max_] = separatorCharacter(charset[style][5]);
|
||||
}
|
||||
|
||||
void TableSelection::BorderTop(BorderStyle style) {
|
||||
for (int x = x_min_; x <= x_max_; x++)
|
||||
table_->elements_[y_min_][x] = separatorCharacter(charset[style][4]);
|
||||
}
|
||||
|
||||
void TableSelection::BorderBottom(BorderStyle style) {
|
||||
for (int x = x_min_; x <= x_max_; x++)
|
||||
table_->elements_[y_max_][x] = separatorCharacter(charset[style][4]);
|
||||
}
|
||||
|
||||
} // 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.
|
716
src/ftxui/dom/table_test.cpp
Normal file
716
src/ftxui/dom/table_test.cpp
Normal file
@@ -0,0 +1,716 @@
|
||||
#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 LIGHT, flex, center, EMPTY, DOUBLE
|
||||
#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
|
||||
|
||||
using namespace ftxui;
|
||||
|
||||
TEST(TableTest, Empty) {
|
||||
auto table = Table({});
|
||||
Screen screen(5, 5);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, Basic) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"abcd \r\n"
|
||||
"efgh \r\n"
|
||||
"ijkl \r\n"
|
||||
"mnop \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SeparatorVerticalEmpty) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().SeparatorVertical(EMPTY);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"a b c d \r\n"
|
||||
"e f g h \r\n"
|
||||
"i j k l \r\n"
|
||||
"m n o p \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SeparatorHorizontalEmpty) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().SeparatorHorizontal(EMPTY);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"abcd \r\n"
|
||||
" \r\n"
|
||||
"efgh \r\n"
|
||||
" \r\n"
|
||||
"ijkl \r\n"
|
||||
" \r\n"
|
||||
"mnop \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SeparatorHorizontalLight) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().SeparatorHorizontal(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"abcd \r\n"
|
||||
"──── \r\n"
|
||||
"efgh \r\n"
|
||||
"──── \r\n"
|
||||
"ijkl \r\n"
|
||||
"──── \r\n"
|
||||
"mnop \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SeparatorVerticalLight) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().SeparatorVertical(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"a│b│c│d \r\n"
|
||||
"e│f│g│h \r\n"
|
||||
"i│j│k│l \r\n"
|
||||
"m│n│o│p \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SeparatorLight) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().Separator(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"a│b│c│d \r\n"
|
||||
"─┼─┼─┼─ \r\n"
|
||||
"e│f│g│h \r\n"
|
||||
"─┼─┼─┼─ \r\n"
|
||||
"i│j│k│l \r\n"
|
||||
"─┼─┼─┼─ \r\n"
|
||||
"m│n│o│p \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SeparatorVerticalHorizontalLight) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().SeparatorVertical(LIGHT);
|
||||
table.SelectAll().SeparatorHorizontal(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"a│b│c│d \r\n"
|
||||
"─┼─┼─┼─ \r\n"
|
||||
"e│f│g│h \r\n"
|
||||
"─┼─┼─┼─ \r\n"
|
||||
"i│j│k│l \r\n"
|
||||
"─┼─┼─┼─ \r\n"
|
||||
"m│n│o│p \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SeparatorHorizontalVerticalLight) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().SeparatorHorizontal(LIGHT);
|
||||
table.SelectAll().SeparatorVertical(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"a│b│c│d \r\n"
|
||||
"─┼─┼─┼─ \r\n"
|
||||
"e│f│g│h \r\n"
|
||||
"─┼─┼─┼─ \r\n"
|
||||
"i│j│k│l \r\n"
|
||||
"─┼─┼─┼─ \r\n"
|
||||
"m│n│o│p \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, BorderLight) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"┌────┐ \r\n"
|
||||
"│abcd│ \r\n"
|
||||
"│efgh│ \r\n"
|
||||
"│ijkl│ \r\n"
|
||||
"│mnop│ \r\n"
|
||||
"└────┘ \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, BorderSeparatorLight) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().Border(LIGHT);
|
||||
table.SelectAll().Separator(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"┌─┬─┬─┬─┐ \r\n"
|
||||
"│a│b│c│d│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│e│f│g│h│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│i│j│k│l│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│m│n│o│p│ \r\n"
|
||||
"└─┴─┴─┴─┘ \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SelectRow) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectRow(1).Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" abcd \r\n"
|
||||
"┌────┐ \r\n"
|
||||
"│efgh│ \r\n"
|
||||
"└────┘ \r\n"
|
||||
" ijkl \r\n"
|
||||
" mnop \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SelectRowNegative) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectRow(-2).Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" abcd \r\n"
|
||||
" efgh \r\n"
|
||||
"┌────┐ \r\n"
|
||||
"│ijkl│ \r\n"
|
||||
"└────┘ \r\n"
|
||||
" mnop \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SelectColumn) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectColumn(1).Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" ┌─┐ \r\n"
|
||||
"a│b│cd \r\n"
|
||||
"e│f│gh \r\n"
|
||||
"i│j│kl \r\n"
|
||||
"m│n│op \r\n"
|
||||
" └─┘ \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SelectColumnNegative) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectColumn(-2).Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" ┌─┐ \r\n"
|
||||
"ab│c│d \r\n"
|
||||
"ef│g│h \r\n"
|
||||
"ij│k│l \r\n"
|
||||
"mn│o│p \r\n"
|
||||
" └─┘ \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, CrossingBorders) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectRow(1).Border(LIGHT);
|
||||
table.SelectColumn(1).Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" ┌─┐ \r\n"
|
||||
" a│b│cd \r\n"
|
||||
"┌─┼─┼──┐ \r\n"
|
||||
"│e│f│gh│ \r\n"
|
||||
"└─┼─┼──┘ \r\n"
|
||||
" i│j│kl \r\n"
|
||||
" m│n│op \r\n"
|
||||
" └─┘ \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, CrossingBordersLightAndDouble) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectRow(1).Border(LIGHT);
|
||||
table.SelectColumn(1).Border(DOUBLE);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" ╔═╗ \r\n"
|
||||
" a║b║cd \r\n"
|
||||
"┌─╫─╫──┐ \r\n"
|
||||
"│e║f║gh│ \r\n"
|
||||
"└─╫─╫──┘ \r\n"
|
||||
" i║j║kl \r\n"
|
||||
" m║n║op \r\n"
|
||||
" ╚═╝ \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SelectColumns) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectColumns(1, 2).Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" ┌──┐ \r\n"
|
||||
"a│bc│d \r\n"
|
||||
"e│fg│h \r\n"
|
||||
"i│jk│l \r\n"
|
||||
"m│no│p \r\n"
|
||||
" └──┘ \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SelectRows) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectRows(1, 2).Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" abcd \r\n"
|
||||
"┌────┐ \r\n"
|
||||
"│efgh│ \r\n"
|
||||
"│ijkl│ \r\n"
|
||||
"└────┘ \r\n"
|
||||
" mnop \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SelectRectangle) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectRectangle(1, 2, 1, 2).Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"a bc d \r\n"
|
||||
" ┌──┐ \r\n"
|
||||
"e│fg│h \r\n"
|
||||
"i│jk│l \r\n"
|
||||
" └──┘ \r\n"
|
||||
"m no p \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SelectColumnsNegative) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectColumns(1, -1).Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" ┌───┐ \r\n"
|
||||
"a│bcd│ \r\n"
|
||||
"e│fgh│ \r\n"
|
||||
"i│jkl│ \r\n"
|
||||
"m│nop│ \r\n"
|
||||
" └───┘ \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, SelectInverted) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectColumns(-1, 1).Border(LIGHT);
|
||||
Screen screen(10, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
" ┌───┐ \r\n"
|
||||
"a│bcd│ \r\n"
|
||||
"e│fgh│ \r\n"
|
||||
"i│jkl│ \r\n"
|
||||
"m│nop│ \r\n"
|
||||
" └───┘ \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, ColumnFlex) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().Border(LIGHT);
|
||||
table.SelectAll().Separator(LIGHT);
|
||||
table.SelectColumn(1).Decorate(flex);
|
||||
Screen screen(20, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"┌─┬────────────┬─┬─┐\r\n"
|
||||
"│a│b │c│d│\r\n"
|
||||
"├─┼────────────┼─┼─┤\r\n"
|
||||
"│e│f │g│h│\r\n"
|
||||
"├─┼────────────┼─┼─┤\r\n"
|
||||
"│i│j │k│l│\r\n"
|
||||
"├─┼────────────┼─┼─┤\r\n"
|
||||
"│m│n │o│p│\r\n"
|
||||
"└─┴────────────┴─┴─┘\r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, ColumnFlexCenter) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().Border(LIGHT);
|
||||
table.SelectAll().Separator(LIGHT);
|
||||
table.SelectColumn(1).Decorate(flex);
|
||||
table.SelectColumn(1).DecorateCells(center);
|
||||
Screen screen(20, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"┌─┬─┬─┬─┐ \r\n"
|
||||
"│a│b│c│d│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│e│f│g│h│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│i│j│k│l│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│m│n│o│p│ \r\n"
|
||||
"└─┴─┴─┴─┘ \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, ColumnCenter) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().Border(LIGHT);
|
||||
table.SelectAll().Separator(LIGHT);
|
||||
table.SelectColumn(1).DecorateCells(center);
|
||||
Screen screen(20, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"┌─┬─┬─┬─┐ \r\n"
|
||||
"│a│b│c│d│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│e│f│g│h│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│i│j│k│l│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│m│n│o│p│ \r\n"
|
||||
"└─┴─┴─┴─┘ \r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, ColumnFlexTwo) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().Border(LIGHT);
|
||||
table.SelectAll().Separator(LIGHT);
|
||||
table.SelectColumn(1).Decorate(flex);
|
||||
table.SelectColumn(3).Decorate(flex);
|
||||
Screen screen(20, 10);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"┌─┬──────┬─┬───────┐\r\n"
|
||||
"│a│b │c│d │\r\n"
|
||||
"├─┼──────┼─┼───────┤\r\n"
|
||||
"│e│f │g│h │\r\n"
|
||||
"├─┼──────┼─┼───────┤\r\n"
|
||||
"│i│j │k│l │\r\n"
|
||||
"├─┼──────┼─┼───────┤\r\n"
|
||||
"│m│n │o│p │\r\n"
|
||||
"└─┴──────┴─┴───────┘\r\n"
|
||||
" ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, RowFlex) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().Border(LIGHT);
|
||||
table.SelectAll().Separator(LIGHT);
|
||||
table.SelectRow(1).Decorate(flex);
|
||||
Screen screen(10, 20);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"┌─┬─┬─┬─┐ \r\n"
|
||||
"│a│b│c│d│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│e│f│g│h│ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│i│j│k│l│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│m│n│o│p│ \r\n"
|
||||
"└─┴─┴─┴─┘ ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
TEST(TableTest, RowFlexTwo) {
|
||||
auto table = Table({
|
||||
{"a", "b", "c", "d"},
|
||||
{"e", "f", "g", "h"},
|
||||
{"i", "j", "k", "l"},
|
||||
{"m", "n", "o", "p"},
|
||||
});
|
||||
table.SelectAll().Border(LIGHT);
|
||||
table.SelectAll().Separator(LIGHT);
|
||||
table.SelectRow(1).Decorate(flex);
|
||||
table.SelectRow(3).Decorate(flex);
|
||||
Screen screen(10, 20);
|
||||
Render(screen, table.Render());
|
||||
EXPECT_EQ(
|
||||
"┌─┬─┬─┬─┐ \r\n"
|
||||
"│a│b│c│d│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│e│f│g│h│ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│i│j│k│l│ \r\n"
|
||||
"├─┼─┼─┼─┤ \r\n"
|
||||
"│m│n│o│p│ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"│ │ │ │ │ \r\n"
|
||||
"└─┴─┴─┴─┘ ",
|
||||
screen.ToString());
|
||||
}
|
||||
|
||||
// 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.
|
@@ -75,6 +75,18 @@ Dimensions Dimension::Fit(Element& e) {
|
||||
std::min(e->requirement().min_y, size.dimy)};
|
||||
}
|
||||
|
||||
/// An element of size 0x0 drawing nothing.
|
||||
/// @ingroup dom
|
||||
Element emptyElement() {
|
||||
class Impl : public Node {
|
||||
void ComputeRequirement() override {
|
||||
requirement_.min_x = 0;
|
||||
requirement_.min_x = 0;
|
||||
}
|
||||
};
|
||||
return std::make_unique<Impl>();
|
||||
}
|
||||
|
||||
} // namespace ftxui
|
||||
|
||||
// Copyright 2020 Arthur Sonzogni. All rights reserved.
|
||||
|
Reference in New Issue
Block a user