FTXUI 7.0.3
C++ functional terminal UI.
Loading...
Searching...
No Matches
src/ftxui/component/radiobox.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 <functional> // for function
5#include <string> // for string
6#include <utility> // for move
7#include <vector> // for vector
8
9#include "ftxui/component/app.hpp" // for Component
10#include "ftxui/component/component.hpp" // for Make, Radiobox
11#include "ftxui/component/component_base.hpp" // for ComponentBase
12#include "ftxui/component/component_options.hpp" // for RadioboxOption, EntryState
13#include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowUp, Event::End, Event::Home, Event::PageDown, Event::PageUp, Event::Return, Event::Tab, Event::TabReverse
14#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::WheelDown, Mouse::WheelUp, Mouse::Left, Mouse::Released
15#include "ftxui/dom/elements.hpp" // for operator|, reflect, Element, vbox, Elements, focus, nothing, select
16#include "ftxui/screen/box.hpp" // for Box
17#include "ftxui/screen/util.hpp" // for clamp
18#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef
19
20namespace ftxui {
21
22namespace {
23/// @brief Une liste d'éléments sélectionnables. Un seul et unique peut être sélectionné à
24/// la fois.
25/// @ingroup component
26class RadioboxBase : public ComponentBase, public RadioboxOption {
27 public:
28 explicit RadioboxBase(const RadioboxOption& option)
29 : RadioboxOption(option) {}
30
31 private:
32 Element OnRender() override {
33 Clamp();
34 Elements elements;
35 const bool is_menu_focused = Focused();
36 elements.reserve(size());
37 for (int i = 0; i < size(); ++i) {
38 const bool is_focused = (focused_entry() == i) && is_menu_focused;
39 const bool is_selected = (hovered_ == i);
40 auto state = EntryState{
41 std::string(entries[i]), selected() == i, is_selected, is_focused, i,
42 };
43 auto element =
44 (transform ? transform : RadioboxOption::Simple().transform)(state);
45 if (is_selected) {
46 element |= focus;
47 }
48 elements.push_back(element | reflect(boxes_[i]));
49 }
50 return vbox(std::move(elements)) | reflect(box_);
51 }
52
53 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
54 bool OnEvent(Event event) override {
55 Clamp();
56 if (!CaptureMouse(event)) {
57 return false;
58 }
59
60 if (event.is_mouse()) {
61 return OnMouseEvent(event);
62 }
63
64 if (Focused()) {
65 const int old_hovered = hovered_;
66 if (event == Event::ArrowUp || event == Event::Character('k')) {
67 (hovered_)--;
68 }
69 if (event == Event::ArrowDown || event == Event::Character('j')) {
70 (hovered_)++;
71 }
72 if (event == Event::PageUp) {
73 (hovered_) -= box_.y_max - box_.y_min;
74 }
75 if (event == Event::PageDown) {
76 (hovered_) += box_.y_max - box_.y_min;
77 }
78 if (event == Event::Home) {
79 (hovered_) = 0;
80 }
81 if (event == Event::End) {
82 (hovered_) = size() - 1;
83 }
84 if (event == Event::Tab && size()) {
85 hovered_ = (hovered_ + 1) % size();
86 }
87 if (event == Event::TabReverse && size()) {
88 hovered_ = (hovered_ + size() - 1) % size();
89 }
90
91 hovered_ = util::clamp(hovered_, 0, size() - 1);
92
93 if (hovered_ != old_hovered) {
94 focused_entry() = hovered_;
95 App::PostEventOrExecute(on_change);
96 return true;
97 }
98 }
99
100 if (event == Event::Character(' ') || event == Event::Return) {
101 selected() = hovered_;
102 App::PostEventOrExecute(on_change);
103 return true;
104 }
105
106 return false;
107 }
108
109 bool OnMouseEvent(Event event) {
110 if (event.mouse().button == Mouse::WheelDown ||
111 event.mouse().button == Mouse::WheelUp) {
112 return OnMouseWheel(event);
113 }
114
115 for (int i = 0; i < size(); ++i) {
116 if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) {
117 continue;
118 }
119
120 TakeFocus();
121 focused_entry() = i;
122 if (event.mouse().button == Mouse::Left &&
123 event.mouse().motion == Mouse::Pressed) {
124 if (selected() != i) {
125 selected() = i;
126 App::PostEventOrExecute(on_change);
127 }
128
129 return true;
130 }
131 }
132 return false;
133 }
134
135 bool OnMouseWheel(Event event) {
136 if (!box_.Contain(event.mouse().x, event.mouse().y)) {
137 return false;
138 }
139
140 const int old_hovered = hovered_;
141
142 if (event.mouse().button == Mouse::WheelUp) {
143 (hovered_)--;
144 }
145 if (event.mouse().button == Mouse::WheelDown) {
146 (hovered_)++;
147 }
148
149 hovered_ = util::clamp(hovered_, 0, size() - 1);
150
151 if (hovered_ != old_hovered) {
152 App::PostEventOrExecute(on_change);
153 }
154
155 return true;
156 }
157
158 void Clamp() {
159 boxes_.resize(size());
160 selected() = util::clamp(selected(), 0, size() - 1);
161 focused_entry() = util::clamp(focused_entry(), 0, size() - 1);
162 hovered_ = util::clamp(hovered_, 0, size() - 1);
163 }
164
165 bool Focusable() const final { return entries.size(); }
166 int size() const { return int(entries.size()); }
167
168 int hovered_ = selected();
169 std::vector<Box> boxes_;
170 Box box_;
171};
172
173} // namespace
174
175/// @brief Une liste d'éléments, où un seul peut être sélectionné.
176/// @param option Les paramètres
177/// @ingroup component
178/// @see RadioboxBase
179///
180/// ### Exemple
181///
182/// ```cpp
183/// auto screen = App::TerminalOutput();
184/// std::vector<std::string> entries = {
185/// "entry 1",
186/// "entry 2",
187/// "entry 3",
188/// };
189/// int selected = 0;
190/// auto menu = Radiobox({
191/// .entries = entries,
192/// .selected = &selected,
193/// });
194/// screen.Loop(menu);
195/// ```
196///
197/// ### Sortie
198///
199/// ```bash
200/// ◉ entry 1
201/// ○ entry 2
202/// ○ entry 3
203/// ```
204/// NOLINTNEXTLINE
205Component Radiobox(RadioboxOption option) {
206 return Make<RadioboxBase>(std::move(option));
207}
208
209/// @brief Une liste d'éléments, où un seul peut être sélectionné.
210/// @param entries La liste des entrées dans la liste.
211/// @param selected L'index de l'élément actuellement sélectionné.
212/// @param option Paramètres optionnels supplémentaires.
213/// @ingroup component
214/// @see RadioboxBase
215///
216/// ### Exemple
217///
218/// ```cpp
219/// auto screen = App::TerminalOutput();
220/// std::vector<std::string> entries = {
221/// "entry 1",
222/// "entry 2",
223/// "entry 3",
224/// };
225/// int selected = 0;
226/// auto menu = Radiobox(&entries, &selected);
227/// screen.Loop(menu);
228/// ```
229///
230/// ### Sortie
231///
232/// ```bash
233/// ◉ entry 1
234/// ○ entry 2
235/// ○ entry 3
236/// ```
237Component Radiobox(ConstStringListRef entries,
238 int* selected,
239 RadioboxOption option) {
240 option.entries = std::move(entries);
241 option.selected = selected;
242 return Make<RadioboxBase>(std::move(option));
243}
244
245} // namespace ftxui
Component Radiobox(ConstStringListRef entries, int *selected_, RadioboxOption options={})
Une liste d'éléments, où un seul peut être sélectionné.
Decorator size(WidthOrHeight direction, Constraint constraint, int value)
Applique une contrainte sur la taille d'un élément.
Element focus(Element child)
Définit l'élément child comme étant celui qui est focalisé parmi ses frères.
Definition frame.cpp:101
Element vbox(Elements children)
Un conteneur affichant les éléments verticalement un par un.
Definition vbox.cpp:96
constexpr const T & clamp(const T &v, const T &lo, const T &hi)
Definition util.hpp:13
L'espace de noms FTXUI ftxui::
Definition animation.hpp:11
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:28
std::shared_ptr< Node > Element
Definition elements.hpp:25
std::vector< Element > Elements
Definition elements.hpp:26
const Element & element
Definition node.hpp:94
Decorator reflect(Box &box)
Definition reflect.cpp:43
std::shared_ptr< ComponentBase > Component
Definition app.hpp:23