FTXUI 6.1.9
C++ functional terminal UI.
Loading...
Searching...
No Matches
src/ftxui/component/slider.cpp
Go to the documentation of this file.
1// Copyright 2020 Arthur Sonzogni. All rights reserved.
2// このソースコードの使用は、LICENSEファイルにあるMITライセンスに準拠します。
3#include <algorithm> // for max, min
4#include <ftxui/component/component_options.hpp> // for SliderOption
5#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
6#include <string> // for allocator
7#include <utility> // for move
8
9#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
10#include "ftxui/component/component.hpp" // for Make, Slider
11#include "ftxui/component/component_base.hpp" // for ComponentBase
12#include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp
13#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released
14#include "ftxui/component/screen_interactive.hpp" // for Component
15#include "ftxui/dom/elements.hpp" // for operator|, text, Element, xflex, hbox, color, underlined, reflect, Decorator, dim, vcenter, focus, nothing, select, yflex, gaugeDirection
16#include "ftxui/screen/box.hpp" // for Box
17#include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White
18#include "ftxui/util/ref.hpp" // for ConstRef, Ref, ConstStringRef
19
20namespace ftxui {
21
22namespace {
23Decorator flexDirection(Direction direction) {
24 switch (direction) {
25 case Direction::Up:
26 case Direction::Down:
27 return yflex;
28 case Direction::Left:
30 return xflex;
31 }
32 return xflex; // NOT_REACHED()
33}
34
35Direction Opposite(Direction d) {
36 switch (d) {
37 case Direction::Up:
38 return Direction::Down;
39 case Direction::Down:
40 return Direction::Up;
41 case Direction::Left:
42 return Direction::Right;
44 return Direction::Left;
45 }
46 return d; // NOT_REACHED()
47}
48
49template <class T>
50class SliderBase : public SliderOption<T>, public ComponentBase {
51 public:
52 explicit SliderBase(SliderOption<T> options) : SliderOption<T>(options) {}
53
54 Element OnRender() override {
55 auto gauge_color =
56 Focused() ? color(this->color_active) : color(this->color_inactive);
57 const float percent =
58 float(this->value() - this->min()) / float(this->max() - this->min());
59 return gaugeDirection(percent, this->direction) |
60 flexDirection(this->direction) | reflect(gauge_box_) | gauge_color;
61 }
62
63 void OnDirection(Direction pressed) {
64 if (pressed == this->direction) {
65 this->value() += this->increment();
66 return;
67 }
68
69 if (pressed == Opposite(this->direction)) {
70 this->value() -= this->increment();
71 return;
72 }
73 }
74
75 bool OnEvent(Event event) final {
76 if (event.is_mouse()) {
77 return OnMouseEvent(event);
78 }
79
80 T old_value = this->value();
81 if (event == Event::ArrowLeft || event == Event::Character('h')) {
82 OnDirection(Direction::Left);
83 }
84 if (event == Event::ArrowRight || event == Event::Character('l')) {
85 OnDirection(Direction::Right);
86 }
87 if (event == Event::ArrowUp || event == Event::Character('k')) {
88 OnDirection(Direction::Up);
89 }
90 if (event == Event::ArrowDown || event == Event::Character('j')) {
91 OnDirection(Direction::Down);
92 }
93
94 this->value() = std::max(this->min(), std::min(this->max(), this->value()));
95 if (old_value != this->value()) {
96 if (this->on_change) {
97 this->on_change();
98 }
99 return true;
100 }
101
102 return ComponentBase::OnEvent(event);
103 }
104
105 bool OnCapturedMouseEvent(Event event) {
106 if (event.mouse().motion == Mouse::Released) {
107 captured_mouse_ = nullptr;
108 return true;
109 }
110
111 T old_value = this->value();
112 switch (this->direction) {
113 case Direction::Right: {
114 this->value() = this->min() + (event.mouse().x - gauge_box_.x_min) *
115 (this->max() - this->min()) /
116 (gauge_box_.x_max - gauge_box_.x_min);
117
118 break;
119 }
120 case Direction::Left: {
121 this->value() = this->max() - (event.mouse().x - gauge_box_.x_min) *
122 (this->max() - this->min()) /
123 (gauge_box_.x_max - gauge_box_.x_min);
124 break;
125 }
126 case Direction::Down: {
127 this->value() = this->min() + (event.mouse().y - gauge_box_.y_min) *
128 (this->max() - this->min()) /
129 (gauge_box_.y_max - gauge_box_.y_min);
130 break;
131 }
132 case Direction::Up: {
133 this->value() = this->max() - (event.mouse().y - gauge_box_.y_min) *
134 (this->max() - this->min()) /
135 (gauge_box_.y_max - gauge_box_.y_min);
136 break;
137 }
138 }
139
140 this->value() = std::max(this->min(), std::min(this->max(), this->value()));
141
142 if (old_value != this->value() && this->on_change) {
143 this->on_change();
144 }
145 return true;
146 }
147
148 bool OnMouseEvent(Event event) {
149 if (captured_mouse_) {
150 return OnCapturedMouseEvent(event);
151 }
152
153 if (event.mouse().button != Mouse::Left) {
154 return false;
155 }
156 if (event.mouse().motion != Mouse::Pressed) {
157 return false;
158 }
159
160 if (!gauge_box_.Contain(event.mouse().x, event.mouse().y)) {
161 return false;
162 }
163
164 captured_mouse_ = CaptureMouse(event);
165
166 if (captured_mouse_) {
167 TakeFocus();
168 return OnCapturedMouseEvent(event);
169 }
170
171 return false;
172 }
173
174 bool Focusable() const final { return true; }
175
176 private:
177 Box gauge_box_;
178 CapturedMouse captured_mouse_;
179};
180
181class SliderWithLabel : public ComponentBase {
182 public:
183 SliderWithLabel(ConstStringRef label, Component inner)
184 : label_(std::move(label)) {
185 Add(std::move(inner));
186 SetActiveChild(ChildAt(0));
187 }
188
189 private:
190 bool OnEvent(Event event) final {
191 if (ComponentBase::OnEvent(event)) {
192 return true;
193 }
194
195 if (!event.is_mouse()) {
196 return false;
197 }
198
199 mouse_hover_ = box_.Contain(event.mouse().x, event.mouse().y);
200
201 if (!mouse_hover_) {
202 return false;
203 }
204
205 if (!CaptureMouse(event)) {
206 return false;
207 }
208
209 return true;
210 }
211
212 Element OnRender() override {
213 auto gauge_color = (Focused() || mouse_hover_) ? color(Color::White)
215 auto element = hbox({
216 text(label_()) | dim | vcenter,
217 hbox({
218 text("["),
220 text("]"),
221 }) | xflex,
222 }) |
223 gauge_color | xflex | reflect(box_);
224
225 element |= focus;
226 return element;
227 }
228
229 ConstStringRef label_;
230 Box box_;
231 bool mouse_hover_ = false;
232};
233
234} // namespace
235
236/// @brief 水平スライダー。
237/// @param label スライダーの名前。
238/// @param value スライダーの現在の値。
239/// @param min 最小値。
240/// @param max 最大値。
241/// @param increment カーソルによる増分値。
242/// @ingroup component
243///
244/// ### 例
245///
246/// ```cpp
247/// auto screen = ScreenInteractive::TerminalOutput();
248/// int value = 50;
249/// auto slider = Slider("Value:", &value, 0, 100, 1);
250/// screen.Loop(slider);
251/// ```
252///
253/// ### 出力
254///
255/// ```bash
256/// Value:[██████████████████████████ ]
257/// ```
259 Ref<int> value,
260 ConstRef<int> min,
261 ConstRef<int> max,
262 ConstRef<int> increment) {
263 SliderOption<int> option;
264 option.value = value;
265 option.min = min;
266 option.max = max;
267 option.increment = increment;
268 auto slider = Make<SliderBase<int>>(option);
269 return Make<SliderWithLabel>(std::move(label), slider);
270}
271
273 Ref<float> value,
274 ConstRef<float> min,
275 ConstRef<float> max,
276 ConstRef<float> increment) {
277 SliderOption<float> option;
278 option.value = value;
279 option.min = min;
280 option.max = max;
281 option.increment = increment;
282 auto slider = Make<SliderBase<float>>(option);
283 return Make<SliderWithLabel>(std::move(label), slider);
284}
286 Ref<long> value,
287 ConstRef<long> min,
288 ConstRef<long> max,
289 ConstRef<long> increment) {
290 SliderOption<long> option;
291 option.value = value;
292 option.min = min;
293 option.max = max;
294 option.increment = increment;
295 auto slider = Make<SliderBase<long>>(option);
296 return Make<SliderWithLabel>(std::move(label), slider);
297}
298
299/// @brief どの方向にも対応するスライダー。
300/// @param options オプション。
301/// ### 例
302///
303/// ```cpp
304/// auto screen = ScreenInteractive::TerminalOutput();
305/// int value = 50;
306/// auto slider = Slider({
307/// .value = &value,
308/// .min = 0,
309/// .max = 100,
310/// .increment= 20,
311/// });
312/// screen.Loop(slider);
313/// ```
314template <typename T>
316 return Make<SliderBase<T>>(options);
317}
318
323
328
331
332} // namespace ftxui
アダプター。不変オブジェクトを所有または参照します。
Definition ref.hpp:16
アダプター。定数文字列を所有または参照します。便宜上、このクラスは複数の不変文字列を共有表現に変換します。
Definition ref.hpp:91
アダプター。可変オブジェクトを所有または参照します。
Definition ref.hpp:45
Element Render()
コンポーネントを描画します。 このftxui::ComponentBaseを表すftxui::Screen上に描画されるftxui::Elementを構築します。レンダリングを変更するにはOnRende...
static const Event ArrowUp
Definition event.hpp:41
static const Event ArrowDown
Definition event.hpp:42
virtual bool OnEvent(Event)
イベントに応じて呼び出されます。
static const Event ArrowLeft
Definition event.hpp:39
static const Event ArrowRight
Definition event.hpp:40
Element xflex(Element)
必要に応じてX軸上で拡大・縮小します。
Definition flex.cpp:126
Element gaugeDirection(float progress, Direction direction)
指定された方向に進行する高精細プログレスバーを描画します。
Direction
Directionは、東西南北の4つの基本方向を表す列挙型です。
Definition direction.hpp:11
Element yflex(Element)
必要に応じてY軸上で拡大・縮小します。
Definition flex.cpp:132
Element underlined(Element)
指定された要素に下線を追加します。
Element text(std::wstring text)
ユニコードテキストを表示します。
Definition text.cpp:160
Element focus(Element)
子要素を兄弟要素の中でフォーカスされたものとして設定します。
Definition frame.cpp:101
Element vcenter(Element)
要素を垂直方向に中央揃えします。
Decorator color(Color)
前景色を使用して装飾します。
FTXUI ftxui:: 名前空間
Definition animation.hpp:9
std::function< Element(Element)> Decorator
Definition elements.hpp:23
std::unique_ptr< CapturedMouseInterface > CapturedMouse
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:26
std::shared_ptr< Node > Element
Definition elements.hpp:21
Element hbox(Elements)
要素を水平方向に1つずつ表示するコンテナ。
Definition hbox.cpp:93
Component Slider(SliderOption< T > options)
どの方向にも対応するスライダー。
Decorator reflect(Box &box)
Definition reflect.cpp:42
std::shared_ptr< ComponentBase > Component