FTXUI  0.9.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
input.cpp
Go to the documentation of this file.
1#include <algorithm> // for max, min
2#include <functional> // for function
3#include <memory> // for shared_ptr, allocator
4#include <string> // for wstring, basic_string
5#include <utility> // for move
6
7#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
8#include "ftxui/component/component.hpp" // for Make, Input
9#include "ftxui/component/component_base.hpp" // for ComponentBase
10#include "ftxui/component/component_options.hpp" // for InputOption
11#include "ftxui/component/deprecated.hpp" // for Input
12#include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Backspace, Event::Custom, Event::Delete, Event::End, Event::Home, Event::Return
13#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed
14#include "ftxui/component/screen_interactive.hpp" // for Component
15#include "ftxui/dom/deprecated.hpp" // for text
16#include "ftxui/dom/elements.hpp" // for operator|, Element, reflect, text, dim, flex, focus, inverted, hbox, size, frame, select, underlined, Decorator, EQUAL, HEIGHT
17#include "ftxui/screen/box.hpp" // for Box
18#include "ftxui/screen/string.hpp" // for to_wstring, to_string
19#include "ftxui/util/ref.hpp" // for WideStringRef, Ref, ConstStringRef, StringRef
20
21namespace ftxui {
22
23// An input box. The user can type text into it.
24class WideInputBase : public ComponentBase {
25 public:
26 WideInputBase(WideStringRef content,
27 ConstStringRef placeholder,
28 Ref<InputOption> option)
29 : content_(content), placeholder_(placeholder), option_(option) {}
30
31 int cursor_position_internal_ = 0;
32 int& cursor_position() {
33 int& opt = option_->cursor_position();
34 if (opt != -1)
35 return opt;
36 return cursor_position_internal_;
37 }
38
39 // Component implementation:
40 Element Render() override {
41 std::wstring password_content;
42 if (option_->password())
43 password_content = std::wstring(content_->size(), U'•');
44 std::wstring& content = option_->password() ? password_content : *content_;
45
46 cursor_position() =
47 std::max(0, std::min<int>(content.size(), cursor_position()));
48 auto main_decorator = flex | size(HEIGHT, EQUAL, 1);
49 bool is_focused = Focused();
50
51 // placeholder.
52 if (content.size() == 0) {
53 if (is_focused)
54 return text(*placeholder_) | focus | dim | inverted | main_decorator |
55 reflect(box_);
56 else
57 return text(*placeholder_) | dim | main_decorator | reflect(box_);
58 }
59
60 // Not focused.
61 if (!is_focused)
62 return text(content) | main_decorator | reflect(box_);
63
64 std::wstring part_before_cursor = content.substr(0, cursor_position());
65 std::wstring part_at_cursor = cursor_position() < (int)content.size()
66 ? content.substr(cursor_position(), 1)
67 : L" ";
68 std::wstring part_after_cursor = cursor_position() < (int)content.size() - 1
69 ? content.substr(cursor_position() + 1)
70 : L"";
71 auto focused = is_focused ? focus : select;
72
73 // clang-format off
74 return
75 hbox(
76 text(part_before_cursor),
77 text(part_at_cursor) | underlined | focused | reflect(cursor_box_),
78 text(part_after_cursor)
79 ) | flex | inverted | frame | main_decorator | reflect(box_);
80 // clang-format on
81 }
82
83 bool OnEvent(Event event) override {
84 cursor_position() =
85 std::max(0, std::min<int>(content_->size(), cursor_position()));
86
87 if (event.is_mouse())
88 return OnMouseEvent(event);
89
90 std::wstring c;
91
92 // Backspace.
93 if (event == Event::Backspace) {
94 if (cursor_position() == 0)
95 return false;
96 content_->erase(cursor_position() - 1, 1);
97 cursor_position()--;
98 option_->on_change();
99 return true;
100 }
101
102 // Delete
103 if (event == Event::Delete) {
104 if (cursor_position() == int(content_->size()))
105 return false;
106 content_->erase(cursor_position(), 1);
107 option_->on_change();
108 return true;
109 }
110
111 // Enter.
112 if (event == Event::Return) {
113 option_->on_enter();
114 return true;
115 }
116
117 if (event == Event::Custom) {
118 return false;
119 }
120
121 if (event == Event::ArrowLeft && cursor_position() > 0) {
122 cursor_position()--;
123 return true;
124 }
125
126 if (event == Event::ArrowRight &&
127 cursor_position() < (int)content_->size()) {
128 cursor_position()++;
129 return true;
130 }
131
132 if (event == Event::Home) {
133 cursor_position() = 0;
134 return true;
135 }
136
137 if (event == Event::End) {
138 cursor_position() = (int)content_->size();
139 return true;
140 }
141
142 // Content
143 if (event.is_character()) {
144 content_->insert(cursor_position(), 1, to_wstring(event.character())[0]);
145 cursor_position()++;
146 option_->on_change();
147 return true;
148 }
149 return false;
150 }
151
152 private:
153 bool OnMouseEvent(Event event) {
154 if (!CaptureMouse(event))
155 return false;
156 if (!box_.Contain(event.mouse().x, event.mouse().y))
157 return false;
158
159 TakeFocus();
160
161 if (event.mouse().button == Mouse::Left &&
162 event.mouse().motion == Mouse::Pressed) {
163 int new_cursor_position =
164 cursor_position() + event.mouse().x - cursor_box_.x_min;
165 new_cursor_position =
166 std::max(0, std::min<int>(content_->size(), new_cursor_position));
167 if (cursor_position() != new_cursor_position) {
168 cursor_position() = new_cursor_position;
169 option_->on_change();
170 }
171 }
172 return true;
173 }
174
175 bool Focusable() const final { return true; }
176
177 WideStringRef content_;
178 ConstStringRef placeholder_;
179
180 Box box_;
181 Box cursor_box_;
182 Ref<InputOption> option_;
183};
184
185// An input box. The user can type text into it.
186// For convenience, the std::string version of Input simply wrap a
187// WideInputBase.
188// TODO(arthursonzogni): Provide an implementation handling std::string natively
189// and adds better support for combining characters.
190class InputBase : public WideInputBase {
191 public:
192 InputBase(StringRef content,
193 ConstStringRef placeholder,
194 Ref<InputOption> option)
195 : WideInputBase(&wrapped_content_,
196 std::move(placeholder),
197 std::move(option)),
198 content_(std::move(content)),
199 wrapped_content_(to_wstring(*content_)) {}
200
201 Element Render() override {
202 wrapped_content_ = to_wstring(*content_);
203 return WideInputBase::Render();
204 }
205
206 bool OnEvent(Event event) override {
207 wrapped_content_ = to_wstring(*content_);
208 if (WideInputBase::OnEvent(event)) {
209 *content_ = to_string(wrapped_content_);
210 return true;
211 }
212 return false;
213 }
214
215 StringRef content_;
216 std::wstring wrapped_content_;
217};
218
219/// @brief An input box for editing text.
220/// @param content The editable content.
221/// @param placeholder The text displayed when content is still empty.
222/// @param option Additional optional parameters.
223/// @ingroup component
224/// @see InputBase
225///
226/// ### Example
227///
228/// ```cpp
229/// auto screen = ScreenInteractive::FitComponent();
230/// std::string content= "";
231/// std::string placeholder = "placeholder";
232/// Component input = Input(&content, &placeholder);
233/// screen.Loop(input);
234/// ```
235///
236/// ### Output
237///
238/// ```bash
239/// placeholder
240/// ```
242 ConstStringRef placeholder,
243 Ref<InputOption> option) {
244 return Make<InputBase>(content, placeholder, std::move(option));
245}
246
247/// @brief . An input box for editing text.
248/// @param content The editable content.
249/// @param placeholder The text displayed when content is still empty.
250/// @param option Additional optional parameters.
251/// @ingroup component
252/// @see InputBase
253///
254/// ### Example
255///
256/// ```cpp
257/// auto screen = ScreenInteractive::FitComponent();
258/// std::string content= "";
259/// std::string placeholder = "placeholder";
260/// Component input = Input(&content, &placeholder);
261/// screen.Loop(input);
262/// ```
263///
264/// ### Output
265///
266/// ```bash
267/// placeholder
268/// ```
270 ConstStringRef placeholder,
271 Ref<InputOption> option) {
272 return Make<WideInputBase>(content, placeholder, std::move(option));
273}
274
275} // namespace ftxui
276
277// Copyright 2020 Arthur Sonzogni. All rights reserved.
278// Use of this source code is governed by the MIT license that can be found in
279// the LICENSE file.
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. 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
An adapter. Own or reference a constant string. For convenience, this class convert multiple mutable ...
Definition ref.hpp:43
An adapter. Own or reference a constant string. For convenience, this class convert multiple mutable ...
Definition ref.hpp:59
@ HEIGHT
Definition elements.hpp:90
Element flex(Element)
Make a child element to expand proportionnally to the space left in a container.
Definition flex.cpp:119
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:25
std::shared_ptr< Node > Element
Definition elements.hpp:15
Component Input(StringRef content, ConstStringRef placeholder, Ref< InputOption > option={})
An input box for editing text.
Definition input.cpp:241
Element focus(Element)
Definition frame.cpp:79
Element hbox(Elements)
A container displaying elements horizontally one by one.
Definition hbox.cpp:76
std::wstring to_wstring(const std::string &s)
Convert a std::wstring into a UTF8 std::string.
Definition string.cpp:303
Element underlined(Element)
Make the underlined element to be underlined.
Element inverted(Element)
Add a filter that will invert the foreground and the background colors.
Definition inverted.cpp:29
std::string to_string(const std::wstring &s)
Convert a UTF8 std::string into a std::wstring.
Definition string.cpp:297
Element text(std::wstring text)
Display a piece of unicode text.
Definition text.cpp:106
Decorator reflect(Box &box)
Definition reflect.cpp:39
Element dim(Element)
Use a light font, for elements with less emphasis.
Definition dim.cpp:28
Element frame(Element)
Allow an element to be displayed inside a 'virtual' area. It size can be larger than its container....
Definition frame.cpp:138
Decorator size(Direction, Constraint, int value)
Apply a constraint on the size of an element.
Definition size.cpp:86
@ EQUAL
Definition elements.hpp:91
Element select(Element)
Definition frame.cpp:38
std::shared_ptr< ComponentBase > Component
bool Contain(int x, int y)
Definition box.cpp:20
int x_min
Definition box.hpp:7
static Event Custom
Definition event.hpp:56
static const Event Backspace
Definition event.hpp:41
static const Event End
Definition event.hpp:50
static const Event Home
Definition event.hpp:49
static const Event Return
Definition event.hpp:43
static const Event ArrowLeft
Definition event.hpp:35
static const Event Delete
Definition event.hpp:42
static const Event ArrowRight
Definition event.hpp:36