FTXUI 7.0.3
C++ functional terminal UI.
Loading...
Searching...
No Matches
src/ftxui/component/dropdown.cpp
Go to the documentation of this file.
1// Copyright 2021 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.
5#include <functional> // for function
6#include <string> // for string
7
8#include <utility>
9#include "ftxui/component/component.hpp" // for Maybe, Checkbox, Make, Radiobox, Vertical, Dropdown
10#include "ftxui/component/component_base.hpp" // for Component, ComponentBase
11#include "ftxui/component/component_options.hpp" // for CheckboxOption, EntryState
12#include "ftxui/dom/elements.hpp" // for operator|, Element, border, filler, operator|=, separator, size, text, vbox, frame, vscroll_indicator, hbox, HEIGHT, LESS_THAN, bold, inverted
13#include "ftxui/screen/util.hpp" // for clamp
14#include "ftxui/util/ref.hpp" // for ConstStringListRef
15
16namespace ftxui {
17
18/// @brief ドロップダウンメニュー。
19/// @ingroup component
20/// @param entries 表示するエントリのリスト。
21/// @param selected 選択されたエントリのインデックス。
22Component Dropdown(ConstStringListRef entries, int* selected) {
23 DropdownOption option;
24 option.radiobox.entries = std::move(entries);
25 option.radiobox.selected = selected;
26 return Dropdown(option);
27}
28
29/// @brief ドロップダウンメニュー。
30/// @ingroup component
31/// @param option ドロップダウンのオプション。
32// NOLINTNEXTLINE
33Component Dropdown(DropdownOption option) {
34 class Impl : public ComponentBase, public DropdownOption {
35 public:
36 explicit Impl(DropdownOption option) : DropdownOption(std::move(option)) {
37 FillDefault();
38 checkbox_ = Checkbox(checkbox);
39 radiobox_ = Radiobox(radiobox);
40
41 container_ = Container::Vertical({
42 checkbox_,
43 Maybe(radiobox_, checkbox.checked),
44 });
45 Add(container_);
46 }
47
48 Element OnRender() override {
49 selected_ =
50 util::clamp(radiobox.selected(), 0, int(radiobox.entries.size()) - 1);
51 selected_ = util::clamp(selected_(), 0, int(radiobox.entries.size()) - 1);
52
53 if (selected_() >= 0 && selected_() < int(radiobox.entries.size())) {
54 title_ = radiobox.entries[selected_()];
55 }
56
57 // 別のコンポーネントがフォーカスを取得したとき、ドロップダウンを
58 // 閉じます。これは、このドロップダウンが何のイベントも受け取らずに
59 // 発生する可能性があります。例えば、ユーザーが兄弟の
60 // ドロップダウンをクリックした場合です。他のコンポーネントから
61 // フォーカスを奪わずに、内部フォーカスをチェックボックスに戻します。
62 if (open_() && !Focused()) {
63 container_->SetActiveChild(checkbox_);
64 *open_ = false;
65 }
66
67 return transform(*open_, checkbox_->Render(), radiobox_->Render());
68 }
69
70 // 選択する際に、チェックボックスとラジオボックスの間でフォーカスを
71// 切り替えます。
72 bool OnEvent(ftxui::Event event) override {
73 const bool open_old = open_();
74 const int selected_old = selected_();
75 bool handled = ComponentBase::OnEvent(event);
76
77 // ドロップダウンが開かれたとき、ラジオボックスにフォーカスを転送します。
78 if (!open_old && open_()) {
79 radiobox_->TakeFocus();
80 }
81
82 // ユーザーが項目を選択したとき、それが前と同じ項目であっても
83 // ドロップダウンを自動的に閉じます。
84 if (open_old && open_()) {
85 const bool should_close =
86 (selected_() != selected_old) || //
87 (event == Event::Return) || //
88 (event == Event::Character(' ')) || //
89 (event == Event::Escape) || //
90 (event.is_mouse() && event.mouse().button == Mouse::Left &&
91 event.mouse().motion == Mouse::Pressed);
92
93 if (should_close) {
94 checkbox_->TakeFocus();
95 *open_ = false;
96 handled = true;
97 }
98 }
99
100 return handled;
101 }
102
103 void FillDefault() {
104 open_ = checkbox.checked;
105 selected_ = radiobox.selected;
106 checkbox.checked = &*open_;
107 radiobox.selected = &*selected_;
108 checkbox.label = &title_;
109
110 if (!checkbox.transform) {
111 checkbox.transform = [](const EntryState& s) {
112 auto prefix = text(s.state ? "↓ " : "→ "); // NOLINT
113 auto t = text(s.label);
114 if (s.active) {
115 t |= bold;
116 }
117 if (s.focused) {
118 t |= inverted;
119 }
120 return hbox({prefix, t});
121 };
122 }
123
124 if (!transform) {
125 transform = [](bool is_open, Element checkbox_element,
126 Element radiobox_element) {
127 if (is_open) {
128 const int max_height = 12;
129 return vbox({
130 std::move(checkbox_element),
131 separator(),
132 std::move(radiobox_element) | vscroll_indicator | frame |
133 size(HEIGHT, LESS_THAN, max_height),
134 }) |
135 border;
136 }
137 return vbox({std::move(checkbox_element), filler()}) | border;
138 };
139 }
140 }
141
142 private:
143 Ref<bool> open_;
144 Ref<int> selected_;
145 Component container_;
146 Component checkbox_;
147 Component radiobox_;
148 std::string title_;
149 };
150
151 return Make<Impl>(option);
152}
153
154} // namespace ftxui
アダプター。可変オブジェクトを所有または参照します。
Definition ref.hpp:56
Component Dropdown(ConstStringListRef entries, int *selected)
ドロップダウンメニュー。
FTXUI ftxui::名前空間
Definition animation.hpp:11
@ LESS_THAN
Definition elements.hpp:191
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:28
std::shared_ptr< Node > Element
Definition elements.hpp:25
std::shared_ptr< ComponentBase > Component
Definition app.hpp:23