FTXUI/src/ftxui/dom/frame.cpp

137 lines
4.4 KiB
C++
Raw Normal View History

2021-05-10 02:32:27 +08:00
#include <algorithm> // for max, min
#include <ext/alloc_traits.h> // for __alloc_traits<>::value_type
#include <memory> // for make_shared, shared_ptr, __shared_ptr_access
#include <utility> // for move
#include <vector> // for vector
2020-03-23 05:32:44 +08:00
2021-05-02 02:40:35 +08:00
#include "ftxui/dom/elements.hpp" // for Element, unpack, focus, frame, select, xframe, yframe
#include "ftxui/dom/node.hpp" // for Node
#include "ftxui/dom/requirement.hpp" // for Requirement, Requirement::FOCUSED, Requirement::SELECTED
#include "ftxui/screen/box.hpp" // for Box
#include "ftxui/screen/screen.hpp" // for Screen, Screen::Cursor
#include "ftxui/util/autoreset.hpp" // for AutoReset
namespace ftxui {
2019-01-20 05:06:05 +08:00
// -----------------------------------------------------------------------------
class Select : public Node {
public:
Select(std::vector<std::shared_ptr<Node>> children)
2019-01-20 05:06:05 +08:00
: Node(std::move(children)) {}
void ComputeRequirement() override {
Node::ComputeRequirement();
requirement_ = children[0]->requirement();
auto& selected_box = requirement_.selected_box;
selected_box.x_min = 0;
selected_box.y_min = 0;
2020-06-01 22:13:29 +08:00
selected_box.x_max = requirement_.min_x;
selected_box.y_max = requirement_.min_y;
2019-01-20 05:06:05 +08:00
requirement_.selection = Requirement::SELECTED;
};
void SetBox(Box box) override {
box_ = box;
children[0]->SetBox(box);
}
};
Element select(Element child) {
return std::make_shared<Select>(unpack(std::move(child)));
2019-01-20 05:06:05 +08:00
}
// -----------------------------------------------------------------------------
class Focus : public Select {
public:
2020-05-21 02:51:07 +08:00
Focus(std::vector<Element> children) : Select(std::move(children)) {}
2019-01-20 05:06:05 +08:00
void ComputeRequirement() override {
Select::ComputeRequirement();
requirement_.selection = Requirement::FOCUSED;
};
void Render(Screen& screen) override {
Select::Render(screen);
screen.SetCursor(Screen::Cursor{box_.x_min, box_.y_min});
}
2019-01-20 05:06:05 +08:00
};
Element focus(Element child) {
return std::make_shared<Focus>(unpack(std::move(child)));
2019-01-20 05:06:05 +08:00
}
// -----------------------------------------------------------------------------
class Frame : public Node {
public:
2020-05-25 07:34:13 +08:00
Frame(std::vector<Element> children, bool x_frame, bool y_frame)
: Node(std::move(children)), x_frame_(x_frame), y_frame_(y_frame) {}
void ComputeRequirement() override {
Node::ComputeRequirement();
requirement_ = children[0]->requirement();
}
void SetBox(Box box) override {
Node::SetBox(box);
2019-01-20 05:06:05 +08:00
auto& selected_box = requirement_.selected_box;
Box children_box = box;
2020-06-07 21:54:45 +08:00
if (x_frame_) {
int external_dimx = box.x_max - box.x_min;
int internal_dimx = std::max(requirement_.min_x, external_dimx);
int focused_dimx = selected_box.x_max - selected_box.x_min;
int dx = selected_box.x_min - external_dimx / 2 + focused_dimx / 2;
dx = std::max(0, std::min(internal_dimx - external_dimx - 1, dx));
children_box.x_min = box.x_min - dx;
children_box.x_max = box.x_min + internal_dimx - dx;
}
if (y_frame_) {
int external_dimy = box.y_max - box.y_min;
int internal_dimy = std::max(requirement_.min_y, external_dimy);
int focused_dimy = selected_box.y_max - selected_box.y_min;
int dy = selected_box.y_min - external_dimy / 2 + focused_dimy / 2;
dy = std::max(0, std::min(internal_dimy - external_dimy - 1, dy));
children_box.y_min = box.y_min - dy;
children_box.y_max = box.y_min + internal_dimy - dy;
}
2019-01-20 05:06:05 +08:00
2020-06-07 21:54:45 +08:00
children[0]->SetBox(children_box);
}
void Render(Screen& screen) override {
2019-01-20 05:06:05 +08:00
AutoReset<Box> stencil(&screen.stencil,
Box::Intersection(box_, screen.stencil));
children[0]->Render(screen);
}
2020-06-07 21:54:45 +08:00
private:
bool x_frame_;
bool y_frame_;
};
2020-05-25 07:34:13 +08:00
/// @brief Allow an element to be displayed inside a 'virtual' area. It size can
/// be larger than its container. In this case only a smaller portion is
/// displayed. The view is scrollable to make the focused element visible.
2020-08-16 08:24:50 +08:00
/// @see focus
Element frame(Element child) {
2020-06-07 21:54:45 +08:00
return std::make_shared<Frame>(unpack(std::move(child)), true, true);
}
Element xframe(Element child) {
return std::make_shared<Frame>(unpack(std::move(child)), true, false);
}
Element yframe(Element child) {
return std::make_shared<Frame>(unpack(std::move(child)), false, true);
}
2020-02-12 04:44:55 +08:00
} // namespace ftxui
// Copyright 2020 Arthur Sonzogni. All rights reserved.
// Use of this source code is governed by the MIT license that can be found in
// the LICENSE file.