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
14namespace ftxui {
15
16namespace {
17// NOLINTNEXTLINE
18static const std::string charset_horizontal[11] = {
19#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
20 // Microsoft's terminals often use fonts not handling the 8 unicode
21 // characters for representing the whole gauge. Fallback with less.
22 " ", " ", " ", " ", "▌", "▌", "▌", "█", "█", "█",
23#else
24 " ", " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█",
25#endif
26 // An extra character in case when the fuzzer manage to have:
27 // int(9 * (limit - limit_int) = 9
28 "█"};
29
30// NOLINTNEXTLINE
31static const std::string charset_vertical[10] = {
32 "█",
33 "▇",
34 "▆",
35 "▅",
36 "▄",
37 "▃",
38 "▂",
39 "▁",
40 " ",
41 // An extra character in case when the fuzzer manage to have:
42 // int(8 * (limit - limit_int) = 8
43 " ",
44};
45
46class Gauge : public Node {
47 public:
48 Gauge(float progress, Direction direction)
49 : progress_(progress), direction_(direction) {
50 // This handle NAN correctly:
51 if (!(progress_ > 0.F)) {
52 progress_ = 0.F;
53 }
54 if (!(progress_ < 1.F)) {
55 progress_ = 1.F;
56 }
57 }
58
59 void ComputeRequirement() override {
60 switch (direction_) {
62 case Direction::Left:
63 requirement_.flex_grow_x = 1;
64 requirement_.flex_grow_y = 0;
65 requirement_.flex_shrink_x = 1;
66 requirement_.flex_shrink_y = 0;
67 break;
68 case Direction::Up:
69 case Direction::Down:
70 requirement_.flex_grow_x = 0;
71 requirement_.flex_grow_y = 1;
72 requirement_.flex_shrink_x = 0;
73 requirement_.flex_shrink_y = 1;
74 break;
75 }
76 requirement_.min_x = 1;
77 requirement_.min_y = 1;
78 }
79
80 void Render(Screen& screen) override {
81 switch (direction_) {
83 RenderHorizontal(screen, /*invert=*/false);
84 break;
85 case Direction::Up:
86 RenderVertical(screen, /*invert=*/false);
87 break;
88 case Direction::Left:
89 RenderHorizontal(screen, /*invert=*/true);
90 break;
91 case Direction::Down:
92 RenderVertical(screen, /*invert=*/true);
93 break;
94 }
95 }
96
97 void RenderHorizontal(Screen& screen, bool invert) {
98 const int y = box_.y_min;
99 if (y > box_.y_max) {
100 return;
101 }
102
103 // Draw the progress bar horizontally across the full allocated height:
104 const float progress = invert ? 1.F - progress_ : progress_;
105 const auto limit =
106 float(box_.x_min) + progress * float(box_.x_max - box_.x_min + 1);
107 const int limit_int = static_cast<int>(limit);
108
109 for (int y = box_.y_min; y <= box_.y_max; y++) {
110 int x = box_.x_min;
111 while (x < limit_int) {
112 screen.at(x++, y) = charset_horizontal[9]; // NOLINT
113 }
114 // NOLINTNEXTLINE
115 screen.at(x++, y) = charset_horizontal[int(9 * (limit - limit_int))];
116 while (x <= box_.x_max) {
117 screen.at(x++, y) = charset_horizontal[0];
118 }
119 }
120
121 if (invert) {
122 Invert(screen);
123 }
124 }
125
126 void RenderVertical(Screen& screen, bool invert) {
127 const int x = box_.x_min;
128 if (x > box_.x_max) {
129 return;
130 }
131
132 // Draw the progress bar vertically across the full allocated width:
133 const float progress = invert ? progress_ : 1.F - progress_;
134 const float limit =
135 float(box_.y_min) + progress * float(box_.y_max - box_.y_min + 1);
136 const int limit_int = static_cast<int>(limit);
137
138 for (int x = box_.x_min; x <= box_.x_max; x++) {
139 int y = box_.y_min;
140 while (y < limit_int) {
141 screen.at(x, y++) = charset_vertical[8]; // NOLINT
142 }
143 // NOLINTNEXTLINE
144 screen.at(x, y++) = charset_vertical[int(8 * (limit - limit_int))];
145 while (y <= box_.y_max) {
146 screen.at(x, y++) = charset_vertical[0];
147 }
148 }
149 if (invert) {
150 Invert(screen);
151 }
152 }
153
154 void Invert(Screen& screen) {
155 for (int y = box_.y_min; y <= box_.y_max; y++) {
156 for (int x = box_.x_min; x <= box_.x_max; x++) {
157 screen.CellAt(x, y).inverted ^= true;
158 }
159 }
160 }
161
162 private:
163 float progress_;
164 Direction direction_;
165};
166
167} // namespace
168
169/// @brief Draw a high definition progress bar progressing in specified
170/// direction.
171/// @param progress The proportion of the area to be filled. Belong to [0,1].
172/// @param direction Direction of progress bars progression.
173/// @ingroup dom
174Element gaugeDirection(float progress, Direction direction) {
175 return std::make_shared<Gauge>(progress, direction);
176}
177
178/// @brief Draw a high definition progress bar progressing from left to right.
179/// @param progress The proportion of the area to be filled. Belong to [0,1].
180/// @ingroup dom
181///
182/// ### Example
183///
184/// A gauge. It can be used to represent a progress bar.
185/// ~~~cpp
186/// border(gaugeRight(0.5))
187/// ~~~
188///
189/// #### Output
190///
191/// ~~~bash
192/// ┌──────────────────────────────────────────────────────────────────────────┐
193/// │█████████████████████████████████████ │
194/// └──────────────────────────────────────────────────────────────────────────┘
195/// ~~~
196Element gaugeRight(float progress) {
197 return gaugeDirection(progress, Direction::Right);
198}
199
200/// @brief Draw a high definition progress bar progressing from right to left.
201/// @param progress The proportion of the area to be filled. Belong to [0,1].
202/// @ingroup dom
203///
204/// ### Example
205///
206/// A gauge. It can be used to represent a progress bar.
207/// ~~~cpp
208/// border(gaugeLeft(0.5))
209/// ~~~
210///
211/// #### Output
212///
213/// ~~~bash
214/// ┌──────────────────────────────────────────────────────────────────────────┐
215/// │ █████████████████████████████████████│
216/// └──────────────────────────────────────────────────────────────────────────┘
217/// ~~~
218Element gaugeLeft(float progress) {
219 return gaugeDirection(progress, Direction::Left);
220}
221
222/// @brief Draw a high definition progress bar progressing from bottom to top.
223/// @param progress The proportion of the area to be filled. Belong to [0,1].
224/// @ingroup dom
225///
226/// ### Example
227///
228/// A gauge. It can be used to represent a progress bar.
229/// ~~~cpp
230/// border(gaugeUp(0.5))
231/// ~~~
232///
233/// #### Output
234///
235/// ~~~bash
236/// ┌─┐
237/// │ │
238/// │ │
239/// │ │
240/// │ │
241/// │█│
242/// │█│
243/// │█│
244/// │█│
245/// └─┘
246/// ~~~
247Element gaugeUp(float progress) {
248 return gaugeDirection(progress, Direction::Up);
249}
250
251/// @brief Draw a high definition progress bar progressing from top to bottom.
252/// @param progress The proportion of the area to be filled. Belong to [0,1].
253/// @ingroup dom
254///
255/// ### Example
256///
257/// A gauge. It can be used to represent a progress bar.
258/// ~~~cpp
259/// border(gaugeDown(0.5))
260/// ~~~
261///
262/// #### Output
263///
264/// ~~~bash
265/// ┌─┐
266/// │█│
267/// │█│
268/// │█│
269/// │█│
270/// │ │
271/// │ │
272/// │ │
273/// │ │
274/// └─┘
275/// ~~~
276Element gaugeDown(float progress) {
277 return gaugeDirection(progress, Direction::Down);
278}
279
280/// @brief Draw a high definition progress bar.
281/// @param progress The proportion of the area to be filled. Belong to [0,1].
282/// @ingroup dom
283///
284/// ### Example
285///
286/// A gauge. It can be used to represent a progress bar.
287/// ~~~cpp
288/// border(gauge(0.5))
289/// ~~~
290///
291/// #### Output
292///
293/// ~~~bash
294/// ┌──────────────────────────────────────────────────────────────────────────┐
295/// │█████████████████████████████████████ │
296/// └──────────────────────────────────────────────────────────────────────────┘
297/// ~~~
298Element gauge(float progress) {
299 return gaugeRight(progress);
300}
301
302} // 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.
The FTXUI ftxui:: namespace.
Definition animation.hpp:10
std::shared_ptr< Node > Element
Definition elements.hpp:23