diff --git a/CMakeLists.txt b/CMakeLists.txt index d2ad461..67a3bd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,8 +46,6 @@ 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 diff --git a/src/ftxui/dom/box_helper.cpp b/src/ftxui/dom/box_helper.cpp deleted file mode 100644 index d90da2a..0000000 --- a/src/ftxui/dom/box_helper.cpp +++ /dev/null @@ -1,85 +0,0 @@ -#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* 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* 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* 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* 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 diff --git a/src/ftxui/dom/box_helper.hpp b/src/ftxui/dom/box_helper.hpp deleted file mode 100644 index 9e0ebda..0000000 --- a/src/ftxui/dom/box_helper.hpp +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef FTXUI_DOM_BOX_HELPER_HPP -#define FTXUI_DOM_BOX_HELPER_HPP - -#include - -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* elements, int target_size); - -} // namespace box_helper -} // namespace ftxui - -#endif /* end of include guard: FTXUI_DOM_BOX_HELPER_HPP */ diff --git a/src/ftxui/dom/hbox.cpp b/src/ftxui/dom/hbox.cpp index 55bc115..092e38f 100644 --- a/src/ftxui/dom/hbox.cpp +++ b/src/ftxui/dom/hbox.cpp @@ -3,7 +3,6 @@ #include // for move #include // 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 @@ -39,23 +38,92 @@ class HBox : public Node { void SetBox(Box box) override { Node::SetBox(box); - std::vector 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); + 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; + } + + 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 (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; + 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; } } }; diff --git a/src/ftxui/dom/vbox.cpp b/src/ftxui/dom/vbox.cpp index 6dd26e7..1ed02d8 100644 --- a/src/ftxui/dom/vbox.cpp +++ b/src/ftxui/dom/vbox.cpp @@ -3,7 +3,6 @@ #include // for move #include // 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 @@ -39,23 +38,92 @@ class VBox : public Node { void SetBox(Box box) override { Node::SetBox(box); - std::vector 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); + int space = box.y_max - box.y_min + 1; + int extra_space = space - requirement_.min_y; - 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; + 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; + } + + 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; } } };