FTXUI  5.0.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
frame.cpp
Go to the documentation of this file.
1// Copyright 2020 Arthur Sonzogni. All rights reserved.
2// Use of this source code is governed by the MIT license that can be found in
3// the LICENSE file.
4#include <algorithm> // for max, min
5#include <memory> // for make_shared, __shared_ptr_access
6#include <utility> // for move
7
8#include "ftxui/dom/elements.hpp" // for Element, unpack, Elements, focus, frame, select, xframe, yframe
9#include "ftxui/dom/node.hpp" // for Node, Elements
10#include "ftxui/dom/requirement.hpp" // for Requirement, Requirement::FOCUSED, Requirement::SELECTED
11#include "ftxui/screen/box.hpp" // for Box
12#include "ftxui/screen/screen.hpp" // for Screen, Screen::Cursor
13#include "ftxui/util/autoreset.hpp" // for AutoReset
14
15namespace ftxui {
16
17namespace {
18class Select : public Node {
19 public:
20 explicit Select(Elements children) : Node(std::move(children)) {}
21
22 void ComputeRequirement() override {
24 requirement_ = children_[0]->requirement();
25 auto& selected_box = requirement_.selected_box;
26 selected_box.x_min = 0;
27 selected_box.y_min = 0;
28 selected_box.x_max = requirement_.min_x - 1;
29 selected_box.y_max = requirement_.min_y - 1;
30 requirement_.selection = Requirement::SELECTED;
31 }
32
33 void SetBox(Box box) override {
35 children_[0]->SetBox(box);
36 }
37};
38
39class Focus : public Select {
40 public:
41 using Select::Select;
42
43 void ComputeRequirement() override {
44 Select::ComputeRequirement();
45 requirement_.selection = Requirement::FOCUSED;
46 }
47
48 void Render(Screen& screen) override {
49 Select::Render(screen);
50
51 // Setting the cursor to the right position allow folks using CJK (China,
52 // Japanese, Korean, ...) characters to see their [input method editor]
53 // displayed at the right location. See [issue].
54 //
55 // [input method editor]:
56 // https://en.wikipedia.org/wiki/Input_method
57 //
58 // [issue]:
59 // https://github.com/ArthurSonzogni/FTXUI/issues/2#issuecomment-505282355
60 //
61 // Unfortunately, Microsoft terminal do not handle properly hidding the
62 // cursor. Instead the character under the cursor is hidden, which is a big
63 // problem. As a result, we can't enable setting cursor to the right
64 // location. It will be displayed at the bottom right corner.
65 // See:
66 // https://github.com/microsoft/terminal/issues/1203
67 // https://github.com/microsoft/terminal/issues/3093
68#if !defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
69 screen.SetCursor(Screen::Cursor{
70 box_.x_min,
71 box_.y_min,
73 });
74#endif
75 }
76};
77
78class Frame : public Node {
79 public:
80 Frame(Elements children, bool x_frame, bool y_frame)
81 : Node(std::move(children)), x_frame_(x_frame), y_frame_(y_frame) {}
82
83 void ComputeRequirement() override {
85 requirement_ = children_[0]->requirement();
86 }
87
88 void SetBox(Box box) override {
90 auto& selected_box = requirement_.selected_box;
91 Box children_box = box;
92
93 if (x_frame_) {
94 const int external_dimx = box.x_max - box.x_min;
95 const int internal_dimx = std::max(requirement_.min_x, external_dimx);
96 const int focused_dimx = selected_box.x_max - selected_box.x_min;
97 int dx = selected_box.x_min - external_dimx / 2 + focused_dimx / 2;
98 dx = std::max(0, std::min(internal_dimx - external_dimx - 1, dx));
99 children_box.x_min = box.x_min - dx;
100 children_box.x_max = box.x_min + internal_dimx - dx;
101 }
102
103 if (y_frame_) {
104 const int external_dimy = box.y_max - box.y_min;
105 const int internal_dimy = std::max(requirement_.min_y, external_dimy);
106 const int focused_dimy = selected_box.y_max - selected_box.y_min;
107 int dy = selected_box.y_min - external_dimy / 2 + focused_dimy / 2;
108 dy = std::max(0, std::min(internal_dimy - external_dimy - 1, dy));
109 children_box.y_min = box.y_min - dy;
110 children_box.y_max = box.y_min + internal_dimy - dy;
111 }
112
113 children_[0]->SetBox(children_box);
114 }
115
116 void Render(Screen& screen) override {
117 const AutoReset<Box> stencil(&screen.stencil,
118 Box::Intersection(box_, screen.stencil));
119 children_[0]->Render(screen);
120 }
121
122 private:
123 bool x_frame_;
124 bool y_frame_;
125};
126
127class FocusCursor : public Focus {
128 public:
129 FocusCursor(Elements children, Screen::Cursor::Shape shape)
130 : Focus(std::move(children)), shape_(shape) {}
131
132 private:
133 void Render(Screen& screen) override {
134 Select::Render(screen); // NOLINT
135 screen.SetCursor(Screen::Cursor{
136 box_.x_min,
137 box_.y_min,
138 shape_,
139 });
140 }
142};
143
144} // namespace
145
146/// @brief Set the `child` to be the one selected among its siblings.
147/// @param child The element to be selected.
148/// @ingroup dom
150 return std::make_shared<Select>(unpack(std::move(child)));
151}
152
153/// @brief Set the `child` to be the one in focus globally.
154/// @param child The element to be focused.
155/// @ingroup dom
157 return std::make_shared<Focus>(unpack(std::move(child)));
158}
159
160/// @brief Allow an element to be displayed inside a 'virtual' area. It size can
161/// be larger than its container. In this case only a smaller portion is
162/// displayed. The view is scrollable to make the focused element visible.
163/// @see frame
164/// @see xframe
165/// @see yframe
167 return std::make_shared<Frame>(unpack(std::move(child)), true, true);
168}
169
170/// @brief Same as `frame`, but only on the x-axis.
171/// @see frame
172/// @see xframe
173/// @see yframe
175 return std::make_shared<Frame>(unpack(std::move(child)), true, false);
176}
177
178/// @brief Same as `frame`, but only on the y-axis.
179/// @see frame
180/// @see xframe
181/// @see yframe
183 return std::make_shared<Frame>(unpack(std::move(child)), false, true);
184}
185
186/// @brief Same as `focus`, but set the cursor shape to be a still block.
187/// @see focus
188/// @see focusCursorBlock
189/// @see focusCursorBlockBlinking
190/// @see focusCursorBar
191/// @see focusCursorBarBlinking
192/// @see focusCursorUnderline
193/// @see focusCursorUnderlineBlinking
194/// @ingroup dom
196 return std::make_shared<FocusCursor>(unpack(std::move(child)),
198}
199
200/// @brief Same as `focus`, but set the cursor shape to be a blinking block.
201/// @see focus
202/// @see focusCursorBlock
203/// @see focusCursorBlockBlinking
204/// @see focusCursorBar
205/// @see focusCursorBarBlinking
206/// @see focusCursorUnderline
207/// @see focusCursorUnderlineBlinking
208/// @ingroup dom
210 return std::make_shared<FocusCursor>(unpack(std::move(child)),
212}
213
214/// @brief Same as `focus`, but set the cursor shape to be a still block.
215/// @see focus
216/// @see focusCursorBlock
217/// @see focusCursorBlockBlinking
218/// @see focusCursorBar
219/// @see focusCursorBarBlinking
220/// @see focusCursorUnderline
221/// @see focusCursorUnderlineBlinking
222/// @ingroup dom
224 return std::make_shared<FocusCursor>(unpack(std::move(child)),
226}
227
228/// @brief Same as `focus`, but set the cursor shape to be a blinking bar.
229/// @see focus
230/// @see focusCursorBlock
231/// @see focusCursorBlockBlinking
232/// @see focusCursorBar
233/// @see focusCursorBarBlinking
234/// @see focusCursorUnderline
235/// @see focusCursorUnderlineBlinking
236/// @ingroup dom
238 return std::make_shared<FocusCursor>(unpack(std::move(child)),
240}
241
242/// @brief Same as `focus`, but set the cursor shape to be a still underline.
243/// @see focus
244/// @see focusCursorBlock
245/// @see focusCursorBlockBlinking
246/// @see focusCursorBar
247/// @see focusCursorBarBlinking
248/// @see focusCursorUnderline
249/// @see focusCursorUnderlineBlinking
250/// @ingroup dom
252 return std::make_shared<FocusCursor>(unpack(std::move(child)),
254}
255
256/// @brief Same as `focus`, but set the cursor shape to be a blinking underline.
257/// @see focus
258/// @see focusCursorBlock
259/// @see focusCursorBlockBlinking
260/// @see focusCursorBar
261/// @see focusCursorBarBlinking
262/// @see focusCursorUnderline
263/// @see focusCursorUnderlineBlinking
264/// @ingroup dom
266 return std::make_shared<FocusCursor>(unpack(std::move(child)),
268}
269
270} // namespace ftxui
virtual void SetBox(Box box)
Assign a position and a dimension to an element for drawing.
Definition node.cpp:26
virtual void ComputeRequirement()
Compute how much space an elements needs.
Definition node.cpp:18
Element focusCursorBarBlinking(Element)
Same as focus, but set the cursor shape to be a blinking bar.
Definition frame.cpp:237
std::shared_ptr< Node > Element
Definition elements.hpp:22
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:26
Element xframe(Element)
Same as frame, but only on the x-axis.
Definition frame.cpp:174
Element focusCursorUnderlineBlinking(Element)
Same as focus, but set the cursor shape to be a blinking underline.
Definition frame.cpp:265
Element focusCursorBar(Element)
Same as focus, but set the cursor shape to be a still block.
Definition frame.cpp:223
Element focusCursorBlock(Element)
Same as focus, but set the cursor shape to be a still block.
Definition frame.cpp:195
Element focusCursorUnderline(Element)
Same as focus, but set the cursor shape to be a still underline.
Definition frame.cpp:251
std::vector< Element > Elements
Definition elements.hpp:23
Element yframe(Element)
Same as frame, but only on the y-axis.
Definition frame.cpp:182
Element select(Element)
Set the child to be the one selected among its siblings.
Definition frame.cpp:149
Element focus(Element)
Set the child to be the one in focus globally.
Definition frame.cpp:156
Element frame(Element)
Allow an element to be displayed inside a 'virtual' area. It size can be larger than its container....
Definition frame.cpp:166
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Definition node.cpp:47
Element focusCursorBlockBlinking(Element)
Same as focus, but set the cursor shape to be a blinking block.
Definition frame.cpp:209
static auto Intersection(Box a, Box b) -> Box
Definition box.cpp:12