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 // 在 fuzzer 設法獲得以下情況時的額外字元:
23 // int(9 * (limit - limit_int) = 9
24 "█"};
25
26// NOLINTNEXTLINE
27static const std::string charset_horizontal_microsoft[11] = {
28 " ", " ", " ", " ", "▌", "▌", "▌", "█", "█", "█",
29 // 在 fuzzer 設法獲得以下情況時的額外字元:
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 // 在 fuzzer 設法獲得以下情況時的額外字元:
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 // 這能正確處理 NAN:
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` 是 `charset` 中「full」字符的索引;邊界
108 // 儲存格會選擇索引 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 // 在整個分配到的高度範圍內水平繪製進度條:
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 // 在整個分配到的寬度範圍內垂直繪製進度條:
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 繪製一個指定方向的高解析度進度條。
200/// @param progress 填充區域的比例。範圍為 [0,1]。
201/// @param direction 進度條的進展方向。
202/// @ingroup dom
204 return std::make_shared<Gauge>(progress, direction);
205}
206
207/// @brief 繪製一個從左到右進展的高解析度進度條。
208/// @param progress 填充區域的比例。範圍為 [0,1]。
209/// @ingroup dom
210///
211/// ### 範例
212///
213/// 一個儀表。它可以用來表示進度條。
214/// ~~~cpp
215/// border(gaugeRight(0.5))
216/// ~~~
217///
218/// #### 輸出
219///
220/// ~~~bash
221/// ┌──────────────────────────────────────────────────────────────────────────┐
222/// │█████████████████████████████████████ │
223/// └──────────────────────────────────────────────────────────────────────────┘
224/// ~~~
225Element gaugeRight(float progress) {
226 return gaugeDirection(progress, Direction::Right);
227}
228
229/// @brief 繪製一個從右到左進展的高解析度進度條。
230/// @param progress 填充區域的比例。範圍為 [0,1]。
231/// @ingroup dom
232///
233/// ### 範例
234///
235/// 一個儀表。它可以用來表示進度條。
236/// ~~~cpp
237/// border(gaugeLeft(0.5))
238/// ~~~
239///
240/// #### 輸出
241///
242/// ~~~bash
243/// ┌──────────────────────────────────────────────────────────────────────────┐
244/// │ █████████████████████████████████████│
245/// └──────────────────────────────────────────────────────────────────────────┘
246/// ~~~
247Element gaugeLeft(float progress) {
248 return gaugeDirection(progress, Direction::Left);
249}
250
251/// @brief 繪製一個從下到上進展的高解析度進度條。
252/// @param progress 填充區域的比例。範圍為 [0,1]。
253/// @ingroup dom
254///
255/// ### 範例
256///
257/// 一個儀表。它可以用來表示進度條。
258/// ~~~cpp
259/// border(gaugeUp(0.5))
260/// ~~~
261///
262/// #### 輸出
263///
264/// ~~~bash
265/// ┌─┐
266/// │ │
267/// │ │
268/// │ │
269/// │ │
270/// │█│
271/// │█│
272/// │█│
273/// │█│
274/// └─┘
275/// ~~~
276Element gaugeUp(float progress) {
277 return gaugeDirection(progress, Direction::Up);
278}
279
280/// @brief 繪製一個從上到下進展的高解析度進度條。
281/// @param progress 填充區域的比例。範圍為 [0,1]。
282/// @ingroup dom
283///
284/// ### 範例
285///
286/// 一個儀表。它可以用來表示進度條。
287/// ~~~cpp
288/// border(gaugeDown(0.5))
289/// ~~~
290///
291/// #### 輸出
292///
293/// ~~~bash
294/// ┌─┐
295/// │█│
296/// │█│
297/// │█│
298/// │█│
299/// │ │
300/// │ │
301/// │ │
302/// │ │
303/// └─┘
304/// ~~~
305Element gaugeDown(float progress) {
306 return gaugeDirection(progress, Direction::Down);
307}
308
309/// @brief 繪製一個高解析度進度條。
310/// @param progress 填充區域的比例。範圍為 [0,1]。
311/// @ingroup dom
312///
313/// ### 範例
314///
315/// 一個儀表。它可以用來表示進度條。
316/// ~~~cpp
317/// border(gauge(0.5))
318/// ~~~
319///
320/// #### 輸出
321///
322/// ~~~bash
323/// ┌──────────────────────────────────────────────────────────────────────────┐
324/// │█████████████████████████████████████ │
325/// └──────────────────────────────────────────────────────────────────────────┘
326/// ~~~
327Element gauge(float progress) {
328 return gaugeRight(progress);
329}
330
331/// @brief 使用自訂字元集繪製高解析度進度條。
332/// @param progress 要填滿的區域比例。屬於 [0,1]。
333/// @param charset 從「空」(索引 0)到「滿」(最後一個索引)的字符;
334/// 只有 2 個項目的字元集會產生單純無陰影的進度條。
335/// @param direction 進度條前進的方向。預設為
336/// Right。
337/// @ingroup dom
338///
339/// ### 範例
340///
341/// 使用自訂字元集而非預設方塊字符繪製的進度條。
342/// ~~~cpp
343/// border(gaugeCharset(0.5, {".", "#"}))
344/// ~~~
345///
346/// #### 輸出
347///
348/// ~~~bash
349/// ┌──────────────────────────────────────────────────────────────────────────┐
350/// │#####################################.....................................│
351/// └──────────────────────────────────────────────────────────────────────────┘
352/// ~~~
353Element gaugeCharset(float progress,
354 std::vector<std::string> charset,
356 return std::make_shared<Gauge>(progress, direction, std::move(charset));
357}
358
359} // namespace ftxui
Element gaugeDirection(float progress, Direction direction)
繪製一個指定方向的高解析度進度條。
Element gaugeRight(float progress)
繪製一個從左到右進展的高解析度進度條。
Direction
Direction 是一個列舉,表示四個主要方向。
Definition direction.hpp:14
Element gaugeUp(float progress)
繪製一個從下到上進展的高解析度進度條。
Element gaugeCharset(float progress, std::vector< std::string > charset, Direction direction=Direction::Right)
使用自訂字元集繪製高解析度進度條。
Element gaugeLeft(float progress)
繪製一個從右到左進展的高解析度進度條。
Element gauge(float progress)
繪製一個高解析度進度條。
Element gaugeDown(float progress)
繪製一個從上到下進展的高解析度進度條。
Quirks GetQuirks()
取得終端機的怪癖行為(quirks)。
Definition terminal.cpp:353
FTXUI ftxui:: 命名空間
Definition animation.hpp:11
std::shared_ptr< Node > Element
Definition elements.hpp:25
Direction direction
Definition elements.hpp:80
int y
Definition elements.hpp:131
void Render(Screen &screen, Node *node, Selection &selection)
Definition node.cpp:105
const Charset & charset_