FTXUI 6.1.9
C++ functional terminal UI.
Chargement...
Recherche...
Aucune correspondance
flexbox.cpp
Aller à la documentation de ce fichier.
1// Copyright 2020 Arthur Sonzogni. Tous droits réservés.
2// L'utilisation de ce code source est régie par la licence MIT qui peut être trouvée dans
3// le fichier LICENSE.
4#include <algorithm> // for min, max
5#include <cstddef> // for size_t
6#include <memory> // for __shared_ptr_access, shared_ptr, allocator_traits<>::value_type, make_shared
7#include <tuple> // for ignore
8#include <utility> // for move, swap
9#include <vector> // for vector
10
11#include "ftxui/dom/elements.hpp" // for Element, Elements, flexbox, hflow, vflow
12#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
13#include "ftxui/dom/flexbox_helper.hpp" // for Block, Global, Compute
14#include "ftxui/dom/node.hpp" // for Node, Elements, Node::Status
15#include "ftxui/dom/requirement.hpp" // for Requirement
16#include "ftxui/dom/selection.hpp" // for Selection
17#include "ftxui/screen/box.hpp" // for Box
18
19namespace ftxui {
20
21namespace {
22void Normalize(FlexboxConfig::Direction& direction) {
23 switch (direction) {
27 } break;
31 } break;
32 }
33}
34
35void Normalize(FlexboxConfig::AlignContent& align_content) {
37}
38
39void Normalize(FlexboxConfig::JustifyContent& justify_content) {
41}
42
43void Normalize(FlexboxConfig::Wrap& wrap) {
45}
46
47FlexboxConfig Normalize(FlexboxConfig config) {
48 Normalize(config.direction);
49 Normalize(config.wrap);
50 Normalize(config.justify_content);
51 Normalize(config.align_content);
52 return config;
53}
54
55class Flexbox : public Node {
56 public:
57 Flexbox(Elements children, FlexboxConfig config)
58 : Node(std::move(children)),
59 config_(config),
60 config_normalized_(Normalize(config)) {
61 requirement_.flex_grow_x = 1;
62 requirement_.flex_grow_y = 0;
63
64 if (IsColumnOriented()) {
65 std::swap(requirement_.flex_grow_x, requirement_.flex_grow_y);
66 }
67 }
68
69 bool IsColumnOriented() const {
70 return config_.direction == FlexboxConfig::Direction::Column ||
72 }
73
74 void Layout(flexbox_helper::Global& global,
75 bool compute_requirement = false) {
76 global.blocks.reserve(children_.size());
77 for (auto& child : children_) {
78 flexbox_helper::Block block;
79 block.min_size_x = child->requirement().min_x;
80 block.min_size_y = child->requirement().min_y;
81 if (!compute_requirement) {
82 block.flex_grow_x = child->requirement().flex_grow_x;
83 block.flex_grow_y = child->requirement().flex_grow_y;
84 block.flex_shrink_x = child->requirement().flex_shrink_x;
85 block.flex_shrink_y = child->requirement().flex_shrink_y;
86 }
87 global.blocks.push_back(block);
88 }
89
91 }
92
93 void ComputeRequirement() override {
94 requirement_ = Requirement{};
95 for (auto& child : children_) {
96 child->ComputeRequirement();
97 }
98 global_ = flexbox_helper::Global();
100 if (IsColumnOriented()) {
101 global_.size_x = 100000; // NOLINT
102 global_.size_y = asked_;
103 } else {
104 global_.size_x = asked_;
105 global_.size_y = 100000; // NOLINT
106 }
107 Layout(global_, true);
108
109 if (global_.blocks.empty()) {
110 return;
111 }
112
113 // Compute the union of all the blocks:
114 Box box;
115 box.x_min = global_.blocks[0].x;
116 box.y_min = global_.blocks[0].y;
117 box.x_max = global_.blocks[0].x + global_.blocks[0].dim_x;
118 box.y_max = global_.blocks[0].y + global_.blocks[0].dim_y;
119 for (auto& b : global_.blocks) {
120 box.x_min = std::min(box.x_min, b.x);
121 box.y_min = std::min(box.y_min, b.y);
122 box.x_max = std::max(box.x_max, b.x + b.dim_x);
123 box.y_max = std::max(box.y_max, b.y + b.dim_y);
124 }
125 requirement_.min_x = box.x_max - box.x_min;
126 requirement_.min_y = box.y_max - box.y_min;
127
128 // Find the selection:
129 for (size_t i = 0; i < children_.size(); ++i) {
130 if (requirement_.focused.Prefer(children_[i]->requirement().focused)) {
131 requirement_.focused = children_[i]->requirement().focused;
132 // Shift |focused.box| according to its position inside this component:
133 auto& b = global_.blocks[i];
134 requirement_.focused.box.Shift(b.x, b.y);
135 requirement_.focused.box =
136 Box::Intersection(requirement_.focused.box, box);
137 }
138 }
139 }
140
141 void SetBox(Box box) override {
142 Node::SetBox(box);
143
144 const int asked_previous = asked_;
145 asked_ = std::min(asked_, IsColumnOriented() ? box.y_max - box.y_min + 1
146 : box.x_max - box.x_min + 1);
147 need_iteration_ = (asked_ != asked_previous);
148
149 flexbox_helper::Global global;
150 global.config = config_;
151 global.size_x = box.x_max - box.x_min + 1;
152 global.size_y = box.y_max - box.y_min + 1;
153 Layout(global);
154
155 for (size_t i = 0; i < children_.size(); ++i) {
156 auto& child = children_[i];
157 auto& b = global.blocks[i];
158
159 Box children_box;
160 children_box.x_min = box.x_min + b.x;
161 children_box.y_min = box.y_min + b.y;
162 children_box.x_max = box.x_min + b.x + b.dim_x - 1;
163 children_box.y_max = box.y_min + b.y + b.dim_y - 1;
164
165 const Box intersection = Box::Intersection(children_box, box);
166 child->SetBox(intersection);
167
168 need_iteration_ |= (intersection != children_box);
169 }
170 }
171
172 void Select(Selection& selection) override {
173 // If this Node box_ doesn't intersect with the selection, then no
174 // selection.
175 if (Box::Intersection(selection.GetBox(), box_).IsEmpty()) {
176 return;
177 }
178
179 Selection selection_lines = IsColumnOriented()
180 ? selection.SaturateVertical(box_)
181 : selection.SaturateHorizontal(box_);
182
183 size_t i = 0;
184 for (auto& line : global_.lines) {
185 Box box;
186 box.x_min = box_.x_min + line.x;
187 box.x_max = box_.x_min + line.x + line.dim_x - 1;
188 box.y_min = box_.y_min + line.y;
189 box.y_max = box_.y_min + line.y + line.dim_y - 1;
190
191 // If the line box doesn't intersect with the selection, then no
192 // selection.
193 if (Box::Intersection(selection.GetBox(), box).IsEmpty()) {
194 continue;
195 }
196
197 Selection selection_line = IsColumnOriented()
198 ? selection_lines.SaturateHorizontal(box)
199 : selection_lines.SaturateVertical(box);
200
201 for (auto& block : line.blocks) {
202 std::ignore = block;
203 children_[i]->Select(selection_line);
204 i++;
205 }
206 }
207 }
208
209 void Check(Status* status) override {
210 for (auto& child : children_) {
211 child->Check(status);
212 }
213
214 if (status->iteration == 0) {
215 asked_ = 6000; // NOLINT
216 need_iteration_ = true;
217 }
218
219 status->need_iteration |= need_iteration_;
220 }
221
222 int asked_ = 6000; // NOLINT
223 bool need_iteration_ = true;
224 const FlexboxConfig config_;
225 const FlexboxConfig config_normalized_;
226 flexbox_helper::Global global_;
227};
228
229} // namespace
230
231/// @brief Un conteneur affichant des éléments sur des lignes/colonnes et capable de
232/// passer à la colonne/ligne suivante lorsqu'il est plein.
233/// @param children Les éléments dans le conteneur
234/// @param config Les options
235/// @return Le conteneur.
236///
237/// #### Example
238///
239/// ```cpp
240/// flexbox({
241/// text("element 1"),
242/// text("element 2"),
243/// text("element 3"),
244/// }, FlexboxConfig()
245/// .Set(FlexboxConfig::Direction::Column)
246/// .Set(FlexboxConfig::Wrap::WrapInversed)
247/// .SetGapMainAxis(1)
248/// .SetGapCrossAxis(1)
249/// )
250/// ```
252 return std::make_shared<Flexbox>(std::move(children), config);
253}
254
255/// @brief Un conteneur affichant des éléments en lignes de gauche à droite. Quand
256/// il est rempli, il commence sur une nouvelle ligne en dessous.
257/// @param children Les éléments dans le conteneur
258/// @return Le conteneur.
259///
260/// #### Example
261///
262/// ```cpp
263/// hflow({
264/// text("element 1"),
265/// text("element 2"),
266/// text("element 3"),
267/// });
268/// ```
270 return flexbox(std::move(children), FlexboxConfig());
271}
272
273/// @brief Un conteneur affichant des éléments en colonnes de haut en bas. Quand
274/// il est rempli, il commence sur une nouvelle colonne à droite.
275/// @param children Les éléments dans le conteneur
276/// @return Le conteneur.
277///
278/// #### Example
279///
280/// ```cpp
281/// vflow({
282/// text("element 1"),
283/// text("element 2"),
284/// text("element 3"),
285/// });
286/// ```
288 return flexbox(std::move(children),
290}
291
292} // namespace ftxui
int asked_
Definition flexbox.cpp:222
bool need_iteration_
Definition flexbox.cpp:223
const FlexboxConfig config_
Definition flexbox.cpp:224
const FlexboxConfig config_normalized_
Definition flexbox.cpp:225
flexbox_helper::Global global_
Definition flexbox.cpp:226
@ FlexStart
Les éléments sont placés au début de l'axe transversal.
@ Column
Les éléments flexibles sont disposés en colonne.
@ Row
Les éléments flexibles sont disposés en ligne.
virtual void SetBox(Box box)
Assigne une position et une dimension à un élément pour le dessin.
Definition node.cpp:41
@ FlexStart
Les éléments sont alignés au début de la direction du flexbox.
FlexboxConfig est une structure de configuration qui définit les propriétés de mise en page pour un c...
static auto Intersection(Box a, Box b) -> Box
Definition box.cpp:11
void Compute(Global &global)
L'espace de noms FTXUI ftxui::
Definition animation.hpp:10
Element flexbox(Elements, FlexboxConfig config=FlexboxConfig())
Un conteneur affichant des éléments sur des lignes/colonnes et capable de passer à la colonne/ligne s...
Definition flexbox.cpp:251
std::shared_ptr< Node > Element
Definition elements.hpp:22
Element hflow(Elements)
Un conteneur affichant des éléments en lignes de gauche à droite. Quand il est rempli,...
Definition flexbox.cpp:269
std::vector< Element > Elements
Definition elements.hpp:23
Element vflow(Elements)
Un conteneur affichant des éléments en colonnes de haut en bas. Quand il est rempli,...
Definition flexbox.cpp:287