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