FTXUI 6.1.9
C++ functional terminal UI.
载入中...
搜索中...
未找到
src/ftxui/component/radiobox.cpp
浏览该文件的文档.
1// Copyright 2020 Arthur Sonzogni. 保留所有权利。
2// 此源代码的使用受 MIT 许可的约束,该许可可在
3// LICENSE 文件中找到。
4#include <functional> // for function
5#include <utility> // for move
6#include <vector> // for vector
7
8#include "ftxui/component/component.hpp" // for Make, Radiobox
9#include "ftxui/component/component_base.hpp" // for ComponentBase
10#include "ftxui/component/component_options.hpp" // for RadioboxOption, EntryState
11#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
12#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::WheelDown, Mouse::WheelUp, Mouse::Left, Mouse::Released
13#include "ftxui/component/screen_interactive.hpp" // for Component
14#include "ftxui/dom/elements.hpp" // for operator|, reflect, Element, vbox, Elements, focus, nothing, select
15#include "ftxui/screen/box.hpp" // for Box
16#include "ftxui/screen/util.hpp" // for clamp
17#include "ftxui/util/ref.hpp" // for Ref, ConstStringListRef
18
19namespace ftxui {
20
21namespace {
22/// @brief 可选择元素的列表。一次只能选择一个。
23/// @ingroup component
24class RadioboxBase : public ComponentBase, public RadioboxOption {
25 public:
26 explicit RadioboxBase(const RadioboxOption& option)
27 : RadioboxOption(option) {}
28
29 private:
30 Element OnRender() override {
31 Clamp();
32 Elements elements;
33 const bool is_menu_focused = Focused();
34 elements.reserve(size());
35 for (int i = 0; i < size(); ++i) {
36 const bool is_focused = (focused_entry() == i) && is_menu_focused;
37 const bool is_selected = (hovered_ == i);
38 auto state = EntryState{
39 entries[i], selected() == i, is_selected, is_focused, i,
40 };
41 auto element =
42 (transform ? transform : RadioboxOption::Simple().transform)(state);
43 if (is_selected) {
44 element |= focus;
45 }
46 elements.push_back(element | reflect(boxes_[i]));
47 }
48 return vbox(std::move(elements)) | reflect(box_);
49 }
50
51 // NOLINTNEXTLINE(readability-function-cognitive-complexity)
52 bool OnEvent(Event event) override {
53 Clamp();
54 if (!CaptureMouse(event)) {
55 return false;
56 }
57
58 if (event.is_mouse()) {
59 return OnMouseEvent(event);
60 }
61
62 if (Focused()) {
63 const int old_hovered = hovered_;
64 if (event == Event::ArrowUp || event == Event::Character('k')) {
65 (hovered_)--;
66 }
67 if (event == Event::ArrowDown || event == Event::Character('j')) {
68 (hovered_)++;
69 }
70 if (event == Event::PageUp) {
71 (hovered_) -= box_.y_max - box_.y_min;
72 }
73 if (event == Event::PageDown) {
74 (hovered_) += box_.y_max - box_.y_min;
75 }
76 if (event == Event::Home) {
77 (hovered_) = 0;
78 }
79 if (event == Event::End) {
80 (hovered_) = size() - 1;
81 }
82 if (event == Event::Tab && size()) {
83 hovered_ = (hovered_ + 1) % size();
84 }
85 if (event == Event::TabReverse && size()) {
86 hovered_ = (hovered_ + size() - 1) % size();
87 }
88
89 hovered_ = util::clamp(hovered_, 0, size() - 1);
90
91 if (hovered_ != old_hovered) {
92 focused_entry() = hovered_;
93 on_change();
94 return true;
95 }
96 }
97
98 if (event == Event::Character(' ') || event == Event::Return) {
99 selected() = hovered_;
100 on_change();
101 return true;
102 }
103
104 return false;
105 }
106
107 bool OnMouseEvent(Event event) {
108 if (event.mouse().button == Mouse::WheelDown ||
109 event.mouse().button == Mouse::WheelUp) {
110 return OnMouseWheel(event);
111 }
112
113 for (int i = 0; i < size(); ++i) {
114 if (!boxes_[i].Contain(event.mouse().x, event.mouse().y)) {
115 continue;
116 }
117
118 TakeFocus();
119 focused_entry() = i;
120 if (event.mouse().button == Mouse::Left &&
121 event.mouse().motion == Mouse::Pressed) {
122 if (selected() != i) {
123 selected() = i;
124 on_change();
125 }
126
127 return true;
128 }
129 }
130 return false;
131 }
132
133 bool OnMouseWheel(Event event) {
134 if (!box_.Contain(event.mouse().x, event.mouse().y)) {
135 return false;
136 }
137
138 const int old_hovered = hovered_;
139
140 if (event.mouse().button == Mouse::WheelUp) {
141 (hovered_)--;
142 }
143 if (event.mouse().button == Mouse::WheelDown) {
144 (hovered_)++;
145 }
146
147 hovered_ = util::clamp(hovered_, 0, size() - 1);
148
149 if (hovered_ != old_hovered) {
150 on_change();
151 }
152
153 return true;
154 }
155
156 void Clamp() {
157 boxes_.resize(size());
158 selected() = util::clamp(selected(), 0, size() - 1);
159 focused_entry() = util::clamp(focused_entry(), 0, size() - 1);
160 hovered_ = util::clamp(hovered_, 0, size() - 1);
161 }
162
163 bool Focusable() const final { return entries.size(); }
164 int size() const { return int(entries.size()); }
165
166 int hovered_ = selected();
167 std::vector<Box> boxes_;
168 Box box_;
169};
170
171} // namespace
172
173/// @brief 元素列表,其中只能选择一个。
174/// @param option 参数
175/// @ingroup component
176/// @see RadioboxBase
177///
178/// ### 示例
179///
180/// ```cpp
181/// auto screen = ScreenInteractive::TerminalOutput();
182/// std::vector<std::string> entries = {
183/// "entry 1",
184/// "entry 2",
185/// "entry 3",
186/// };
187/// int selected = 0;
188/// auto menu = Radiobox({
189/// .entries = entries,
190/// .selected = &selected,
191/// });
192/// screen.Loop(menu);
193/// ```
194///
195/// ### 输出
196///
197/// ```bash
198/// ◉ entry 1
199/// ○ entry 2
200/// ○ entry 3
201/// ```
202/// NOLINTNEXTLINE
204 return Make<RadioboxBase>(std::move(option));
205}
206
207/// @brief 元素列表,其中只能选择一个。
208/// @param entries 列表中的条目列表。
209/// @param selected 当前选定元素的索引。
210/// @param option 其他可选参数。
211/// @ingroup component
212/// @see RadioboxBase
213///
214/// ### 示例
215///
216/// ```cpp
217/// auto screen = ScreenInteractive::TerminalOutput();
218/// std::vector<std::string> entries = {
219/// "entry 1",
220/// "entry 2",
221/// "entry 3",
222/// };
223/// int selected = 0;
224/// auto menu = Radiobox(&entries, &selected);
225/// screen.Loop(menu);
226/// ```
227///
228/// ### 输出
229///
230/// ```bash
231/// ◉ entry 1
232/// ○ entry 2
233/// ○ entry 3
234/// ```
236 int* selected,
237 RadioboxOption option) {
238 option.entries = std::move(entries);
239 option.selected = selected;
240 return Make<RadioboxBase>(std::move(option));
241}
242
243} // namespace ftxui
一个适配器。引用一个字符串列表。
static const Event TabReverse
static const Event PageUp
static const Event ArrowUp
static const Event Tab
static const Event ArrowDown
static const Event End
static const Event Home
static const Event PageDown
static const Event Return
static RadioboxOption Simple()
标准Radiobox的选项
std::function< Element(const EntryState &)> transform
Component Radiobox(RadioboxOption options)
元素列表,其中只能选择一个。
Radiobox 组件的选项。
Decorator size(WidthOrHeight, Constraint, int value)
对元素大小应用约束。
Element focus(Element)
将 child 设置为其同级元素中获得焦点的元素。
Element vbox(Elements)
垂直一个接一个显示元素的容器。
constexpr const T & clamp(const T &v, const T &lo, const T &hi)
#include "ftxui/component/component_base.hpp" // 用于 ComponentBase
std::shared_ptr< T > Make(Args &&... args)
std::shared_ptr< Node > Element
std::vector< Element > Elements
Decorator reflect(Box &box)
std::shared_ptr< ComponentBase > Component