FTXUI  5.0.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
slider.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 <algorithm> // for max, min
5#include <ftxui/component/component_options.hpp> // for SliderOption
6#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
7#include <string> // for allocator
8#include <utility> // for move
9
10#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
11#include "ftxui/component/component.hpp" // for Make, Slider
12#include "ftxui/component/component_base.hpp" // for ComponentBase
13#include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowLeft, Event::ArrowRight, Event::ArrowUp
14#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released
15#include "ftxui/component/screen_interactive.hpp" // for Component
16#include "ftxui/dom/elements.hpp" // for operator|, text, Element, xflex, hbox, color, underlined, reflect, Decorator, dim, vcenter, focus, nothing, select, yflex, gaugeDirection
17#include "ftxui/screen/box.hpp" // for Box
18#include "ftxui/screen/color.hpp" // for Color, Color::GrayDark, Color::White
19#include "ftxui/screen/util.hpp" // for clamp
20#include "ftxui/util/ref.hpp" // for ConstRef, Ref, ConstStringRef
21
22namespace ftxui {
23
24namespace {
26 switch (direction) {
27 case Direction::Up:
28 case Direction::Down:
29 return yflex;
30 case Direction::Left:
32 return xflex;
33 }
34 return xflex; // NOT_REACHED()
35}
36
37template <class T>
38class SliderBase : public SliderOption<T>, public ComponentBase {
39 public:
40 explicit SliderBase(SliderOption<T> options) : SliderOption<T>(options) {}
41
42 Element Render() override {
43 auto gauge_color =
44 Focused() ? color(this->color_active) : color(this->color_inactive);
45 const float percent =
46 float(this->value() - this->min()) / float(this->max() - this->min());
47 return gaugeDirection(percent, this->direction) |
48 flexDirection(this->direction) | reflect(gauge_box_) | gauge_color;
49 }
50
51 void OnLeft() {
52 switch (this->direction) {
54 this->value() -= this->increment();
55 break;
56 case Direction::Left:
57 this->value() += this->increment();
58 break;
59 case Direction::Up:
60 case Direction::Down:
61 break;
62 }
63 }
64
65 void OnRight() {
66 switch (this->direction) {
68 this->value() += this->increment();
69 break;
70 case Direction::Left:
71 this->value() -= this->increment();
72 break;
73 case Direction::Up:
74 case Direction::Down:
75 break;
76 }
77 }
78
79 void OnUp() {
80 switch (this->direction) {
81 case Direction::Up:
82 this->value() -= this->increment();
83 break;
84 case Direction::Down:
85 this->value() += this->increment();
86 break;
87 case Direction::Left:
89 break;
90 }
91 }
92
93 void OnDown() {
94 switch (this->direction) {
95 case Direction::Down:
96 this->value() += this->increment();
97 break;
98 case Direction::Up:
99 this->value() -= this->increment();
100 break;
101 case Direction::Left:
102 case Direction::Right:
103 break;
104 }
105 }
106
107 bool OnEvent(Event event) final {
108 if (event.is_mouse()) {
109 return OnMouseEvent(event);
110 }
111
112 T old_value = this->value();
113 if (event == Event::ArrowLeft || event == Event::Character('h')) {
114 OnLeft();
115 }
116 if (event == Event::ArrowRight || event == Event::Character('l')) {
117 OnRight();
118 }
119 if (event == Event::ArrowUp || event == Event::Character('k')) {
120 OnDown();
121 }
122 if (event == Event::ArrowDown || event == Event::Character('j')) {
123 OnUp();
124 }
125
126 this->value() = std::max(this->min(), std::min(this->max(), this->value()));
127 if (old_value != this->value()) {
128 if (this->on_change) {
129 this->on_change();
130 }
131 return true;
132 }
133
135 }
136
137 bool OnMouseEvent(Event event) {
138 if (captured_mouse_) {
139 if (event.mouse().motion == Mouse::Released) {
140 captured_mouse_ = nullptr;
141 return true;
142 }
143
144 T old_value = this->value();
145 switch (this->direction) {
146 case Direction::Right: {
147 this->value() =
148 this->min() + (event.mouse().x - gauge_box_.x_min) *
149 (this->max() - this->min()) /
150 (gauge_box_.x_max - gauge_box_.x_min);
151
152 break;
153 }
154 case Direction::Left: {
155 this->value() =
156 this->max() - (event.mouse().x - gauge_box_.x_min) *
157 (this->max() - this->min()) /
158 (gauge_box_.x_max - gauge_box_.x_min);
159 break;
160 }
161 case Direction::Down: {
162 this->value() =
163 this->min() + (event.mouse().y - gauge_box_.y_min) *
164 (this->max() - this->min()) /
165 (gauge_box_.y_max - gauge_box_.y_min);
166 break;
167 }
168 case Direction::Up: {
169 this->value() =
170 this->max() - (event.mouse().y - gauge_box_.y_min) *
171 (this->max() - this->min()) /
172 (gauge_box_.y_max - gauge_box_.y_min);
173 break;
174 }
175 }
176
177 this->value() =
178 std::max(this->min(), std::min(this->max(), this->value()));
179
180 if (old_value != this->value() && this->on_change) {
181 this->on_change();
182 }
183 return true;
184 }
185
186 if (event.mouse().button != Mouse::Left) {
187 return false;
188 }
189 if (event.mouse().motion != Mouse::Pressed) {
190 return false;
191 }
192
193 if (!gauge_box_.Contain(event.mouse().x, event.mouse().y)) {
194 return false;
195 }
196
197 captured_mouse_ = CaptureMouse(event);
198
199 if (captured_mouse_) {
200 TakeFocus();
201 return true;
202 }
203
204 return false;
205 }
206
207 bool Focusable() const final { return true; }
208
209 private:
210 Box gauge_box_;
211 CapturedMouse captured_mouse_;
212};
213
214class SliderWithLabel : public ComponentBase {
215 public:
216 SliderWithLabel(ConstStringRef label, Component inner)
217 : label_(std::move(label)) {
218 Add(std::move(inner));
219 SetActiveChild(ChildAt(0));
220 }
221
222 private:
223 bool OnEvent(Event event) final {
225 return true;
226 }
227
228 if (!event.is_mouse()) {
229 return false;
230 }
231
232 mouse_hover_ = box_.Contain(event.mouse().x, event.mouse().y);
233
234 if (!mouse_hover_) {
235 return false;
236 }
237
238 if (!CaptureMouse(event)) {
239 return false;
240 }
241
242 return true;
243 }
244
245 Element Render() override {
246 auto focus_management = Focused() ? focus : Active() ? select : nothing;
247 auto gauge_color = (Focused() || mouse_hover_) ? color(Color::White)
249 return hbox({
250 text(label_()) | dim | vcenter,
251 hbox({
252 text("["),
254 text("]"),
255 }) | xflex,
256 }) |
258 }
259
260 ConstStringRef label_;
261 Box box_;
262 bool mouse_hover_ = false;
263};
264
265} // namespace
266
267/// @brief An horizontal slider.
268/// @param label The name of the slider.
269/// @param value The current value of the slider.
270/// @param min The minimum value.
271/// @param max The maximum value.
272/// @param increment The increment when used by the cursor.
273/// @ingroup component
274///
275/// ### Example
276///
277/// ```cpp
278/// auto screen = ScreenInteractive::TerminalOutput();
279/// int value = 50;
280/// auto slider = Slider("Value:", &value, 0, 100, 1);
281/// screen.Loop(slider);
282/// ```
283///
284/// ### Output
285///
286/// ```bash
287/// Value:[██████████████████████████ ]
288/// ```
290 Ref<int> value,
291 ConstRef<int> min,
292 ConstRef<int> max,
293 ConstRef<int> increment) {
295 option.value = value;
296 option.min = min;
297 option.max = max;
298 option.increment = increment;
300 return Make<SliderWithLabel>(std::move(label), slider);
301}
302
304 Ref<float> value,
305 ConstRef<float> min,
306 ConstRef<float> max,
307 ConstRef<float> increment) {
309 option.value = value;
310 option.min = min;
311 option.max = max;
312 option.increment = increment;
314 return Make<SliderWithLabel>(std::move(label), slider);
315}
317 Ref<long> value,
318 ConstRef<long> min,
319 ConstRef<long> max,
320 ConstRef<long> increment) {
322 option.value = value;
323 option.min = min;
324 option.max = max;
325 option.increment = increment;
327 return Make<SliderWithLabel>(std::move(label), slider);
328}
329
330/// @brief A slider in any direction.
331/// @param options The options
332/// ### Example
333///
334/// ```cpp
335/// auto screen = ScreenInteractive::TerminalOutput();
336/// int value = 50;
337/// auto slider = Slider({
338/// .value = &value,
339/// .min = 0,
340/// .max = 100,
341/// .increment= 20,
342/// });
343/// screen.Loop(slider);
344/// ```
345template <typename T>
349
354
359
362
363} // namespace ftxui
virtual Element Render()
Draw the component. Build a ftxui::Element to be drawn on the ftxi::Screen representing this ftxui::C...
virtual bool OnEvent(Event)
Called in response to an event.
An adapter. Own or reference an immutable object.
Definition ref.hpp:17
An adapter. Own or reference a constant string. For convenience, this class convert multiple immutabl...
Definition ref.hpp:94
An adapter. Own or reference an mutable object.
Definition ref.hpp:46
Element xflex(Element)
Expand/Minimize if possible/needed on the X axis.
Definition flex.cpp:129
Element gaugeDirection(float progress, Direction direction)
Draw a high definition progress bar progressing in specified direction.
Definition gauge.cpp:169
std::function< Element(Element)> Decorator
Definition elements.hpp:24
Element nothing(Element element)
A decoration doing absolutely nothing.
Definition util.cpp:28
std::unique_ptr< CapturedMouseInterface > CapturedMouse
std::shared_ptr< Node > Element
Definition elements.hpp:22
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:26
std::shared_ptr< ComponentBase > Component
Element yflex(Element)
Expand/Minimize if possible/needed on the Y axis.
Definition flex.cpp:135
Element hbox(Elements)
A container displaying elements horizontally one by one.
Definition hbox.cpp:96
Element underlined(Element)
Make the underlined element to be underlined.
Element text(std::wstring text)
Display a piece of unicode text.
Definition text.cpp:159
Element select(Element)
Set the child to be the one selected among its siblings.
Definition frame.cpp:149
Element focus(Element)
Set the child to be the one in focus globally.
Definition frame.cpp:156
Component Slider(SliderOption< T > options)
A slider in any direction.
Definition slider.cpp:346
Decorator reflect(Box &box)
Definition reflect.cpp:43
Element dim(Element)
Use a light font, for elements with less emphasis.
Definition dim.cpp:33
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Definition node.cpp:72
Element vcenter(Element)
Center an element vertically.
Decorator color(Color)
Decorate using a foreground color.
Definition color.cpp:110
static const Event ArrowUp
Definition event.hpp:40
static const Event ArrowDown
Definition event.hpp:41
static const Event ArrowLeft
Definition event.hpp:38
static const Event ArrowRight
Definition event.hpp:39