FTXUI  0.9.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
menu.cpp
Go to the documentation of this file.
1#include <stddef.h> // for size_t
2#include <algorithm> // for max, min
3#include <functional> // for function
4#include <memory> // for shared_ptr, allocator_traits<>::value_type
5#include <string> // for operator+, string
6#include <utility> // for move
7#include <vector> // for vector, __alloc_traits<>::value_type
8
9#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
10#include "ftxui/component/component.hpp" // for Make, Menu
11#include "ftxui/component/component_base.hpp" // for ComponentBase
12#include "ftxui/component/component_options.hpp" // for MenuOption
13#include "ftxui/component/event.hpp" // for Event, Event::ArrowDown, Event::ArrowUp, Event::Return, Event::Tab, Event::TabReverse
14#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Released
15#include "ftxui/component/screen_interactive.hpp" // for Component
16#include "ftxui/dom/elements.hpp" // for operator|, Element, reflect, text, vbox, Elements, focus, nothing, select
17#include "ftxui/screen/box.hpp" // for Box
18#include "ftxui/util/ref.hpp" // for Ref
19
20namespace ftxui {
21
22/// @brief A list of items. The user can navigate through them.
23/// @ingroup component
24class MenuBase : public ComponentBase {
25 public:
26 MenuBase(ConstStringListRef entries, int* selected, Ref<MenuOption> option)
27 : entries_(entries), selected_(selected), option_(option) {}
28
29 Element Render() override {
30 Elements elements;
31 bool is_menu_focused = Focused();
32 boxes_.resize(entries_.size());
33 for (size_t i = 0; i < entries_.size(); ++i) {
34 bool is_focused = (focused_entry() == int(i)) && is_menu_focused;
35 bool is_selected = (*selected_ == int(i));
36
37 auto style = is_selected ? (is_focused ? option_->style_selected_focused
38 : option_->style_selected)
39 : (is_focused ? option_->style_focused
40 : option_->style_normal);
41 auto focus_management = !is_selected ? nothing
42 : is_menu_focused ? focus
43 : select;
44 auto icon = is_selected ? "> " : " ";
45 elements.push_back(text(icon + entries_[i]) | style | focus_management |
46 reflect(boxes_[i]));
47 }
48 return vbox(std::move(elements)) | reflect(box_);
49 }
50
51 bool OnEvent(Event event) override {
52 if (!CaptureMouse(event))
53 return false;
54
55 if (event.is_mouse())
56 return OnMouseEvent(event);
57
58 if (Focused()) {
59 int old_selected = *selected_;
60 if (event == Event::ArrowUp || event == Event::Character('k'))
61 (*selected_)--;
62 if (event == Event::ArrowDown || event == Event::Character('j'))
63 (*selected_)++;
64 if (event == Event::Tab && entries_.size())
65 *selected_ = (*selected_ + 1) % entries_.size();
66 if (event == Event::TabReverse && entries_.size())
67 *selected_ = (*selected_ + entries_.size() - 1) % entries_.size();
68
69 *selected_ = std::max(0, std::min(int(entries_.size()) - 1, *selected_));
70
71 if (*selected_ != old_selected) {
72 focused_entry() = *selected_;
73 option_->on_change();
74 return true;
75 }
76 }
77
78 if (event == Event::Return) {
79 option_->on_enter();
80 return true;
81 }
82
83 return false;
84 }
85
86 bool OnMouseEvent(Event event) {
87 if (event.mouse().button == Mouse::WheelDown ||
88 event.mouse().button == Mouse::WheelUp) {
89 return OnMouseWheel(event);
90 }
91
92 if (event.mouse().button != Mouse::None &&
93 event.mouse().button != Mouse::Left) {
94 return false;
95 }
96 if (!CaptureMouse(event))
97 return false;
98 for (int i = 0; i < int(boxes_.size()); ++i) {
99 if (!boxes_[i].Contain(event.mouse().x, event.mouse().y))
100 continue;
101
102 TakeFocus();
103 focused_entry() = i;
104 if (event.mouse().button == Mouse::Left &&
105 event.mouse().motion == Mouse::Released) {
106 if (*selected_ != i) {
107 *selected_ = i;
108 option_->on_change();
109 }
110 return true;
111 }
112 }
113 return false;
114 }
115
116 bool OnMouseWheel(Event event) {
117 if (!box_.Contain(event.mouse().x, event.mouse().y))
118 return false;
119 int old_selected = *selected_;
120
121 if (event.mouse().button == Mouse::WheelUp)
122 (*selected_)--;
123 if (event.mouse().button == Mouse::WheelDown)
124 (*selected_)++;
125
126 *selected_ = std::max(0, std::min(int(entries_.size()) - 1, *selected_));
127
128 if (*selected_ != old_selected)
129 option_->on_change();
130 return true;
131 }
132
133 bool Focusable() const final { return entries_.size(); }
134 int& focused_entry() { return option_->focused_entry(); }
135
136 protected:
137 ConstStringListRef entries_;
138 int* selected_ = 0;
139 Ref<MenuOption> option_;
140
141 std::vector<Box> boxes_;
142 Box box_;
143};
144
145/// @brief A list of text. The focused element is selected.
146/// @param entries The list of entries in the menu.
147/// @param selected The index of the currently selected element.
148/// @param option Additional optional parameters.
149/// @ingroup component
150/// @see MenuBase
151///
152/// ### Example
153///
154/// ```cpp
155/// auto screen = ScreenInteractive::TerminalOutput();
156/// std::vector<std::string> entries = {
157/// "entry 1",
158/// "entry 2",
159/// "entry 3",
160/// };
161/// int selected = 0;
162/// auto menu = Menu(&entries, &selected);
163/// screen.Loop(menu);
164/// ```
165///
166/// ### Output
167///
168/// ```bash
169/// > entry 1
170/// entry 2
171/// entry 3
172/// ```
174 int* selected,
175 Ref<MenuOption> option) {
176 return Make<MenuBase>(entries, selected, std::move(option));
177}
178
180 class Impl : public ComponentBase {
181 public:
182 Impl(ConstStringRef label, Ref<MenuEntryOption> option)
183 : label_(std::move(label)), option_(std::move(option)) {}
184
185 private:
186 Element Render() override {
187 bool focused = Focused();
188 auto style =
189 hovered_ ? (focused ? option_->style_selected_focused
190 : option_->style_selected)
191 : (focused ? option_->style_focused : option_->style_normal);
192 auto focus_management = focused ? select : nothing;
193 auto label = focused ? "> " + (*label_) //
194 : " " + (*label_);
195 return text(label) | style | focus_management | reflect(box_);
196 }
197 bool Focusable() const override { return true; }
198 bool OnEvent(Event event) override {
199 if (!event.is_mouse())
200 return false;
201
202 hovered_ = box_.Contain(event.mouse().x, event.mouse().y);
203
204 if (!hovered_)
205 return false;
206
207 if (event.mouse().button == Mouse::Left &&
208 event.mouse().motion == Mouse::Released) {
209 TakeFocus();
210 return true;
211 }
212
213 return false;
214 }
215 ConstStringRef label_;
216 Ref<MenuEntryOption> option_;
217 Box box_;
218 bool hovered_ = false;
219 };
220
221 return Make<Impl>(std::move(label), std::move(option));
222}
223
224} // namespace ftxui
225
226// Copyright 2020 Arthur Sonzogni. All rights reserved.
227// Use of this source code is governed by the MIT license that can be found in
228// the LICENSE file.
It implement rendering itself as ftxui::Element. It implement keyboard navigation by responding to ft...
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 TakeFocus()
Configure all the ancestors to give focus to this component.
An adapter. Reference a list of strings.
Definition ref.hpp:94
size_t size() const
Definition ref.hpp:99
An adapter. Own or reference a constant string. For convenience, this class convert multiple immutabl...
Definition ref.hpp:76
An adapter. Own or reference an mutable object.
Definition ref.hpp:27
Element nothing(Element element)
A decoration doing absolutely nothing.
Definition util.cpp:25
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:25
std::shared_ptr< Node > Element
Definition elements.hpp:15
Element focus(Element)
Definition frame.cpp:79
std::vector< Element > Elements
Definition elements.hpp:16
Element text(std::wstring text)
Display a piece of unicode text.
Definition text.cpp:106
Component Menu(ConstStringListRef entries, int *selected_, Ref< MenuOption >={})
A list of text. The focused element is selected.
Definition menu.cpp:173
Decorator reflect(Box &box)
Definition reflect.cpp:39
Component MenuEntry(ConstStringRef label, Ref< MenuEntryOption >={})
Definition menu.cpp:179
void Render(Screen &screen, const Element &node)
Display an element on a ftxui::Screen.
Definition node.cpp:34
Element select(Element)
Definition frame.cpp:38
std::shared_ptr< ComponentBase > Component
Element vbox(Elements)
A container displaying elements vertically one by one.
Definition vbox.cpp:77
bool Contain(int x, int y)
Definition box.cpp:20
Represent an event. It can be key press event, a terminal resize, or more ...
Definition event.hpp:25
static const Event TabReverse
Definition event.hpp:46
bool is_mouse() const
Definition event.hpp:62
struct Mouse & mouse()
Definition event.hpp:63
static const Event ArrowUp
Definition event.hpp:37
static const Event Tab
Definition event.hpp:45
static const Event ArrowDown
Definition event.hpp:38
static const Event Return
Definition event.hpp:43
Button button
Definition mouse.hpp:24
Motion motion
Definition mouse.hpp:27