FTXUI  0.8.1
C++ functional terminal UI.
frame.cpp
Go to the documentation of this file.
1 #include <algorithm> // for max, min
2 #include <memory> // for make_shared, shared_ptr, __shared_ptr_access
3 #include <utility> // for move
4 #include <vector> // for vector, __alloc_traits<>::value_type
5 
6 #include "ftxui/dom/elements.hpp" // for Element, unpack, focus, frame, select, xframe, yframe
7 #include "ftxui/dom/node.hpp" // for Node
8 #include "ftxui/dom/requirement.hpp" // for Requirement, Requirement::FOCUSED, Requirement::SELECTED
9 #include "ftxui/screen/box.hpp" // for Box
10 #include "ftxui/screen/screen.hpp" // for Screen, Screen::Cursor
11 #include "ftxui/util/autoreset.hpp" // for AutoReset
12 
13 namespace ftxui {
14 
15 // -----------------------------------------------------------------------------
16 
17 class Select : public Node {
18  public:
19  Select(Elements children) : Node(std::move(children)) {}
20 
21  void ComputeRequirement() override {
23  requirement_ = children_[0]->requirement();
24  auto& selected_box = requirement_.selected_box;
25  selected_box.x_min = 0;
26  selected_box.y_min = 0;
27  selected_box.x_max = requirement_.min_x;
28  selected_box.y_max = requirement_.min_y;
30  };
31 
32  void SetBox(Box box) override {
33  Node::SetBox(box);
34  children_[0]->SetBox(box);
35  }
36 };
37 
39  return std::make_shared<Select>(unpack(std::move(child)));
40 }
41 
42 // -----------------------------------------------------------------------------
43 
44 class Focus : public Select {
45  public:
46  using Select::Select;
47 
48  void ComputeRequirement() override {
49  Select::ComputeRequirement();
50  requirement_.selection = Requirement::FOCUSED;
51  };
52 
53  void Render(Screen& screen) override {
54  Select::Render(screen);
55 
56  // Setting the cursor to the right position allow folks using CJK (China,
57  // Japanese, Korean, ...) characters to see their [input method editor]
58  // displayed at the right location. See [issue].
59  //
60  // [input method editor]:
61  // https://en.wikipedia.org/wiki/Input_method
62  //
63  // [issue]:
64  // https://github.com/ArthurSonzogni/FTXUI/issues/2#issuecomment-505282355
65  //
66  // Unfortunately, Microsoft terminal do not handle properly hidding the
67  // cursor. Instead the character under the cursor is hidden, which is a big
68  // problem. As a result, we can't enable setting cursor to the right
69  // location. It will be displayed at the bottom right corner.
70  // See:
71  // https://github.com/microsoft/terminal/issues/1203
72  // https://github.com/microsoft/terminal/issues/3093
73 #if !defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
74  screen.SetCursor(Screen::Cursor{box_.x_min, box_.y_min});
75 #endif
76  }
77 };
78 
80  return std::make_shared<Focus>(unpack(std::move(child)));
81 }
82 
83 // -----------------------------------------------------------------------------
84 
85 class Frame : public Node {
86  public:
87  Frame(Elements children, bool x_frame, bool y_frame)
88  : Node(std::move(children)), x_frame_(x_frame), y_frame_(y_frame) {}
89 
90  void ComputeRequirement() override {
92  requirement_ = children_[0]->requirement();
93  }
94 
95  void SetBox(Box box) override {
96  Node::SetBox(box);
97  auto& selected_box = requirement_.selected_box;
98  Box children_box = box;
99 
100  if (x_frame_) {
101  int external_dimx = box.x_max - box.x_min;
102  int internal_dimx = std::max(requirement_.min_x, external_dimx);
103  int focused_dimx = selected_box.x_max - selected_box.x_min;
104  int dx = selected_box.x_min - external_dimx / 2 + focused_dimx / 2;
105  dx = std::max(0, std::min(internal_dimx - external_dimx - 1, dx));
106  children_box.x_min = box.x_min - dx;
107  children_box.x_max = box.x_min + internal_dimx - dx;
108  }
109 
110  if (y_frame_) {
111  int external_dimy = box.y_max - box.y_min;
112  int internal_dimy = std::max(requirement_.min_y, external_dimy);
113  int focused_dimy = selected_box.y_max - selected_box.y_min;
114  int dy = selected_box.y_min - external_dimy / 2 + focused_dimy / 2;
115  dy = std::max(0, std::min(internal_dimy - external_dimy - 1, dy));
116  children_box.y_min = box.y_min - dy;
117  children_box.y_max = box.y_min + internal_dimy - dy;
118  }
119 
120  children_[0]->SetBox(children_box);
121  }
122 
123  void Render(Screen& screen) override {
124  AutoReset<Box> stencil(&screen.stencil,
125  Box::Intersection(box_, screen.stencil));
126  children_[0]->Render(screen);
127  }
128 
129  private:
130  bool x_frame_;
131  bool y_frame_;
132 };
133 
134 /// @brief Allow an element to be displayed inside a 'virtual' area. It size can
135 /// be larger than its container. In this case only a smaller portion is
136 /// displayed. The view is scrollable to make the focused element visible.
137 /// @see focus
139  return std::make_shared<Frame>(unpack(std::move(child)), true, true);
140 }
141 
143  return std::make_shared<Frame>(unpack(std::move(child)), true, false);
144 }
145 
147  return std::make_shared<Frame>(unpack(std::move(child)), false, true);
148 }
149 
150 } // namespace ftxui
151 
152 // Copyright 2020 Arthur Sonzogni. All rights reserved.
153 // Use of this source code is governed by the MIT license that can be found in
154 // the LICENSE file.
ftxui::Requirement::selected_box
Box selected_box
Definition: requirement.hpp:26
ftxui::Node::SetBox
virtual void SetBox(Box box)
Assign a position and a dimension to an element for drawing.
Definition: node.cpp:21
ftxui::Requirement::min_x
int min_x
Definition: requirement.hpp:10
autoreset.hpp
ftxui::focus
Element focus(Element)
Definition: frame.cpp:79
ftxui::Box::x_min
int x_min
Definition: box.hpp:7
ftxui::Node::box_
Box box_
Definition: node.hpp:41
ftxui
Definition: captured_mouse.hpp:6
ftxui::frame
Element frame(Element)
Allow an element to be displayed inside a 'virtual' area. It size can be larger than its container....
Definition: frame.cpp:138
ftxui::yframe
Element yframe(Element)
Definition: frame.cpp:146
node.hpp
ftxui::Node::children_
Elements children_
Definition: node.hpp:39
box.hpp
requirement.hpp
ftxui::Box::Intersection
static Box Intersection(Box a, Box b)
Definition: box.cpp:9
ftxui::Box::x_max
int x_max
Definition: box.hpp:8
ftxui::Elements
std::vector< Element > Elements
Definition: elements.hpp:16
ftxui::select
Element select(Element)
Definition: frame.cpp:38
elements.hpp
ftxui::Node::Node
Node()
Definition: node.cpp:8
ftxui::Requirement::SELECTED
@ SELECTED
Definition: requirement.hpp:22
ftxui::xframe
Element xframe(Element)
Definition: frame.cpp:142
ftxui::Element
std::shared_ptr< Node > Element
Definition: elements.hpp:15
ftxui::Box::y_min
int y_min
Definition: box.hpp:9
ftxui::Requirement::selection
Selection selection
Definition: requirement.hpp:25
ftxui::Requirement::min_y
int min_y
Definition: requirement.hpp:11
ftxui::Render
void Render(Screen &screen, const Element &node)
Display an element on a ftxui::Screen.
Definition: node.cpp:34
ftxui::Node::requirement_
Requirement requirement_
Definition: node.hpp:40
ftxui::Node::ComputeRequirement
virtual void ComputeRequirement()
Compute how much space an elements needs.
Definition: node.cpp:14
screen.hpp
ftxui::Requirement::FOCUSED
@ FOCUSED
Definition: requirement.hpp:23