FTXUI 7.0.3
C++ functional terminal UI.
Loading...
Searching...
No Matches
src/ftxui/dom/gauge.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 <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
5#include <memory> // for allocator, make_shared
6#include <string> // for string
7
8#include "ftxui/dom/elements.hpp" // for Element, gauge, gaugeDirection, gaugeDown, gaugeLeft, gaugeRight, gaugeUp
9#include "ftxui/dom/node.hpp" // for Node
10#include "ftxui/dom/requirement.hpp" // for Requirement
11#include "ftxui/screen/box.hpp" // for Box
12#include "ftxui/screen/screen.hpp" // for Screen, Cell
13
14#include "ftxui/screen/terminal.hpp" // for Quirks, GetQuirks
15
16namespace ftxui {
17
18namespace {
19// NOLINTNEXTLINE
20static const std::string charset_horizontal[11] = {
21 " ", " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█",
22 // An extra character in case when the fuzzer manage to have:
23 // int(9 * (limit - limit_int) = 9
24 "█"};
25
26// NOLINTNEXTLINE
27static const std::string charset_horizontal_microsoft[11] = {
28 " ", " ", " ", " ", "▌", "▌", "▌", "█", "█", "█",
29 // An extra character in case when the fuzzer manage to have:
30 // int(9 * (limit - limit_int) = 9
31 "█"};
32
33// NOLINTNEXTLINE
34static const std::string charset_vertical[10] = {
35 "█",
36 "▇",
37 "▆",
38 "▅",
39 "▄",
40 "▃",
41 "▂",
42 "▁",
43 " ",
44 // An extra character in case when the fuzzer manage to have:
45 // int(8 * (limit - limit_int) = 8
46 " ",
47};
48
49class Gauge : public Node {
50 public:
51 Gauge(float progress, Direction direction, std::vector<std::string> charset = {})
52 : progress_(progress),
53 direction_(direction),
54 charset_(std::move(charset)) {
55 // This handle NAN correctly:
56 if (!(progress_ > 0.F)) {
57 progress_ = 0.F;
58 }
59 if (!(progress_ < 1.F)) {
60 progress_ = 1.F;
61 }
62 }
63
64 void ComputeRequirement() override {
65 switch (direction_) {
67 case Direction::Left:
68 requirement_.flex_grow_x = 1;
69 requirement_.flex_grow_y = 0;
70 requirement_.flex_shrink_x = 1;
71 requirement_.flex_shrink_y = 0;
72 break;
73 case Direction::Up:
74 case Direction::Down:
75 requirement_.flex_grow_x = 0;
76 requirement_.flex_grow_y = 1;
77 requirement_.flex_shrink_x = 0;
78 requirement_.flex_shrink_y = 1;
79 break;
80 }
81 requirement_.min_x = 1;
82 requirement_.min_y = 1;
83 }
84
85 void Render(Screen& screen) override {
86 switch (direction_) {
88 RenderHorizontal(screen, /*invert=*/false);
89 break;
90 case Direction::Up:
91 RenderVertical(screen, /*invert=*/false);
92 break;
93 case Direction::Left:
94 RenderHorizontal(screen, /*invert=*/true);
95 break;
96 case Direction::Down:
97 RenderVertical(screen, /*invert=*/true);
98 break;
99 }
100 }
101
102 void RenderHorizontal(Screen& screen, bool invert) {
103 if (box_.y_min > box_.y_max) {
104 return;
105 }
106
107 // `full` is the index of the "full" glyph in `charset`; the boundary
108 // cell picks glyph index int(full * fractional_fill).
109 const std::string* charset;
110 int full;
111 if (charset_.empty()) {
112 charset = Terminal::GetQuirks().BlockCharacters() // NOLINT
113 ? charset_horizontal
114 : charset_horizontal_microsoft;
115 full = 9;
116 } else {
117 charset = charset_.data();
118 full = static_cast<int>(charset_.size()) - 1;
119 }
120
121 // Draw the progress bar horizontally across the full allocated height:
122 const float progress = invert ? 1.F - progress_ : progress_;
123 const auto limit =
124 float(box_.x_min) + progress * float(box_.x_max - box_.x_min + 1);
125 const int limit_int = static_cast<int>(limit);
126
127 for (int y = box_.y_min; y <= box_.y_max; y++) {
128 int x = box_.x_min;
129 while (x < limit_int) {
130 screen.at(x++, y) = charset[full];
131 }
132 if (x <= box_.x_max) {
133 screen.at(x++, y) = charset[int(full * (limit - limit_int))];
134 }
135 while (x <= box_.x_max) {
136 screen.at(x++, y) = charset[0];
137 }
138 }
139
140 if (invert) {
141 Invert(screen);
142 }
143 }
144
145 void RenderVertical(Screen& screen, bool invert) {
146 if (box_.x_min > box_.x_max) {
147 return;
148 }
149
150 const std::string* charset;
151 int full;
152 if (charset_.empty()) {
153 charset = charset_vertical;
154 full = 8;
155 } else {
156 charset = charset_.data();
157 full = static_cast<int>(charset_.size()) - 1;
158 }
159
160 // Draw the progress bar vertically across the full allocated width:
161 const float progress = invert ? progress_ : 1.F - progress_;
162 const float limit =
163 float(box_.y_min) + progress * float(box_.y_max - box_.y_min + 1);
164 const int limit_int = static_cast<int>(limit);
165
166 for (int x = box_.x_min; x <= box_.x_max; x++) {
167 int y = box_.y_min;
168 while (y < limit_int) {
169 screen.at(x, y++) = charset[full];
170 }
171 if (y <= box_.y_max) {
172 screen.at(x, y++) = charset[int(full * (limit - limit_int))];
173 }
174 while (y <= box_.y_max) {
175 screen.at(x, y++) = charset[0];
176 }
177 }
178 if (invert) {
179 Invert(screen);
180 }
181 }
182
183 void Invert(Screen& screen) {
184 for (int y = box_.y_min; y <= box_.y_max; y++) {
185 for (int x = box_.x_min; x <= box_.x_max; x++) {
186 screen.CellAt(x, y).inverted ^= true;
187 }
188 }
189 }
190
191 private:
192 float progress_;
193 Direction direction_;
194 std::vector<std::string> charset_;
195};
196
197} // namespace
198
199/// @brief Draw a high definition progress bar progressing in specified
200/// direction.
201/// @param progress The proportion of the area to be filled. Belong to [0,1].
202/// @param direction Direction of progress bars progression.
203/// @ingroup dom
205 return std::make_shared<Gauge>(progress, direction);
206}
207
208/// @brief Draw a high definition progress bar progressing from left to right.
209/// @param progress The proportion of the area to be filled. Belong to [0,1].
210/// @ingroup dom
211///
212/// ### Example
213///
214/// A gauge. It can be used to represent a progress bar.
215/// ~~~cpp
216/// border(gaugeRight(0.5))
217/// ~~~
218///
219/// #### Output
220///
221/// ~~~bash
222/// ┌──────────────────────────────────────────────────────────────────────────┐
223/// │█████████████████████████████████████ │
224/// └──────────────────────────────────────────────────────────────────────────┘
225/// ~~~
226Element gaugeRight(float progress) {
227 return gaugeDirection(progress, Direction::Right);
228}
229
230/// @brief Draw a high definition progress bar progressing from right to left.
231/// @param progress The proportion of the area to be filled. Belong to [0,1].
232/// @ingroup dom
233///
234/// ### Example
235///
236/// A gauge. It can be used to represent a progress bar.
237/// ~~~cpp
238/// border(gaugeLeft(0.5))
239/// ~~~
240///
241/// #### Output
242///
243/// ~~~bash
244/// ┌──────────────────────────────────────────────────────────────────────────┐
245/// │ █████████████████████████████████████│
246/// └──────────────────────────────────────────────────────────────────────────┘
247/// ~~~
248Element gaugeLeft(float progress) {
249 return gaugeDirection(progress, Direction::Left);
250}
251
252/// @brief Draw a high definition progress bar progressing from bottom to top.
253/// @param progress The proportion of the area to be filled. Belong to [0,1].
254/// @ingroup dom
255///
256/// ### Example
257///
258/// A gauge. It can be used to represent a progress bar.
259/// ~~~cpp
260/// border(gaugeUp(0.5))
261/// ~~~
262///
263/// #### Output
264///
265/// ~~~bash
266/// ┌─┐
267/// │ │
268/// │ │
269/// │ │
270/// │ │
271/// │█│
272/// │█│
273/// │█│
274/// │█│
275/// └─┘
276/// ~~~
277Element gaugeUp(float progress) {
278 return gaugeDirection(progress, Direction::Up);
279}
280
281/// @brief Draw a high definition progress bar progressing from top to bottom.
282/// @param progress The proportion of the area to be filled. Belong to [0,1].
283/// @ingroup dom
284///
285/// ### Example
286///
287/// A gauge. It can be used to represent a progress bar.
288/// ~~~cpp
289/// border(gaugeDown(0.5))
290/// ~~~
291///
292/// #### Output
293///
294/// ~~~bash
295/// ┌─┐
296/// │█│
297/// │█│
298/// │█│
299/// │█│
300/// │ │
301/// │ │
302/// │ │
303/// │ │
304/// └─┘
305/// ~~~
306Element gaugeDown(float progress) {
307 return gaugeDirection(progress, Direction::Down);
308}
309
310/// @brief Draw a high definition progress bar.
311/// @param progress The proportion of the area to be filled. Belong to [0,1].
312/// @ingroup dom
313///
314/// ### Example
315///
316/// A gauge. It can be used to represent a progress bar.
317/// ~~~cpp
318/// border(gauge(0.5))
319/// ~~~
320///
321/// #### Output
322///
323/// ~~~bash
324/// ┌──────────────────────────────────────────────────────────────────────────┐
325/// │█████████████████████████████████████ │
326/// └──────────────────────────────────────────────────────────────────────────┘
327/// ~~~
328Element gauge(float progress) {
329 return gaugeRight(progress);
330}
331
332/// @brief Draw a high definition progress bar using a custom charset.
333/// @param progress The proportion of the area to be filled. Belong to [0,1].
334/// @param charset Glyphs from "empty" (index 0) to "full" (last index); a
335/// 2-entry charset gives a plain unshaded bar.
336/// @param direction Direction of progress bars progression. Defaults to
337/// Right.
338/// @ingroup dom
339///
340/// ### Example
341///
342/// A gauge rendered with a custom charset instead of the default block
343/// characters.
344/// ~~~cpp
345/// border(gaugeCharset(0.5, {".", "#"}))
346/// ~~~
347///
348/// #### Output
349///
350/// ~~~bash
351/// ┌──────────────────────────────────────────────────────────────────────────┐
352/// │#####################################.....................................│
353/// └──────────────────────────────────────────────────────────────────────────┘
354/// ~~~
355Element gaugeCharset(float progress,
356 std::vector<std::string> charset,
358 return std::make_shared<Gauge>(progress, direction, std::move(charset));
359}
360
361} // namespace ftxui
Element gaugeDirection(float progress, Direction direction)
Draw a high definition progress bar progressing in specified direction.
Element gaugeRight(float progress)
Draw a high definition progress bar progressing from left to right.
Direction
Direction is an enumeration that represents the four cardinal directions.
Definition direction.hpp:15
Element gaugeUp(float progress)
Draw a high definition progress bar progressing from bottom to top.
Element gaugeCharset(float progress, std::vector< std::string > charset, Direction direction=Direction::Right)
Draw a high definition progress bar using a custom charset.
Element gaugeLeft(float progress)
Draw a high definition progress bar progressing from right to left.
Element gauge(float progress)
Draw a high definition progress bar.
Element gaugeDown(float progress)
Draw a high definition progress bar progressing from top to bottom.
Quirks GetQuirks()
Get the terminal quirks.
Definition terminal.cpp:365
The FTXUI ftxui:: namespace.
Definition animation.hpp:11
std::shared_ptr< Node > Element
Definition elements.hpp:25
Direction direction
Definition elements.hpp:83
int y
Definition elements.hpp:134
void Render(Screen &screen, Node *node, Selection &selection)
Definition node.cpp:105
const Charset & charset_