FTXUI  0.8.1
C++ functional terminal UI.
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 
21 namespace ftxui {
22 
23 // An input box. The user can type text into it.
24 class 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.
190 class 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.
deprecated.hpp
screen_interactive.hpp
ftxui::focus
Element focus(Element)
Definition: frame.cpp:79
ftxui::Event::Backspace
static const Event Backspace
Definition: event.hpp:41
ftxui::Event::Custom
static Event Custom
Definition: event.hpp:56
ftxui
Definition: captured_mouse.hpp:6
ftxui::frame
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
ftxui::to_string
std::string to_string(const std::wstring &s)
Convert a UTF8 std::string into a std::wstring.
Definition: string.cpp:297
ftxui::Component
std::shared_ptr< ComponentBase > Component
Definition: component_base.hpp:17
ftxui::inverted
Element inverted(Element)
Add a filter that will invert the foreground and the background colors.
Definition: inverted.cpp:29
event.hpp
ftxui::Event::ArrowLeft
static const Event ArrowLeft
Definition: event.hpp:35
ftxui::reflect
Decorator reflect(Box &box)
Definition: reflect.cpp:38
box.hpp
ftxui::HEIGHT
@ HEIGHT
Definition: elements.hpp:79
ftxui::to_wstring
std::wstring to_wstring(const std::string &s)
Convert a std::wstring into a UTF8 std::string.
Definition: string.cpp:303
ftxui::hbox
Element hbox(Elements)
A container displaying elements horizontally one by one.
Definition: hbox.cpp:75
ref.hpp
ftxui::flex
Element flex(Element)
Make a child element to expand proportionnally to the space left in a container.
Definition: flex.cpp:119
string.hpp
ftxui::select
Element select(Element)
Definition: frame.cpp:38
elements.hpp
captured_mouse.hpp
component.hpp
ftxui::ComponentBase::Focused
bool Focused() const
Returns if the elements if focused by the user. True when the ComponentBase is focused by the user....
Definition: component.cpp:132
ftxui::underlined
Element underlined(Element)
Make the underlined element to be underlined.
Definition: underlined.cpp:28
ftxui::StringRef
An adapter. Own or reference a constant string. For convenience, this class convert multiple mutable ...
Definition: ref.hpp:43
ftxui::Event::Return
static const Event Return
Definition: event.hpp:43
ftxui::ComponentBase::CaptureMouse
CapturedMouse CaptureMouse(const Event &event)
Take the CapturedMouse if available. There is only one component of them. It represents a component t...
Definition: component.cpp:166
ftxui::Event::Delete
static const Event Delete
Definition: event.hpp:42
component_base.hpp
ftxui::Element
std::shared_ptr< Node > Element
Definition: elements.hpp:15
ftxui::Ref
An adapter. Own or reference an mutable object.
Definition: ref.hpp:27
ftxui::Mouse::Pressed
@ Pressed
Definition: mouse.hpp:20
ftxui::Event::Home
static const Event Home
Definition: event.hpp:49
ftxui::Event::End
static const Event End
Definition: event.hpp:50
ftxui::WideStringRef
An adapter. Own or reference a constant string. For convenience, this class convert multiple mutable ...
Definition: ref.hpp:59
ftxui::size
Decorator size(Direction, Constraint, int value)
Apply a constraint on the size of an element.
Definition: size.cpp:86
mouse.hpp
ftxui::ComponentBase::TakeFocus
void TakeFocus()
Configure all the ancestors to give focus to this component.
Definition: component.cpp:154
ftxui::dim
Element dim(Element)
Use a light font, for elements with less emphasis.
Definition: dim.cpp:28
ftxui::Render
void Render(Screen &screen, const Element &node)
Display an element on a ftxui::Screen.
Definition: node.cpp:34
ftxui::EQUAL
@ EQUAL
Definition: elements.hpp:80
ftxui::ConstStringRef
An adapter. Own or reference a constant string. For convenience, this class convert multiple immutabl...
Definition: ref.hpp:76
component_options.hpp
deprecated.hpp
ftxui::Input
Component Input(StringRef content, ConstStringRef placeholder, Ref< InputOption > option={})
An input box for editing text.
Definition: input.cpp:241
ftxui::Event::ArrowRight
static const Event ArrowRight
Definition: event.hpp:36
ftxui::Mouse::Left
@ Left
Definition: mouse.hpp:10
ftxui::text
Element text(std::wstring text)
Display a piece of unicode text.
Definition: text.cpp:106