mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-25 20:27:31 +08:00
Factorize box layout functions. (#185)
|hbox| and |vbox| are similar. They are just the same component, but drawing in a different direction. This patchs factorize the layout logic. Goal is to reduce code size and reuse it for the |gridbox| dom element. Bug: https://github.com/ArthurSonzogni/FTXUI/issues/114
This commit is contained in:
parent
4450cca31a
commit
71299daea4
@ -46,6 +46,8 @@ add_library(dom STATIC
|
||||
src/ftxui/dom/blink.cpp
|
||||
src/ftxui/dom/bold.cpp
|
||||
src/ftxui/dom/border.cpp
|
||||
src/ftxui/dom/box_helper.cpp
|
||||
src/ftxui/dom/box_helper.hpp
|
||||
src/ftxui/dom/clear_under.cpp
|
||||
src/ftxui/dom/color.cpp
|
||||
src/ftxui/dom/composite_decorator.cpp
|
||||
|
85
src/ftxui/dom/box_helper.cpp
Normal file
85
src/ftxui/dom/box_helper.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
#include "ftxui/dom/box_helper.hpp"
|
||||
|
||||
namespace ftxui {
|
||||
namespace box_helper {
|
||||
|
||||
namespace {
|
||||
// Called when the size allowed is greater than the requested size. This
|
||||
// distributes the extra spaces toward the flexible elements, in relative
|
||||
// proportions.
|
||||
void ComputeGrow(std::vector<Element>* elements,
|
||||
int extra_space,
|
||||
int flex_grow_sum) {
|
||||
for (Element& element : *elements) {
|
||||
int added_space =
|
||||
extra_space * element.flex_grow / std::max(flex_grow_sum, 1);
|
||||
extra_space -= added_space;
|
||||
flex_grow_sum -= element.flex_grow;
|
||||
element.size = element.min_size + added_space;
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the size allowed is lower than the requested size, and the
|
||||
// shrinkable element can absorbe the (negative) extra_space. This distribute
|
||||
// the extra_space toward those.
|
||||
void ComputeShrinkEasy(std::vector<Element>* elements,
|
||||
int extra_space,
|
||||
int flex_shrink_sum) {
|
||||
for (Element& element : *elements) {
|
||||
int added_space = extra_space * element.min_size * element.flex_shrink /
|
||||
std::max(flex_shrink_sum, 1);
|
||||
extra_space -= added_space;
|
||||
flex_shrink_sum -= element.flex_shrink * element.min_size;
|
||||
element.size = element.min_size + added_space;
|
||||
}
|
||||
}
|
||||
|
||||
// Called when the size allowed is lower than the requested size, and the
|
||||
// shrinkable element can not absorbe the (negative) extra_space. This assign
|
||||
// zero to shrinkable elements and distribute the remaining (negative)
|
||||
// extra_space toward the other non shrinkable elements.
|
||||
void ComputeShrinkHard(std::vector<Element>* elements,
|
||||
int extra_space,
|
||||
int size) {
|
||||
for (Element& element : *elements) {
|
||||
if (element.flex_shrink) {
|
||||
element.size = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
int added_space = extra_space * element.min_size / std::max(1, size);
|
||||
extra_space -= added_space;
|
||||
size -= element.min_size;
|
||||
|
||||
element.size = element.min_size + added_space;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void Compute(std::vector<Element>* elements, int target_size) {
|
||||
int size = 0;
|
||||
int flex_grow_sum = 0;
|
||||
int flex_shrink_sum = 0;
|
||||
int flex_shrink_size = 0;
|
||||
|
||||
for (auto& element : *elements) {
|
||||
flex_grow_sum += element.flex_grow;
|
||||
flex_shrink_sum += element.min_size * element.flex_shrink;
|
||||
if (element.flex_shrink)
|
||||
flex_shrink_size += element.min_size;
|
||||
size += element.min_size;
|
||||
}
|
||||
|
||||
int extra_space = target_size - size;
|
||||
if (extra_space >= 0)
|
||||
ComputeGrow(elements, extra_space, flex_grow_sum);
|
||||
else if (flex_shrink_size + extra_space >= 0)
|
||||
ComputeShrinkEasy(elements, extra_space, flex_shrink_sum);
|
||||
else
|
||||
ComputeShrinkHard(elements, extra_space + flex_shrink_size,
|
||||
size - flex_shrink_size);
|
||||
}
|
||||
|
||||
} // namespace box_helper
|
||||
} // namespace ftxui
|
24
src/ftxui/dom/box_helper.hpp
Normal file
24
src/ftxui/dom/box_helper.hpp
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef FTXUI_DOM_BOX_HELPER_HPP
|
||||
#define FTXUI_DOM_BOX_HELPER_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace ftxui {
|
||||
namespace box_helper {
|
||||
|
||||
struct Element {
|
||||
// Input:
|
||||
int min_size = 0;
|
||||
int flex_grow = 0;
|
||||
int flex_shrink = 0;
|
||||
|
||||
// Output;
|
||||
int size = 0;
|
||||
};
|
||||
|
||||
void Compute(std::vector<Element>* elements, int target_size);
|
||||
|
||||
} // namespace box_helper
|
||||
} // namespace ftxui
|
||||
|
||||
#endif /* end of include guard: FTXUI_DOM_BOX_HELPER_HPP */
|
@ -3,6 +3,7 @@
|
||||
#include <utility> // for move
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/dom/box_helper.hpp" // for Box
|
||||
#include "ftxui/dom/elements.hpp" // for Element, Elements, hbox
|
||||
#include "ftxui/dom/node.hpp" // for Node
|
||||
#include "ftxui/dom/requirement.hpp" // for Requirement
|
||||
@ -38,92 +39,23 @@ class HBox : public Node {
|
||||
void SetBox(Box box) override {
|
||||
Node::SetBox(box);
|
||||
|
||||
int space = box.x_max - box.x_min + 1;
|
||||
int extra_space = space - requirement_.min_x;
|
||||
|
||||
int size = 0;
|
||||
int flex_grow_sum = 0;
|
||||
int flex_shrink_sum = 0;
|
||||
int flex_shrink_size = 0;
|
||||
for (auto& child : children_) {
|
||||
const Requirement& r = child->requirement();
|
||||
flex_grow_sum += r.flex_grow_x;
|
||||
flex_shrink_sum += r.min_x * r.flex_shrink_x;
|
||||
if (r.flex_shrink_x) {
|
||||
flex_shrink_size += r.min_x;
|
||||
}
|
||||
size += r.min_x;
|
||||
std::vector<box_helper::Element> elements(children_.size());
|
||||
for (size_t i = 0; i < children_.size(); ++i) {
|
||||
auto& element = elements[i];
|
||||
const auto& requirement = children_[i]->requirement();
|
||||
element.min_size = requirement.min_x;
|
||||
element.flex_grow = requirement.flex_grow_x;
|
||||
element.flex_shrink = requirement.flex_shrink_x;
|
||||
}
|
||||
int target_size = box.x_max - box.x_min + 1;
|
||||
box_helper::Compute(&elements, target_size);
|
||||
|
||||
if (extra_space >= 0)
|
||||
SetBoxGrow(box, extra_space, flex_grow_sum);
|
||||
else if (flex_shrink_size + extra_space >= 0)
|
||||
SetBoxShrinkEasy(box, extra_space, flex_shrink_sum);
|
||||
else
|
||||
SetBoxShrinkHard(box, extra_space + flex_shrink_size,
|
||||
size - flex_shrink_size);
|
||||
}
|
||||
|
||||
void SetBoxGrow(Box box, int extra_space, int flex_grow_sum) {
|
||||
int x = box.x_min;
|
||||
for (auto& child : children_) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
int added_space =
|
||||
extra_space * r.flex_grow_x / std::max(flex_grow_sum, 1);
|
||||
extra_space -= added_space;
|
||||
flex_grow_sum -= r.flex_grow_x;
|
||||
|
||||
child_box.x_min = x;
|
||||
child_box.x_max = x + r.min_x + added_space - 1;
|
||||
|
||||
child->SetBox(child_box);
|
||||
x = child_box.x_max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBoxShrinkEasy(Box box, int extra_space, int flex_shrink_sum) {
|
||||
int x = box.x_min;
|
||||
for (auto& child : children_) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
int added_space = extra_space * r.min_x * r.flex_shrink_x /
|
||||
std::max(flex_shrink_sum, 1);
|
||||
extra_space -= added_space;
|
||||
flex_shrink_sum -= r.flex_shrink_x * r.min_x;
|
||||
|
||||
child_box.x_min = x;
|
||||
child_box.x_max = x + r.min_x + added_space - 1;
|
||||
|
||||
child->SetBox(child_box);
|
||||
x = child_box.x_max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBoxShrinkHard(Box box, int extra_space, int size) {
|
||||
int x = box.x_min;
|
||||
for (auto& child : children_) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
if (r.flex_shrink_x) {
|
||||
child_box.x_min = x;
|
||||
child_box.x_max = x - 1;
|
||||
child->SetBox(child_box);
|
||||
continue;
|
||||
}
|
||||
|
||||
int added_space = extra_space * r.min_x / std::max(1, size);
|
||||
extra_space -= added_space;
|
||||
size -= r.min_x;
|
||||
|
||||
child_box.x_min = x;
|
||||
child_box.x_max = x + r.min_x + added_space - 1;
|
||||
|
||||
child->SetBox(child_box);
|
||||
x = child_box.x_max + 1;
|
||||
for (size_t i = 0; i < children_.size(); ++i) {
|
||||
box.x_min = x;
|
||||
box.x_max = x + elements[i].size - 1;
|
||||
children_[i]->SetBox(box);
|
||||
x = box.x_max + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <utility> // for move
|
||||
#include <vector> // for vector
|
||||
|
||||
#include "ftxui/dom/box_helper.hpp" // for Box
|
||||
#include "ftxui/dom/elements.hpp" // for Element, Elements, vbox
|
||||
#include "ftxui/dom/node.hpp" // for Node
|
||||
#include "ftxui/dom/requirement.hpp" // for Requirement
|
||||
@ -38,92 +39,23 @@ class VBox : public Node {
|
||||
void SetBox(Box box) override {
|
||||
Node::SetBox(box);
|
||||
|
||||
int space = box.y_max - box.y_min + 1;
|
||||
int extra_space = space - requirement_.min_y;
|
||||
|
||||
int size = 0;
|
||||
int flex_grow_sum = 0;
|
||||
int flex_shrink_sum = 0;
|
||||
int flex_shrink_size = 0;
|
||||
for (auto& child : children_) {
|
||||
const Requirement& r = child->requirement();
|
||||
flex_grow_sum += r.flex_grow_y;
|
||||
flex_shrink_sum += r.min_y * r.flex_shrink_y;
|
||||
if (r.flex_shrink_y) {
|
||||
flex_shrink_size += r.min_y;
|
||||
}
|
||||
size += r.min_y;
|
||||
std::vector<box_helper::Element> elements(children_.size());
|
||||
for (size_t i = 0; i < children_.size(); ++i) {
|
||||
auto& element = elements[i];
|
||||
const auto& requirement = children_[i]->requirement();
|
||||
element.min_size = requirement.min_y;
|
||||
element.flex_grow = requirement.flex_grow_y;
|
||||
element.flex_shrink = requirement.flex_shrink_y;
|
||||
}
|
||||
int target_size = box.y_max - box.y_min + 1;
|
||||
box_helper::Compute(&elements, target_size);
|
||||
|
||||
if (extra_space >= 0)
|
||||
SetBoxGrow(box, extra_space, flex_grow_sum);
|
||||
else if (flex_shrink_size + extra_space >= 0)
|
||||
SetBoxShrinkEasy(box, extra_space, flex_shrink_sum);
|
||||
else
|
||||
SetBoxShrinkHard(box, extra_space + flex_shrink_size,
|
||||
size - flex_shrink_size);
|
||||
}
|
||||
|
||||
void SetBoxGrow(Box box, int extra_space, int flex_grow_sum) {
|
||||
int y = box.y_min;
|
||||
for (auto& child : children_) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
int added_space =
|
||||
extra_space * r.flex_grow_y / std::max(flex_grow_sum, 1);
|
||||
extra_space -= added_space;
|
||||
flex_grow_sum -= r.flex_grow_y;
|
||||
|
||||
child_box.y_min = y;
|
||||
child_box.y_max = y + r.min_y + added_space - 1;
|
||||
|
||||
child->SetBox(child_box);
|
||||
y = child_box.y_max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBoxShrinkEasy(Box box, int extra_space, int flex_shrink_sum) {
|
||||
int y = box.y_min;
|
||||
for (auto& child : children_) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
int added_space = extra_space * r.min_y * r.flex_shrink_y /
|
||||
std::max(flex_shrink_sum, 1);
|
||||
extra_space -= added_space;
|
||||
flex_shrink_sum -= r.flex_shrink_y * r.min_y;
|
||||
|
||||
child_box.y_min = y;
|
||||
child_box.y_max = y + r.min_y + added_space - 1;
|
||||
|
||||
child->SetBox(child_box);
|
||||
y = child_box.y_max + 1;
|
||||
}
|
||||
}
|
||||
|
||||
void SetBoxShrinkHard(Box box, int extra_space, int size) {
|
||||
int y = box.y_min;
|
||||
for (auto& child : children_) {
|
||||
Box child_box = box;
|
||||
const Requirement& r = child->requirement();
|
||||
|
||||
if (r.flex_shrink_y) {
|
||||
child_box.y_min = y;
|
||||
child_box.y_max = y - 1;
|
||||
child->SetBox(child_box);
|
||||
continue;
|
||||
}
|
||||
|
||||
int added_space = extra_space * r.min_y / std::max(1, size);
|
||||
extra_space -= added_space;
|
||||
size -= r.min_y;
|
||||
|
||||
child_box.y_min = y;
|
||||
child_box.y_max = y + r.min_y + added_space - 1;
|
||||
|
||||
child->SetBox(child_box);
|
||||
y = child_box.y_max + 1;
|
||||
int x = box.x_min;
|
||||
for (size_t i = 0; i < children_.size(); ++i) {
|
||||
box.y_min = x;
|
||||
box.y_max = x + elements[i].size - 1;
|
||||
children_[i]->SetBox(box);
|
||||
x = box.y_max + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user