FTXUI  0.8.1
C++ functional terminal UI.
gridbox.cpp
Go to the documentation of this file.
1 #include <iostream>
2 #include <algorithm> // for max
3 #include <memory> // for __shared_ptr_access, shared_ptr, make_shared
4 #include <utility> // for move
5 #include <vector> // for vector
6 
7 #include "ftxui/dom/box_helper.hpp" // for Requirement
8 #include "ftxui/dom/elements.hpp" // for Element, Elements, hbox
9 #include "ftxui/dom/node.hpp" // for Node
10 #include "ftxui/dom/requirement.hpp" // for Requirement
11 #include "ftxui/screen/box.hpp" // for Box
12 
13 namespace ftxui {
14 
15 class GridBox : public Node {
16  public:
17  GridBox(std::vector<Elements> lines) : Node(), lines_(std::move(lines)) {
18  y_size = lines_.size();
19  for (const auto& line : lines_)
20  x_size = std::max(x_size, (int)line.size());
21  for (auto& line : lines_) {
22  while (line.size() < (size_t)y_size) {
23  line.push_back(filler());
24  }
25  }
26  }
27 
28  void ComputeRequirement() override {
29  requirement_.min_x = 0;
30  requirement_.min_y = 0;
35 
36  for(auto& line : lines_) {
37  for(auto& cell : line) {
38  cell->ComputeRequirement();
39 
40  // Determine focus based on the focused child.
41  if (requirement_.selection >= cell->requirement().selection)
42  continue;
43  requirement_.selection = cell->requirement().selection;
44  requirement_.selected_box = cell->requirement().selected_box;
47  }
48  }
49 
50  // Work on the x-axis.
51  for (int x = 0; x < x_size; ++x) {
52  int min_x = 0;
53  for (int y = 0; y < y_size; ++y)
54  min_x = std::max(min_x, lines_[y][x]->requirement().min_x);
55  requirement_.min_x += min_x;
56  }
57 
58  // Work on the y-axis.
59  for (int y = 0; y < y_size; ++y) {
60  int min_y = 0;
61  for (int x = 0; x < x_size; ++x)
62  min_y = std::max(min_y, lines_[y][x]->requirement().min_y);
63  requirement_.min_y += min_y;
64  }
65  }
66 
67  void SetBox(Box box) override {
68  Node::SetBox(box);
69 
71  init.min_size = 0;
72  init.flex_grow = 1024;
73  init.flex_shrink = 1024;
74  std::vector<box_helper::Element> elements_x(x_size, init);
75  std::vector<box_helper::Element> elements_y(y_size, init);
76 
77  for (int y = 0; y < y_size; ++y) {
78  for (int x = 0; x < x_size; ++x) {
79  const auto& cell = lines_[y][x];
80  const auto& requirement = cell->requirement();
81  auto& e_x = elements_x[x];
82  auto& e_y = elements_y[y];
83  e_x.min_size = std::max(e_x.min_size, requirement.min_x);
84  e_y.min_size = std::max(e_y.min_size, requirement.min_y);
85  e_x.flex_grow = std::min(e_x.flex_grow, requirement.flex_grow_x);
86  e_y.flex_grow = std::min(e_y.flex_grow, requirement.flex_grow_y);
87  e_x.flex_shrink = std::min(e_x.flex_shrink, requirement.flex_shrink_x);
88  e_y.flex_shrink = std::min(e_y.flex_shrink, requirement.flex_shrink_y);
89  }
90  }
91 
92  int target_size_x = box.x_max - box.x_min + 1;
93  int target_size_y = box.y_max - box.y_min + 1;
94  box_helper::Compute(&elements_x, target_size_x);
95  box_helper::Compute(&elements_y, target_size_y);
96 
97  Box box_y = box;
98  int y = box_y.y_min;
99  for (int iy = 0; iy < y_size; ++iy) {
100  box_y.y_min = y;
101  y += elements_y[iy].size;
102  box_y.y_max = y - 1;
103 
104  Box box_x = box_y;
105  int x = box_x.x_min;
106  for (int ix = 0; ix < x_size; ++ix) {
107  box_x.x_min = x;
108  x += elements_x[ix].size;
109  box_x.x_max = x - 1;
110  lines_[iy][ix]->SetBox(box_x);
111  }
112  }
113  }
114 
115  void Render(Screen& screen) override {
116  for (auto& line : lines_) {
117  for (auto& cell : line)
118  cell->Render(screen);
119  }
120  }
121 
122  int x_size = 0;
123  int y_size = 0;
124  std::vector<Elements> lines_;
125 };
126 
127 /// @brief A container displaying a grid of elements.
128 /// @param lines A list of lines, each line being a list of elements.
129 /// @return The container.
130 ///
131 /// #### Example
132 ///
133 /// ```cpp
134 /// auto cell = [](const char* t) { return text(t) | border; };
135 /// auto document = gridbox({
136 /// {cell("north-west") , cell("north") , cell("north-east")} ,
137 /// {cell("west") , cell("center") , cell("east")} ,
138 /// {cell("south-west") , cell("south") , cell("south-east")} ,
139 /// });
140 /// ```
141 /// Output:
142 /// ```
143 ///╭──────────╮╭──────╮╭──────────╮
144 ///│north-west││north ││north-east│
145 ///╰──────────╯╰──────╯╰──────────╯
146 ///╭──────────╮╭──────╮╭──────────╮
147 ///│west ││center││east │
148 ///╰──────────╯╰──────╯╰──────────╯
149 ///╭──────────╮╭──────╮╭──────────╮
150 ///│south-west││south ││south-east│
151 ///╰──────────╯╰──────╯╰──────────╯
152 /// ```
153 Element gridbox(std::vector<Elements> lines) {
154  return std::make_shared<GridBox>(std::move(lines));
155 }
156 
157 } // namespace ftxui
158 
159 // Copyright 2020 Arthur Sonzogni. All rights reserved.
160 // Use of this source code is governed by the MIT license that can be found in
161 // the LICENSE file.
ftxui::Requirement::selected_box
Box selected_box
Definition: requirement.hpp:26
ftxui::Node::SetBox
virtual void SetBox(Box box)
Assign a position and a dimension to an element for drawing.
Definition: node.cpp:21
ftxui::Requirement::min_x
int min_x
Definition: requirement.hpp:10
ftxui::Box::x_min
int x_min
Definition: box.hpp:7
ftxui
Definition: captured_mouse.hpp:6
node.hpp
ftxui::Node::requirement
Requirement requirement()
Definition: node.hpp:29
box.hpp
box_helper.hpp
requirement.hpp
ftxui::filler
Element filler()
An element that will take expand proportionnally to the space left in a container.
Definition: flex.cpp:94
ftxui::Box::x_max
int x_max
Definition: box.hpp:8
elements.hpp
ftxui::Node::Node
Node()
Definition: node.cpp:8
ftxui::Requirement::flex_grow_y
int flex_grow_y
Definition: requirement.hpp:15
ftxui::Element
std::shared_ptr< Node > Element
Definition: elements.hpp:15
ftxui::Requirement::selection
Selection selection
Definition: requirement.hpp:25
ftxui::Requirement::min_y
int min_y
Definition: requirement.hpp:11
ftxui::Render
void Render(Screen &screen, const Element &node)
Display an element on a ftxui::Screen.
Definition: node.cpp:34
ftxui::Node::requirement_
Requirement requirement_
Definition: node.hpp:40
ftxui::gridbox
Element gridbox(std::vector< Elements > lines)
A container displaying a grid of elements.
Definition: gridbox.cpp:153
ftxui::Requirement::flex_shrink_y
int flex_shrink_y
Definition: requirement.hpp:17
ftxui::Requirement::flex_grow_x
int flex_grow_x
Definition: requirement.hpp:14
ftxui::box_helper::Compute
void Compute(std::vector< Element > *elements, int target_size)
Definition: box_helper.cpp:60
ftxui::Requirement::flex_shrink_x
int flex_shrink_x
Definition: requirement.hpp:16