FTXUI 6.1.9
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 <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
一個適配器。引用一個字串列表。
Definition ref.hpp:114
static const Event TabReverse
Definition event.hpp:54
static const Event PageUp
Definition event.hpp:60
ConstStringListRef entries
static const Event ArrowUp
Definition event.hpp:40
static const Event Tab
Definition event.hpp:53
static const Event ArrowDown
Definition event.hpp:41
static const Event End
Definition event.hpp:59
static const Event Home
Definition event.hpp:58
static const Event PageDown
Definition event.hpp:61
static const Event Return
Definition event.hpp:51
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 設置為其同級元素中被聚焦的元素。
Definition frame.cpp:101
Element vbox(Elements)
一個垂直一個接一個顯示元素的容器。
Definition vbox.cpp:95
constexpr const T & clamp(const T &v, const T &lo, const T &hi)
Definition util.hpp:11
FTXUI 的 ftxui:: 命名空間
Definition animation.hpp:10
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:26
std::shared_ptr< Node > Element
Definition elements.hpp:22
std::vector< Element > Elements
Definition elements.hpp:23
Decorator reflect(Box &box)
Definition reflect.cpp:42
std::shared_ptr< ComponentBase > Component