56std::string PasswordField(
size_t size) {
58 out.reserve(2 *
size);
66class InputBase :
public ComponentBase {
68 InputBase(StringRef content,
69 ConstStringRef placeholder,
70 Ref<InputOption> option)
71 : content_(std::move(content)),
72 placeholder_(std::move(placeholder)),
73 option_(std::move(option)) {}
75 int cursor_position_internal_ = 0;
76 int& cursor_position() {
77 int& opt = option_->cursor_position();
81 return cursor_position_internal_;
86 std::string password_content;
87 if (option_->password()) {
88 password_content = PasswordField(content_->size());
90 const std::string& content =
91 option_->password() ? password_content : *content_;
95 cursor_position() = std::max(0, std::min<int>(
size, cursor_position()));
97 const bool is_focused = Focused();
101 auto element =
text(*placeholder_) |
dim | main_decorator |
reflect(box_);
105 if (hovered_ || is_focused) {
113 auto element =
text(content) | main_decorator |
reflect(box_);
120 const int index_before_cursor =
GlyphPosition(content, cursor_position());
121 const int index_after_cursor =
123 const std::string part_before_cursor =
124 content.substr(0, index_before_cursor);
125 std::string part_at_cursor =
" ";
126 if (cursor_position() <
size) {
127 part_at_cursor = content.substr(index_before_cursor,
128 index_after_cursor - index_before_cursor);
130 const std::string part_after_cursor = content.substr(index_after_cursor);
133 text(part_before_cursor),
134 text(part_at_cursor) | focused |
reflect(cursor_box_),
135 text(part_after_cursor),
140 bool OnEvent(Event event)
override {
142 std::max(0, std::min<int>((
int)content_->size(), cursor_position()));
144 if (event.is_mouse()) {
145 return OnMouseEvent(event);
150 if (cursor_position() == 0) {
153 const size_t start =
GlyphPosition(*content_, cursor_position() - 1);
154 const size_t end =
GlyphPosition(*content_, cursor_position());
155 content_->erase(start, end - start);
157 option_->on_change();
163 if (cursor_position() ==
int(content_->size())) {
166 const size_t start =
GlyphPosition(*content_, cursor_position());
167 const size_t end =
GlyphPosition(*content_, cursor_position() + 1);
168 content_->erase(start, end - start);
169 option_->on_change();
190 cursor_position() < (
int)content_->size()) {
206 cursor_position() = 0;
216 if (event.is_character()) {
217 const size_t start =
GlyphPosition(*content_, cursor_position());
218 content_->insert(start, event.character());
220 option_->on_change();
227 void HandleLeftCtrl() {
231 while (cursor_position() > 0 &&
232 !IsWordCharacter(properties[cursor_position() - 1])) {
237 while (cursor_position() > 0 &&
238 IsWordCharacter(properties[cursor_position() - 1])) {
243 void HandleRightCtrl() {
245 const int max = (int)properties.size();
248 while (cursor_position() < max &&
249 !IsWordCharacter(properties[cursor_position()])) {
254 while (cursor_position() < max &&
255 IsWordCharacter(properties[cursor_position()])) {
260 bool OnMouseEvent(Event event) {
262 box_.Contain(event.mouse().x, event.mouse().y) && CaptureMouse(event);
273 if (content_->empty()) {
278 int original_glyph = cursor_position();
279 original_glyph =
util::clamp(original_glyph, 0,
int(mapping.size()));
280 size_t original_cell = 0;
281 for (
size_t i = 0; i < mapping.size(); i++) {
282 if (mapping[i] == original_glyph) {
283 original_cell = (int)i;
287 if (mapping[original_cell] != original_glyph) {
288 original_cell = mapping.size();
290 const int target_cell =
291 int(original_cell) +
event.mouse().x - cursor_box_.x_min;
292 int target_glyph = target_cell < (int)mapping.size() ? mapping[target_cell]
293 : (int)mapping.size();
295 if (cursor_position() != target_glyph) {
296 cursor_position() = target_glyph;
297 option_->on_change();
302 bool Focusable() const final {
return true; }
304 bool hovered_ =
false;
306 ConstStringRef placeholder_;
310 Ref<InputOption> option_;
An adapter. Own or reference a constant string. For convenience, this class convert multiple immutabl...
An adapter. Own or reference an mutable object.
An adapter. Own or reference a constant string. For convenience, this class convert multiple mutable ...
constexpr const T & clamp(const T &v, const T &lo, const T &hi)
Element flex(Element)
Make a child element to expand proportionnally to the space left in a container.
std::shared_ptr< T > Make(Args &&... args)
std::shared_ptr< Node > Element
Component Input(StringRef content, ConstStringRef placeholder, Ref< InputOption > option={})
An input box for editing text.
Element bold(Element)
Use a bold font, for elements with more emphasis.
Element hbox(Elements)
A container displaying elements horizontally one by one.
Element inverted(Element)
Add a filter that will invert the foreground and the background colors.
Element text(std::wstring text)
Display a piece of unicode text.
int GlyphPosition(const std::string &input, size_t glyph_index, size_t start=0)
std::vector< int > CellToGlyphIndex(const std::string &input)
int GlyphCount(const std::string &input)
Decorator reflect(Box &box)
Element dim(Element)
Use a light font, for elements with less emphasis.
Element frame(Element)
Allow an element to be displayed inside a 'virtual' area. It size can be larger than its container....
std::vector< WordBreakProperty > Utf8ToWordBreakProperty(const std::string &input)
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Decorator size(Direction, Constraint, int value)
Apply a constraint on the size of an element.
std::shared_ptr< ComponentBase > Component
Element focusCursorBarBlinking(Element)
static const Event ArrowLeftCtrl
static const Event Custom
static const Event Backspace
static const Event Return
static const Event ArrowLeft
static const Event Delete
static const Event ArrowRightCtrl
static const Event ArrowRight