FTXUI  0.11.1
C++ functional terminal UI.
toggle.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 <utility> // for move
6 #include <vector> // for vector
7 
8 #include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
9 #include "ftxui/component/component.hpp" // for Make, Toggle
10 #include "ftxui/component/component_base.hpp" // for Component, ComponentBase
11 #include "ftxui/component/component_options.hpp" // for ToggleOption
12 #include "ftxui/component/event.hpp" // for Event, Event::ArrowLeft, Event::ArrowRight, Event::Return, Event::Tab, Event::TabReverse
13 #include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed
14 #include "ftxui/dom/elements.hpp" // for operator|, Element, Elements, hbox, reflect, separator, text, focus, nothing, select
15 #include "ftxui/screen/box.hpp" // for Box
16 #include "ftxui/util/ref.hpp" // for ConstStringListRef, Ref
17 
18 namespace ftxui {
19 
20 namespace {
21 
22 /// @brief An horizontal list of elements. The user can navigate through them.
23 /// @ingroup component
24 class ToggleBase : public ComponentBase {
25  public:
26  ToggleBase(ConstStringListRef entries,
27  int* selected,
28  Ref<ToggleOption> option)
29  : entries_(entries), selected_(selected), option_(std::move(option)) {}
30 
31  private:
32  Element Render() override {
33  Elements children;
34  bool is_toggle_focused = Focused();
35  boxes_.resize(entries_.size());
36  for (size_t i = 0; i < entries_.size(); ++i) {
37  // Separator.
38  if (i != 0)
39  children.push_back(separator());
40 
41  bool is_focused = (focused_entry() == int(i)) && is_toggle_focused;
42  bool is_selected = (*selected_ == int(i));
43 
44  auto style = is_selected ? (is_focused ? option_->style_selected_focused
45  : option_->style_selected)
46  : (is_focused ? option_->style_focused
47  : option_->style_normal);
48  auto focus_management = !is_selected ? nothing
49  : is_toggle_focused ? focus
50  : select;
51  children.push_back(text(entries_[i]) | style | focus_management |
52  reflect(boxes_[i]));
53  }
54  return hbox(std::move(children));
55  }
56 
57  bool OnEvent(Event event) override {
58  if (event.is_mouse())
59  return OnMouseEvent(event);
60 
61  int old_selected = *selected_;
62  if (event == Event::ArrowLeft || event == Event::Character('h'))
63  (*selected_)--;
64  if (event == Event::ArrowRight || event == Event::Character('l'))
65  (*selected_)++;
66  if (event == Event::Tab && entries_.size())
67  *selected_ = (*selected_ + 1) % entries_.size();
68  if (event == Event::TabReverse && entries_.size())
69  *selected_ = (*selected_ + entries_.size() - 1) % entries_.size();
70 
71  *selected_ = std::max(0, std::min(int(entries_.size()) - 1, *selected_));
72 
73  if (old_selected != *selected_) {
74  focused_entry() = *selected_;
75  option_->on_change();
76  return true;
77  }
78 
79  if (event == Event::Return) {
80  option_->on_enter();
81  return true;
82  }
83 
84  return false;
85  }
86 
87  bool OnMouseEvent(Event event) {
88  if (!CaptureMouse(event))
89  return false;
90  for (int i = 0; i < int(boxes_.size()); ++i) {
91  if (!boxes_[i].Contain(event.mouse().x, event.mouse().y))
92  continue;
93 
94  TakeFocus();
95  focused_entry() = i;
96  if (event.mouse().button == Mouse::Left &&
97  event.mouse().motion == Mouse::Pressed) {
98  TakeFocus();
99  if (*selected_ != i) {
100  *selected_ = i;
101  option_->on_change();
102  }
103  return true;
104  }
105  }
106  return false;
107  }
108 
109  bool Focusable() const final { return entries_.size(); }
110  int& focused_entry() { return option_->focused_entry(); }
111 
112  ConstStringListRef entries_;
113  int* selected_ = 0;
114 
115  std::vector<Box> boxes_;
116  Ref<ToggleOption> option_;
117 };
118 
119 } // namespace
120 
121 /// @brief An horizontal list of elements. The user can navigate through them.
122 /// @param entries The list of selectable entries to display.
123 /// @param selected Reference the selected entry.
124 /// @param option Additional optional parameters.
125 /// @ingroup component
127  int* selected,
128  Ref<ToggleOption> option) {
129  return Make<ToggleBase>(entries, selected, std::move(option));
130 }
131 
132 } // namespace ftxui
133 
134 // Copyright 2020 Arthur Sonzogni. All rights reserved.
135 // Use of this source code is governed by the MIT license that can be found in
136 // the LICENSE file.
An adapter. Reference a list of strings.
Definition: ref.hpp:94
An adapter. Own or reference an mutable object.
Definition: ref.hpp:27
Element nothing(Element element)
A decoration doing absolutely nothing.
Definition: util.cpp:26
Component Toggle(ConstStringListRef entries, int *selected, Ref< ToggleOption > option={})
An horizontal list of elements. The user can navigate through them.
Definition: toggle.cpp:126
std::shared_ptr< Node > Element
Definition: elements.hpp:16
std::shared_ptr< ComponentBase > Component
Element focus(Element)
Definition: frame.cpp:79
Element hbox(Elements)
A container displaying elements horizontally one by one.
Definition: hbox.cpp:76
Element text(std::wstring text)
Display a piece of unicode text.
Definition: text.cpp:106
std::vector< Element > Elements
Definition: elements.hpp:17
Decorator reflect(Box &box)
Definition: reflect.cpp:39
Element separator(void)
Draw a vertical or horizontal separation in between two other elements.
Definition: separator.cpp:114
void Render(Screen &screen, const Element &node)
Display an element on a ftxui::Screen.
Definition: node.cpp:40
Element select(Element)
Definition: frame.cpp:38
static const Event TabReverse
Definition: event.hpp:46
static Event Character(std::string)
Definition: event.cpp:10
static const Event Tab
Definition: event.hpp:45
static const Event Return
Definition: event.hpp:43
static const Event ArrowLeft
Definition: event.hpp:35
static const Event ArrowRight
Definition: event.hpp:36