FTXUI 6.1.9
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)
52 : progress_(progress), direction_(direction) {
53 // This handle NAN correctly:
54 if (!(progress_ > 0.F)) {
55 progress_ = 0.F;
56 }
57 if (!(progress_ < 1.F)) {
58 progress_ = 1.F;
59 }
60 }
61
62 void ComputeRequirement() override {
63 switch (direction_) {
65 case Direction::Left:
66 requirement_.flex_grow_x = 1;
67 requirement_.flex_grow_y = 0;
68 requirement_.flex_shrink_x = 1;
69 requirement_.flex_shrink_y = 0;
70 break;
71 case Direction::Up:
72 case Direction::Down:
73 requirement_.flex_grow_x = 0;
74 requirement_.flex_grow_y = 1;
75 requirement_.flex_shrink_x = 0;
76 requirement_.flex_shrink_y = 1;
77 break;
78 }
79 requirement_.min_x = 1;
80 requirement_.min_y = 1;
81 }
82
83 void Render(Screen& screen) override {
84 switch (direction_) {
86 RenderHorizontal(screen, /*invert=*/false);
87 break;
88 case Direction::Up:
89 RenderVertical(screen, /*invert=*/false);
90 break;
91 case Direction::Left:
92 RenderHorizontal(screen, /*invert=*/true);
93 break;
94 case Direction::Down:
95 RenderVertical(screen, /*invert=*/true);
96 break;
97 }
98 }
99
100 void RenderHorizontal(Screen& screen, bool invert) {
101 if (box_.y_min > box_.y_max) {
102 return;
103 }
104
105 const auto* charset = Terminal::GetQuirks().block_characters
106 ? charset_horizontal
107 : charset_horizontal_microsoft;
108
109 // Draw the progress bar horizontally across the full allocated height:
110 const float progress = invert ? 1.F - progress_ : progress_;
111 const auto limit =
112 float(box_.x_min) + progress * float(box_.x_max - box_.x_min + 1);
113 const int limit_int = static_cast<int>(limit);
114
115 for (int y = box_.y_min; y <= box_.y_max; y++) {
116 int x = box_.x_min;
117 while (x < limit_int) {
118 screen.at(x++, y) = charset[9]; // NOLINT
119 }
120 // NOLINTNEXTLINE
121 screen.at(x++, y) = charset[int(9 * (limit - limit_int))];
122 while (x <= box_.x_max) {
123 screen.at(x++, y) = charset[0];
124 }
125 }
126
127 if (invert) {
128 Invert(screen);
129 }
130 }
131
132 void RenderVertical(Screen& screen, bool invert) {
133 if (box_.x_min > box_.x_max) {
134 return;
135 }
136
137 // Draw the progress bar vertically across the full allocated width:
138 const float progress = invert ? progress_ : 1.F - progress_;
139 const float limit =
140 float(box_.y_min) + progress * float(box_.y_max - box_.y_min + 1);
141 const int limit_int = static_cast<int>(limit);
142
143 for (int x = box_.x_min; x <= box_.x_max; x++) {
144 int y = box_.y_min;
145 while (y < limit_int) {
146 screen.at(x, y++) = charset_vertical[8]; // NOLINT
147 }
148 // NOLINTNEXTLINE
149 screen.at(x, y++) = charset_vertical[int(8 * (limit - limit_int))];
150 while (y <= box_.y_max) {
151 screen.at(x, y++) = charset_vertical[0];
152 }
153 }
154 if (invert) {
155 Invert(screen);
156 }
157 }
158
159 void Invert(Screen& screen) {
160 for (int y = box_.y_min; y <= box_.y_max; y++) {
161 for (int x = box_.x_min; x <= box_.x_max; x++) {
162 screen.CellAt(x, y).inverted ^= true;
163 }
164 }
165 }
166
167 private:
168 float progress_;
169 Direction direction_;
170};
171
172} // namespace
173
174/// @brief Draw a high definition progress bar progressing in specified
175/// direction.
176/// @param progress The proportion of the area to be filled. Belong to [0,1].
177/// @param direction Direction of progress bars progression.
178/// @ingroup dom
179Element gaugeDirection(float progress, Direction direction) {
180 return std::make_shared<Gauge>(progress, direction);
181}
182
183/// @brief Draw a high definition progress bar progressing from left to right.
184/// @param progress The proportion of the area to be filled. Belong to [0,1].
185/// @ingroup dom
186///
187/// ### Example
188///
189/// A gauge. It can be used to represent a progress bar.
190/// ~~~cpp
191/// border(gaugeRight(0.5))
192/// ~~~
193///
194/// #### Output
195///
196/// ~~~bash
197/// ┌──────────────────────────────────────────────────────────────────────────┐
198/// │█████████████████████████████████████ │
199/// └──────────────────────────────────────────────────────────────────────────┘
200/// ~~~
201Element gaugeRight(float progress) {
202 return gaugeDirection(progress, Direction::Right);
203}
204
205/// @brief Draw a high definition progress bar progressing from right to left.
206/// @param progress The proportion of the area to be filled. Belong to [0,1].
207/// @ingroup dom
208///
209/// ### Example
210///
211/// A gauge. It can be used to represent a progress bar.
212/// ~~~cpp
213/// border(gaugeLeft(0.5))
214/// ~~~
215///
216/// #### Output
217///
218/// ~~~bash
219/// ┌──────────────────────────────────────────────────────────────────────────┐
220/// │ █████████████████████████████████████│
221/// └──────────────────────────────────────────────────────────────────────────┘
222/// ~~~
223Element gaugeLeft(float progress) {
224 return gaugeDirection(progress, Direction::Left);
225}
226
227/// @brief Draw a high definition progress bar progressing from bottom to top.
228/// @param progress The proportion of the area to be filled. Belong to [0,1].
229/// @ingroup dom
230///
231/// ### Example
232///
233/// A gauge. It can be used to represent a progress bar.
234/// ~~~cpp
235/// border(gaugeUp(0.5))
236/// ~~~
237///
238/// #### Output
239///
240/// ~~~bash
241/// ┌─┐
242/// │ │
243/// │ │
244/// │ │
245/// │ │
246/// │█│
247/// │█│
248/// │█│
249/// │█│
250/// └─┘
251/// ~~~
252Element gaugeUp(float progress) {
253 return gaugeDirection(progress, Direction::Up);
254}
255
256/// @brief Draw a high definition progress bar progressing from top to bottom.
257/// @param progress The proportion of the area to be filled. Belong to [0,1].
258/// @ingroup dom
259///
260/// ### Example
261///
262/// A gauge. It can be used to represent a progress bar.
263/// ~~~cpp
264/// border(gaugeDown(0.5))
265/// ~~~
266///
267/// #### Output
268///
269/// ~~~bash
270/// ┌─┐
271/// │█│
272/// │█│
273/// │█│
274/// │█│
275/// │ │
276/// │ │
277/// │ │
278/// │ │
279/// └─┘
280/// ~~~
281Element gaugeDown(float progress) {
282 return gaugeDirection(progress, Direction::Down);
283}
284
285/// @brief Draw a high definition progress bar.
286/// @param progress The proportion of the area to be filled. Belong to [0,1].
287/// @ingroup dom
288///
289/// ### Example
290///
291/// A gauge. It can be used to represent a progress bar.
292/// ~~~cpp
293/// border(gauge(0.5))
294/// ~~~
295///
296/// #### Output
297///
298/// ~~~bash
299/// ┌──────────────────────────────────────────────────────────────────────────┐
300/// │█████████████████████████████████████ │
301/// └──────────────────────────────────────────────────────────────────────────┘
302/// ~~~
303Element gauge(float progress) {
304 return gaugeRight(progress);
305}
306
307} // namespace ftxui
Element gaugeDirection(float progress, Direction direction)
Draw a high definition progress bar progressing in specified direction.
Direction
Direction is an enumeration that represents the four cardinal directions.
Definition direction.hpp:13
Element gaugeRight(float progress)
Draw a high definition progress bar progressing from left to right.
Element gaugeUp(float progress)
Draw a high definition progress bar progressing from bottom to top.
Element gaugeLeft(float progress)
Draw a high definition progress bar progressing from right to left.
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Definition node.cpp:84
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.
bool block_characters
Whether the terminal font supports the 8 Unicode block characters.
Definition terminal.hpp:37
Quirks GetQuirks()
Get the terminal quirks.
Definition terminal.cpp:183
The FTXUI ftxui:: namespace.
Definition animation.hpp:10
std::shared_ptr< Node > Element
Definition elements.hpp:23