FTXUI 6.1.9
C++ functional terminal UI.
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages Modules
src/ftxui/component/resizable_split.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 <ftxui/component/component_options.hpp> // for ResizableSplitOption
5#include <ftxui/dom/direction.hpp> // for Direction, Direction::Down, Direction::Left, Direction::Right, Direction::Up
6#include <ftxui/util/ref.hpp> // for Ref
7#include <algorithm> // for max
8#include <functional> // for function
9#include <utility> // for move
10
11#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
12#include "ftxui/component/component.hpp" // for Horizontal, Make, ResizableSplit, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop
13#include "ftxui/component/component_base.hpp" // for Component, ComponentBase
14#include "ftxui/component/event.hpp" // for Event
15#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released
16#include "ftxui/dom/elements.hpp" // for operator|, reflect, Element, size, EQUAL, xflex, yflex, hbox, vbox, HEIGHT, WIDTH, text
17#include "ftxui/screen/box.hpp" // for Box
18
19namespace ftxui {
20namespace {
21
22class ResizableSplitBase : public ComponentBase {
23 public:
24 explicit ResizableSplitBase(ResizableSplitOption options)
25 : options_(std::move(options)) {
26 switch (options_->direction()) {
27 case Direction::Left:
28 Add(Container::Horizontal({
29 options_->main,
30 options_->back,
31 }));
32 break;
35 options_->back,
36 options_->main,
37 }));
38 break;
39 case Direction::Up:
41 options_->main,
42 options_->back,
43 }));
44 break;
45 case Direction::Down:
47 options_->back,
48 options_->main,
49 }));
50 break;
51 }
52 }
53
54 bool OnEvent(Event event) final {
55 if (event.is_mouse()) {
56 return OnMouseEvent(std::move(event));
57 }
58 return ComponentBase::OnEvent(std::move(event));
59 }
60
61 bool OnMouseEvent(Event event) {
62 if (captured_mouse_ && event.mouse().motion == Mouse::Released) {
63 captured_mouse_.reset();
64 return true;
65 }
66
67 if (event.mouse().button == Mouse::Left &&
68 event.mouse().motion == Mouse::Pressed &&
69 separator_box_.Contain(event.mouse().x, event.mouse().y) &&
70 !captured_mouse_) {
71 captured_mouse_ = CaptureMouse(event);
72 return true;
73 }
74
75 if (!captured_mouse_) {
76 return ComponentBase::OnEvent(event);
77 }
78
79 switch (options_->direction()) {
80 case Direction::Left:
81 options_->main_size() = std::max(0, event.mouse().x - box_.x_min);
82 return true;
84 options_->main_size() = std::max(0, box_.x_max - event.mouse().x);
85 return true;
86 case Direction::Up:
87 options_->main_size() = std::max(0, event.mouse().y - box_.y_min);
88 return true;
89 case Direction::Down:
90 options_->main_size() = std::max(0, box_.y_max - event.mouse().y);
91 return true;
92 }
93
94 // NOTREACHED()
95 return false;
96 }
97
98 Element OnRender() final {
99 switch (options_->direction()) {
100 case Direction::Left:
101 return RenderLeft();
102 case Direction::Right:
103 return RenderRight();
104 case Direction::Up:
105 return RenderTop();
106 case Direction::Down:
107 return RenderBottom();
108 }
109 // NOTREACHED()
110 return text("unreacheable");
111 }
112
113 Element RenderLeft() {
114 return hbox({
115 options_->main->Render() |
116 size(WIDTH, EQUAL, options_->main_size()),
117 options_->separator_func() | reflect(separator_box_),
118 options_->back->Render() | xflex,
119 }) |
120 reflect(box_);
121 }
122
123 Element RenderRight() {
124 return hbox({
125 options_->back->Render() | xflex,
126 options_->separator_func() | reflect(separator_box_),
127 options_->main->Render() |
128 size(WIDTH, EQUAL, options_->main_size()),
129 }) |
130 reflect(box_);
131 }
132
133 Element RenderTop() {
134 return vbox({
135 options_->main->Render() |
136 size(HEIGHT, EQUAL, options_->main_size()),
137 options_->separator_func() | reflect(separator_box_),
138 options_->back->Render() | yflex,
139 }) |
140 reflect(box_);
141 }
142
143 Element RenderBottom() {
144 return vbox({
145 options_->back->Render() | yflex,
146 options_->separator_func() | reflect(separator_box_),
147 options_->main->Render() |
148 size(HEIGHT, EQUAL, options_->main_size()),
149 }) |
150 reflect(box_);
151 }
152
153 private:
154 Ref<ResizableSplitOption> options_;
155 CapturedMouse captured_mouse_;
156 Box separator_box_;
157 Box box_;
158};
159
160} // namespace
161
162/// @brief A split in between two components.
163/// @param options all the parameters.
164///
165/// ### Example
166///
167/// ```cpp
168/// auto left = Renderer([] { return text("Left") | center;});
169/// auto right = Renderer([] { return text("right") | center;});
170/// int left_size = 10;
171/// auto component = ResizableSplit({
172/// .main = left,
173/// .back = right,
174/// .direction = Direction::Left,
175/// .main_size = &left_size,
176/// .separator_func = [] { return separatorDouble(); },
177/// });
178/// ```
179///
180/// ### Output
181///
182/// ```bash
183/// ║
184/// left ║ right
185/// ║
186/// ```
187Component ResizableSplit(ResizableSplitOption options) {
188 return Make<ResizableSplitBase>(std::move(options));
189}
190
191/// @brief An horizontal split in between two components, configurable using the
192/// mouse.
193/// @param main The main component of size |main_size|, on the left.
194/// @param back The back component taking the remaining size, on the right.
195/// @param main_size The size of the |main| component.
196/// @ingroup component
197///
198/// ### Example
199///
200/// ```cpp
201/// auto screen = ScreenInteractive::Fullscreen();
202/// int left_size = 10;
203/// auto left = Renderer([] { return text("Left") | center;});
204/// auto right = Renderer([] { return text("right") | center;});
205/// auto split = ResizableSplitLeft(left, right, &left_size);
206/// screen.Loop(split);
207/// ```
208///
209/// ### Output
210///
211/// ```bash
212/// │
213/// left │ right
214/// │
215/// ```
216Component ResizableSplitLeft(Component main, Component back, int* main_size) {
217 return ResizableSplit({
218 std::move(main),
219 std::move(back),
220 Direction::Left,
221 main_size,
222 });
223}
224
225/// @brief An horizontal split in between two components, configurable using the
226/// mouse.
227/// @param main The main component of size |main_size|, on the right.
228/// @param back The back component taking the remaining size, on the left.
229/// @param main_size The size of the |main| component.
230/// @ingroup component
231///
232/// ### Example
233///
234/// ```cpp
235/// auto screen = ScreenInteractive::Fullscreen();
236/// int right_size = 10;
237/// auto left = Renderer([] { return text("Left") | center;});
238/// auto right = Renderer([] { return text("right") | center;});
239/// auto split = ResizableSplitRight(right, left, &right_size)
240/// screen.Loop(split);
241/// ```
242///
243/// ### Output
244///
245/// ```bash
246/// │
247/// left │ right
248/// │
249/// ```
250Component ResizableSplitRight(Component main, Component back, int* main_size) {
251 return ResizableSplit({
252 std::move(main),
253 std::move(back),
254 Direction::Right,
255 main_size,
256 });
257}
258
259/// @brief An vertical split in between two components, configurable using the
260/// mouse.
261/// @param main The main component of size |main_size|, on the top.
262/// @param back The back component taking the remaining size, on the bottom.
263/// @param main_size The size of the |main| component.
264/// @ingroup component
265///
266/// ### Example
267///
268/// ```cpp
269/// auto screen = ScreenInteractive::Fullscreen();
270/// int top_size = 1;
271/// auto top = Renderer([] { return text("Top") | center;});
272/// auto bottom = Renderer([] { return text("Bottom") | center;});
273/// auto split = ResizableSplitTop(top, bottom, &top_size)
274/// screen.Loop(split);
275/// ```
276///
277/// ### Output
278///
279/// ```bash
280/// top
281/// ────────────
282/// bottom
283/// ```
284Component ResizableSplitTop(Component main, Component back, int* main_size) {
285 return ResizableSplit({
286 std::move(main),
287 std::move(back),
288 Direction::Up,
289 main_size,
290 });
291}
292
293/// @brief An vertical split in between two components, configurable using the
294/// mouse.
295/// @param main The main component of size |main_size|, on the bottom.
296/// @param back The back component taking the remaining size, on the top.
297/// @param main_size The size of the |main| component.
298/// @ingroup component
299///
300/// ### Example
301///
302/// ```cpp
303/// auto screen = ScreenInteractive::Fullscreen();
304/// int bottom_size = 1;
305/// auto top = Renderer([] { return text("Top") | center;});
306/// auto bottom = Renderer([] { return text("Bottom") | center;});
307/// auto split = ResizableSplit::Bottom(bottom, top, &bottom_size)
308/// screen.Loop(split);
309/// ```
310///
311/// ### Output
312///
313/// ```bash
314/// top
315/// ────────────
316/// bottom
317/// ```
318Component ResizableSplitBottom(Component main, Component back, int* main_size) {
319 return ResizableSplit({
320 std::move(main),
321 std::move(back),
322 Direction::Down,
323 main_size,
324 });
325}
326
327} // namespace ftxui
virtual bool OnEvent(Event)
Called in response to an event.
Component Horizontal(Components children)
A list of components, drawn one by one horizontally and navigated horizontally using left/right arrow...
Component Vertical(Components children)
A list of components, drawn one by one vertically and navigated vertically using up/down arrow key or...
Element xflex(Element)
Expand/Minimize if possible/needed on the X axis.
Definition flex.cpp:129
Decorator size(WidthOrHeight, Constraint, int value)
Apply a constraint on the size of an element.
Element yflex(Element)
Expand/Minimize if possible/needed on the Y axis.
Definition flex.cpp:135
Element text(std::wstring text)
Display a piece of unicode text.
Definition text.cpp:160
Element vbox(Elements)
A container displaying elements vertically one by one.
Definition vbox.cpp:96
bool Contain(int x, int y) const
Definition box.cpp:42
int x_max
Definition box.hpp:18
int y_min
Definition box.hpp:19
int y_max
Definition box.hpp:20
int x_min
Definition box.hpp:17
The FTXUI ftxui:: namespace.
Definition animation.hpp:10
std::unique_ptr< CapturedMouseInterface > CapturedMouse
std::shared_ptr< Node > Element
Definition elements.hpp:22
Element hbox(Elements)
A container displaying elements horizontally one by one.
Definition hbox.cpp:94
Decorator reflect(Box &box)
Definition reflect.cpp:43
std::shared_ptr< ComponentBase > Component