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