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, Pixel
13
14namespace ftxui {
15
16namespace {
17// NOLINTNEXTLINE
18static const std::string charset_horizontal[11] = {
19#if defined(FTXUI_MICROSOFT_TERMINAL_FALLBACK)
20 // 微軟的終端機通常使用不支援 8 個 Unicode 字元來表示整個儀表。
21 // 使用較少的字元作為替代方案。
22 " ", " ", " ", " ", "▌", "▌", "▌", "█", "█", "█",
23#else
24 " ", " ", "▏", "▎", "▍", "▌", "▋", "▊", "▉", "█",
25#endif
26 // 在 fuzzer 設法獲得以下情況時的額外字元:
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 // 在 fuzzer 設法獲得以下情況時的額外字元:
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.
104 {
105 const float progress = invert ? 1.F - progress_ : progress_;
106 const auto limit =
107 float(box_.x_min) + progress * float(box_.x_max - box_.x_min + 1);
108 const int limit_int = static_cast<int>(limit);
109 int x = box_.x_min;
110 while (x < limit_int) {
111 screen.at(x++, y) = charset_horizontal[9]; // NOLINT
112 }
113 // NOLINTNEXTLINE
114 screen.at(x++, y) = charset_horizontal[int(9 * (limit - limit_int))];
115 while (x <= box_.x_max) {
116 screen.at(x++, y) = charset_horizontal[0];
117 }
118 }
119
120 if (invert) {
121 for (int x = box_.x_min; x <= box_.x_max; x++) {
122 screen.PixelAt(x, y).inverted ^= true;
123 }
124 }
125 }
126
127 void RenderVertical(Screen& screen, bool invert) {
128 const int x = box_.x_min;
129 if (x > box_.x_max) {
130 return;
131 }
132
133 // Draw the progress bar vertically:
134 {
135 const float progress = invert ? progress_ : 1.F - progress_;
136 const float limit =
137 float(box_.y_min) + progress * float(box_.y_max - box_.y_min + 1);
138 const int limit_int = static_cast<int>(limit);
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
150 if (invert) {
151 for (int y = box_.y_min; y <= box_.y_max; y++) {
152 screen.PixelAt(x, y).inverted ^= true;
153 }
154 }
155 }
156
157 private:
158 float progress_;
159 Direction direction_;
160};
161
162} // namespace
163
164/// @brief 繪製一個指定方向的高解析度進度條。
165/// @param progress 填充區域的比例。範圍為 [0,1]。
166/// @param direction 進度條的進展方向。
167/// @ingroup dom
168Element gaugeDirection(float progress, Direction direction) {
169 return std::make_shared<Gauge>(progress, direction);
170}
171
172/// @brief 繪製一個從左到右進展的高解析度進度條。
173/// @param progress 填充區域的比例。範圍為 [0,1]。
174/// @ingroup dom
175///
176/// ### 範例
177///
178/// 一個儀表。它可以用來表示進度條。
179/// ~~~cpp
180/// border(gaugeRight(0.5))
181/// ~~~
182///
183/// #### 輸出
184///
185/// ~~~bash
186/// ┌──────────────────────────────────────────────────────────────────────────┐
187/// │█████████████████████████████████████ │
188/// └──────────────────────────────────────────────────────────────────────────┘
189/// ~~~
190Element gaugeRight(float progress) {
191 return gaugeDirection(progress, Direction::Right);
192}
193
194/// @brief 繪製一個從右到左進展的高解析度進度條。
195/// @param progress 填充區域的比例。範圍為 [0,1]。
196/// @ingroup dom
197///
198/// ### 範例
199///
200/// 一個儀表。它可以用來表示進度條。
201/// ~~~cpp
202/// border(gaugeLeft(0.5))
203/// ~~~
204///
205/// #### 輸出
206///
207/// ~~~bash
208/// ┌──────────────────────────────────────────────────────────────────────────┐
209/// │ █████████████████████████████████████│
210/// └──────────────────────────────────────────────────────────────────────────┘
211/// ~~~
212Element gaugeLeft(float progress) {
213 return gaugeDirection(progress, Direction::Left);
214}
215
216/// @brief 繪製一個從下到上進展的高解析度進度條。
217/// @param progress 填充區域的比例。範圍為 [0,1]。
218/// @ingroup dom
219///
220/// ### 範例
221///
222/// 一個儀表。它可以用來表示進度條。
223/// ~~~cpp
224/// border(gaugeUp(0.5))
225/// ~~~
226///
227/// #### 輸出
228///
229/// ~~~bash
230/// ┌─┐
231/// │ │
232/// │ │
233/// │ │
234/// │ │
235/// │█│
236/// │█│
237/// │█│
238/// │█│
239/// └─┘
240/// ~~~
241Element gaugeUp(float progress) {
242 return gaugeDirection(progress, Direction::Up);
243}
244
245/// @brief 繪製一個從上到下進展的高解析度進度條。
246/// @param progress 填充區域的比例。範圍為 [0,1]。
247/// @ingroup dom
248///
249/// ### 範例
250///
251/// 一個儀表。它可以用來表示進度條。
252/// ~~~cpp
253/// border(gaugeDown(0.5))
254/// ~~~
255///
256/// #### 輸出
257///
258/// ~~~bash
259/// ┌─┐
260/// │█│
261/// │█│
262/// │█│
263/// │█│
264/// │ │
265/// │ │
266/// │ │
267/// │ │
268/// └─┘
269/// ~~~
270Element gaugeDown(float progress) {
271 return gaugeDirection(progress, Direction::Down);
272}
273
274/// @brief 繪製一個高解析度進度條。
275/// @param progress 填充區域的比例。範圍為 [0,1]。
276/// @ingroup dom
277///
278/// ### 範例
279///
280/// 一個儀表。它可以用來表示進度條。
281/// ~~~cpp
282/// border(gauge(0.5))
283/// ~~~
284///
285/// #### 輸出
286///
287/// ~~~bash
288/// ┌──────────────────────────────────────────────────────────────────────────┐
289/// │█████████████████████████████████████ │
290/// └──────────────────────────────────────────────────────────────────────────┘
291/// ~~~
292Element gauge(float progress) {
293 return gaugeRight(progress);
294}
295
296} // namespace ftxui
Element gaugeDirection(float progress, Direction direction)
繪製一個指定方向的高解析度進度條。
Direction
Direction 是一個列舉,表示四個主要方向。
Definition direction.hpp:12
Element gaugeRight(float progress)
繪製一個從左到右進展的高解析度進度條。
Element gaugeUp(float progress)
繪製一個從下到上進展的高解析度進度條。
Element gaugeLeft(float progress)
繪製一個從右到左進展的高解析度進度條。
Element gauge(float progress)
繪製一個高解析度進度條。
Element gaugeDown(float progress)
繪製一個從上到下進展的高解析度進度條。
FTXUI 的 ftxui:: 命名空間
Definition animation.hpp:10
std::shared_ptr< Node > Element
Definition elements.hpp:22
void Render(Screen &screen, const Element &element)