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