FTXUI  5.0.0
C++ functional terminal UI.
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.
4 #include <cstddef> // for size_t
6 #include <functional> // for function
7 #include <string> // for string
8 
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 
16 namespace ftxui {
17 
18 /// @brief A dropdown menu.
19 /// @ingroup component
20 /// @param entries The list of entries to display.
21 /// @param selected The index of the selected entry.
22 Component Dropdown(ConstStringListRef entries, int* selected) {
23  DropdownOption option;
24  option.radiobox.entries = entries;
25  option.radiobox.selected = selected;
26  return Dropdown(option);
27 }
28 
29 /// @brief A dropdown menu.
30 /// @ingroup component
31 /// @param option The options for the dropdown.
33  class Impl : public ComponentBase, public DropdownOption {
34  public:
35  explicit Impl(DropdownOption option) : DropdownOption(std::move(option)) {
36  FillDefault();
37  checkbox_ = Checkbox(checkbox);
38  radiobox_ = Radiobox(radiobox);
39 
41  checkbox_,
42  Maybe(radiobox_, checkbox.checked),
43  }));
44  }
45 
46  Element Render() override {
47  radiobox.selected =
48  util::clamp(radiobox.selected(), 0, int(radiobox.entries.size()) - 1);
49  title_ = radiobox.entries[selected_()];
50 
51  return transform(*open_, checkbox_->Render(), radiobox_->Render());
52  }
53 
54  // Switch focus in between the checkbox and the radiobox when selecting it.
55  bool OnEvent(ftxui::Event event) override {
56  const bool open_old = open_();
57  const int selected_old = selected_();
58  bool handled = ComponentBase::OnEvent(event);
59 
60  // Transfer focus to the radiobox when the dropdown is opened.
61  if (!open_old && open_()) {
62  radiobox_->TakeFocus();
63  }
64 
65  // Auto-close the dropdown when the user selects an item, even if the item
66  // it the same as the previous one.
67  if (open_old && open_()) {
68  const bool should_close = (selected_() != selected_old) || //
69  (event == Event::Return) || //
70  (event == Event::Character(' ')) || //
71  (event == Event::Escape); //
72 
73  if (should_close) {
74  checkbox_->TakeFocus();
75  open_ = false;
76  handled = true;
77  }
78  }
79 
80  return handled;
81  }
82 
83  void FillDefault() {
84  open_ = checkbox.checked;
85  selected_ = radiobox.selected;
86  checkbox.checked = &*open_;
87  radiobox.selected = &*selected_;
88  checkbox.label = &title_;
89 
90  if (!checkbox.transform) {
91  checkbox.transform = [](const EntryState& s) {
92  auto prefix = text(s.state ? "↓ " : "→ "); // NOLINT
93  auto t = text(s.label);
94  if (s.active) {
95  t |= bold;
96  }
97  if (s.focused) {
98  t |= inverted;
99  }
100  return hbox({prefix, t});
101  };
102  }
103 
104  if (!transform) {
105  transform = [](bool is_open, Element checkbox_element,
106  Element radiobox_element) {
107  if (is_open) {
108  const int max_height = 12;
109  return vbox({
110  std::move(checkbox_element),
111  separator(),
112  std::move(radiobox_element) | vscroll_indicator | frame |
113  size(HEIGHT, LESS_THAN, max_height),
114  }) |
115  border;
116  }
117  return vbox({std::move(checkbox_element), filler()}) | border;
118  };
119  }
120  }
121 
122  private:
123  Ref<bool> open_;
124  Ref<int> selected_;
125  Component checkbox_;
126  Component radiobox_;
127  std::string title_;
128  };
129 
130  return Make<Impl>(option);
131 }
132 
133 } // namespace ftxui
It implement rendering itself as ftxui::Element. It implement keyboard navigation by responding to ft...
virtual bool OnEvent(Event)
Called in response to an event.
Definition: component.cpp:106
An adapter. Reference a list of strings.
Definition: ref.hpp:116
Component Vertical(Components children)
A list of components, drawn one by one vertically and navigated vertically using up/down arrow key or...
Definition: container.cpp:316
constexpr const T & clamp(const T &v, const T &lo, const T &hi)
Definition: util.hpp:11
@ HEIGHT
Definition: elements.hpp:147
Element vscroll_indicator(Element)
Display a vertical scrollbar to the right. colors.
Decorator size(WidthOrHeight, Constraint, int value)
Apply a constraint on the size of an element.
Definition: size.cpp:89
Component Maybe(Component, const bool *show)
Decorate a component |child|. It is shown only when |show| is true.
Definition: maybe.cpp:74
std::shared_ptr< Node > Element
Definition: elements.hpp:22
std::shared_ptr< ComponentBase > Component
Element bold(Element)
Use a bold font, for elements with more emphasis.
Definition: bold.cpp:33
Component Radiobox(RadioboxOption options)
A list of element, where only one can be selected.
Definition: radiobox.cpp:207
Element hbox(Elements)
A container displaying elements horizontally one by one.
Definition: hbox.cpp:83
Element inverted(Element)
Add a filter that will invert the foreground and the background colors.
Definition: inverted.cpp:34
Element text(std::wstring text)
Display a piece of unicode text.
Definition: text.cpp:119
Component Dropdown(ConstStringListRef entries, int *selected)
A dropdown menu.
Definition: dropdown.cpp:22
Element separator()
Draw a vertical or horizontal separation in between two other elements.
Definition: separator.cpp:132
Element filler()
An element that will take expand proportionally to the space left in a container.
Definition: flex.cpp:98
Element frame(Element)
Allow an element to be displayed inside a 'virtual' area. It size can be larger than its container....
Definition: frame.cpp:166
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Definition: node.cpp:47
@ LESS_THAN
Definition: elements.hpp:148
Component Checkbox(CheckboxOption options)
Draw checkable element.
Definition: checkbox.cpp:111
Element border(Element)
Draw a border around the element.
Definition: border.cpp:227
Element vbox(Elements)
A container displaying elements vertically one by one.
Definition: vbox.cpp:83
Option for the Dropdown component.A dropdown menu is a checkbox opening/closing a radiobox.
arguments for |ButtonOption::transform|, |CheckboxOption::transform|, |Radiobox::transform|,...
Represent an event. It can be key press event, a terminal resize, or more ...
Definition: event.hpp:27
static const Event Escape
Definition: event.hpp:52
static Event Character(std::string)
An event corresponding to a given typed character.
Definition: event.cpp:28
static const Event Return
Definition: event.hpp:51
ConstStringListRef entries