mirror of
https://github.com/ArthurSonzogni/FTXUI.git
synced 2024-11-22 18:59:59 +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/blink.cpp
|
||||||
src/ftxui/dom/bold.cpp
|
src/ftxui/dom/bold.cpp
|
||||||
src/ftxui/dom/border.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/clear_under.cpp
|
||||||
src/ftxui/dom/color.cpp
|
src/ftxui/dom/color.cpp
|
||||||
src/ftxui/dom/composite_decorator.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 <utility> // for move
|
||||||
#include <vector> // for vector
|
#include <vector> // for vector
|
||||||
|
|
||||||
|
#include "ftxui/dom/box_helper.hpp" // for Box
|
||||||
#include "ftxui/dom/elements.hpp" // for Element, Elements, hbox
|
#include "ftxui/dom/elements.hpp" // for Element, Elements, hbox
|
||||||
#include "ftxui/dom/node.hpp" // for Node
|
#include "ftxui/dom/node.hpp" // for Node
|
||||||
#include "ftxui/dom/requirement.hpp" // for Requirement
|
#include "ftxui/dom/requirement.hpp" // for Requirement
|
||||||
@ -38,92 +39,23 @@ class HBox : public Node {
|
|||||||
void SetBox(Box box) override {
|
void SetBox(Box box) override {
|
||||||
Node::SetBox(box);
|
Node::SetBox(box);
|
||||||
|
|
||||||
int space = box.x_max - box.x_min + 1;
|
std::vector<box_helper::Element> elements(children_.size());
|
||||||
int extra_space = space - requirement_.min_x;
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
|
auto& element = elements[i];
|
||||||
int size = 0;
|
const auto& requirement = children_[i]->requirement();
|
||||||
int flex_grow_sum = 0;
|
element.min_size = requirement.min_x;
|
||||||
int flex_shrink_sum = 0;
|
element.flex_grow = requirement.flex_grow_x;
|
||||||
int flex_shrink_size = 0;
|
element.flex_shrink = requirement.flex_shrink_x;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
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;
|
int x = box.x_min;
|
||||||
for (auto& child : children_) {
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
Box child_box = box;
|
box.x_min = x;
|
||||||
const Requirement& r = child->requirement();
|
box.x_max = x + elements[i].size - 1;
|
||||||
|
children_[i]->SetBox(box);
|
||||||
int added_space =
|
x = box.x_max + 1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
#include <utility> // for move
|
#include <utility> // for move
|
||||||
#include <vector> // for vector
|
#include <vector> // for vector
|
||||||
|
|
||||||
|
#include "ftxui/dom/box_helper.hpp" // for Box
|
||||||
#include "ftxui/dom/elements.hpp" // for Element, Elements, vbox
|
#include "ftxui/dom/elements.hpp" // for Element, Elements, vbox
|
||||||
#include "ftxui/dom/node.hpp" // for Node
|
#include "ftxui/dom/node.hpp" // for Node
|
||||||
#include "ftxui/dom/requirement.hpp" // for Requirement
|
#include "ftxui/dom/requirement.hpp" // for Requirement
|
||||||
@ -38,92 +39,23 @@ class VBox : public Node {
|
|||||||
void SetBox(Box box) override {
|
void SetBox(Box box) override {
|
||||||
Node::SetBox(box);
|
Node::SetBox(box);
|
||||||
|
|
||||||
int space = box.y_max - box.y_min + 1;
|
std::vector<box_helper::Element> elements(children_.size());
|
||||||
int extra_space = space - requirement_.min_y;
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
|
auto& element = elements[i];
|
||||||
int size = 0;
|
const auto& requirement = children_[i]->requirement();
|
||||||
int flex_grow_sum = 0;
|
element.min_size = requirement.min_y;
|
||||||
int flex_shrink_sum = 0;
|
element.flex_grow = requirement.flex_grow_y;
|
||||||
int flex_shrink_size = 0;
|
element.flex_shrink = requirement.flex_shrink_y;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
int target_size = box.y_max - box.y_min + 1;
|
||||||
|
box_helper::Compute(&elements, target_size);
|
||||||
|
|
||||||
if (extra_space >= 0)
|
int x = box.x_min;
|
||||||
SetBoxGrow(box, extra_space, flex_grow_sum);
|
for (size_t i = 0; i < children_.size(); ++i) {
|
||||||
else if (flex_shrink_size + extra_space >= 0)
|
box.y_min = x;
|
||||||
SetBoxShrinkEasy(box, extra_space, flex_shrink_sum);
|
box.y_max = x + elements[i].size - 1;
|
||||||
else
|
children_[i]->SetBox(box);
|
||||||
SetBoxShrinkHard(box, extra_space + flex_shrink_size,
|
x = box.y_max + 1;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user