FTXUI  0.10.0
C++ functional terminal UI.
Loading...
Searching...
No Matches
resizable_split.cpp
Go to the documentation of this file.
1#include <memory> // for __shared_ptr_access
2#include <utility> // for move
3
4#include "ftxui/component/captured_mouse.hpp" // for CapturedMouse
5#include "ftxui/component/component.hpp" // for Component, Make, Horizontal, Vertical, ResizableSplitBottom, ResizableSplitLeft, ResizableSplitRight, ResizableSplitTop
6#include "ftxui/component/component_base.hpp" // for ComponentBase
7#include "ftxui/component/event.hpp" // for Event
8#include "ftxui/component/mouse.hpp" // for Mouse, Mouse::Left, Mouse::Pressed, Mouse::Released
9#include "ftxui/dom/elements.hpp" // for operator|, reflect, Element, separator, size, EQUAL, xflex, yflex, hbox, vbox, HEIGHT, WIDTH
10#include "ftxui/screen/box.hpp" // for Box
11
12namespace ftxui {
13namespace {
14
15class ResizableSplitLeftBase : public ComponentBase {
16 public:
17 ResizableSplitLeftBase(Component main, Component child, int* main_size)
18 : main_(main), child_(child), main_size_(main_size) {
20 main,
21 child,
22 }));
23 }
24
25 bool OnEvent(Event event) final {
26 if (event.is_mouse())
27 return OnMouseEvent(std::move(event));
28 return ComponentBase::OnEvent(std::move(event));
29 }
30
31 bool OnMouseEvent(Event event) {
32 if (captured_mouse_ && event.mouse().motion == Mouse::Released) {
33 captured_mouse_.reset();
34 return true;
35 }
36
37 if (event.mouse().button == Mouse::Left &&
38 event.mouse().motion == Mouse::Pressed &&
39 separator_box_.Contain(event.mouse().x, event.mouse().y) &&
40 !captured_mouse_) {
41 captured_mouse_ = CaptureMouse(event);
42 return true;
43 }
44
45 if (captured_mouse_) {
46 *main_size_ = event.mouse().x - box_.x_min;
47 return true;
48 }
49
50 return ComponentBase::OnEvent(event);
51 }
52
53 Element Render() final {
54 return hbox({
55 main_->Render() | size(WIDTH, EQUAL, *main_size_),
56 separator() | reflect(separator_box_),
57 child_->Render() | xflex,
58 }) |
59 reflect(box_);
60 };
61
62 private:
63 Component main_;
64 Component child_;
65 int* const main_size_;
66 CapturedMouse captured_mouse_;
67 Box separator_box_;
68 Box box_;
69};
70
71class ResizableSplitRightBase : public ComponentBase {
72 public:
73 ResizableSplitRightBase(Component main, Component child, int* main_size)
74 : main_(main), child_(child), main_size_(main_size) {
76 child,
77 main,
78 }));
79 }
80
81 bool OnEvent(Event event) final {
82 if (event.is_mouse())
83 return OnMouseEvent(std::move(event));
84 return ComponentBase::OnEvent(std::move(event));
85 }
86
87 bool OnMouseEvent(Event event) {
88 if (captured_mouse_ && event.mouse().motion == Mouse::Released) {
89 captured_mouse_.reset();
90 return true;
91 }
92
93 if (event.mouse().button == Mouse::Left &&
94 event.mouse().motion == Mouse::Pressed &&
95 separator_box_.Contain(event.mouse().x, event.mouse().y) &&
96 !captured_mouse_) {
97 captured_mouse_ = CaptureMouse(event);
98 return true;
99 }
100
101 if (captured_mouse_) {
102 *main_size_ = box_.x_max - event.mouse().x;
103 return true;
104 }
105
106 return ComponentBase::OnEvent(event);
107 }
108
109 Element Render() final {
110 return hbox({
111 child_->Render() | xflex,
112 separator() | reflect(separator_box_),
113 main_->Render() | size(WIDTH, EQUAL, *main_size_),
114 }) |
115 reflect(box_);
116 };
117
118 private:
119 Component main_;
120 Component child_;
121 int* const main_size_;
122 CapturedMouse captured_mouse_;
123 Box separator_box_;
124 Box box_;
125};
126
127class ResizableSplitTopBase : public ComponentBase {
128 public:
129 ResizableSplitTopBase(Component main, Component child, int* main_size)
130 : main_(main), child_(child), main_size_(main_size) {
132 main,
133 child,
134 }));
135 }
136
137 bool OnEvent(Event event) final {
138 if (event.is_mouse())
139 return OnMouseEvent(std::move(event));
140 return ComponentBase::OnEvent(std::move(event));
141 }
142
143 bool OnMouseEvent(Event event) {
144 if (captured_mouse_ && event.mouse().motion == Mouse::Released) {
145 captured_mouse_.reset();
146 return true;
147 }
148
149 if (event.mouse().button == Mouse::Left &&
150 event.mouse().motion == Mouse::Pressed &&
151 separator_box_.Contain(event.mouse().x, event.mouse().y) &&
152 !captured_mouse_) {
153 captured_mouse_ = CaptureMouse(event);
154 return true;
155 }
156
157 if (captured_mouse_) {
158 *main_size_ = event.mouse().y - box_.y_min;
159 return true;
160 }
161
162 return ComponentBase::OnEvent(event);
163 }
164
165 Element Render() final {
166 return vbox({
167 main_->Render() | size(HEIGHT, EQUAL, *main_size_),
168 separator() | reflect(separator_box_),
169 child_->Render() | yflex,
170 }) |
171 reflect(box_);
172 };
173
174 private:
175 Component main_;
176 Component child_;
177 int* const main_size_;
178 CapturedMouse captured_mouse_;
179 Box separator_box_;
180 Box box_;
181};
182
183class ResizableSplitBottomBase : public ComponentBase {
184 public:
185 ResizableSplitBottomBase(Component main, Component child, int* main_size)
186 : main_(main), child_(child), main_size_(main_size) {
188 child,
189 main,
190 }));
191 }
192
193 bool OnEvent(Event event) final {
194 if (event.is_mouse())
195 return OnMouseEvent(std::move(event));
196 return ComponentBase::OnEvent(std::move(event));
197 }
198
199 bool OnMouseEvent(Event event) {
200 if (captured_mouse_ && event.mouse().motion == Mouse::Released) {
201 captured_mouse_.reset();
202 return true;
203 }
204
205 if (event.mouse().button == Mouse::Left &&
206 event.mouse().motion == Mouse::Pressed &&
207 separator_box_.Contain(event.mouse().x, event.mouse().y) &&
208 !captured_mouse_) {
209 captured_mouse_ = CaptureMouse(event);
210 return true;
211 }
212
213 if (captured_mouse_) {
214 *main_size_ = box_.y_max - event.mouse().y;
215 return true;
216 }
217
218 return ComponentBase::OnEvent(event);
219 }
220
221 Element Render() final {
222 return vbox({
223 child_->Render() | yflex,
224 separator() | reflect(separator_box_),
225 main_->Render() | size(HEIGHT, EQUAL, *main_size_),
226 }) |
227 reflect(box_);
228 };
229
230 private:
231 Component main_;
232 Component child_;
233 int* const main_size_;
234 CapturedMouse captured_mouse_;
235 Box separator_box_;
236 Box box_;
237};
238
239} // namespace
240
241/// @brief An horizontal split in between two components, configurable using the
242/// mouse.
243/// @param main The main component of size |main_size|, on the left.
244/// @param back The back component taking the remaining size, on the right.
245/// @param main_size The size of the |main| component.
246/// @ingroup component
247///
248/// ### Example
249///
250/// ```cpp
251/// auto screen = ScreenInteractive::Fullscreen();
252/// int left_size = 10;
253/// auto left = Renderer([] { return text("Left") | center;});
254/// auto right = Renderer([] { return text("right") | center;});
255/// auto split = ResizableSplitLeft(left, right, &left_size);
256/// screen.Loop(split);
257/// ```
258///
259/// ### Output
260///
261/// ```bash
262/// │
263/// left │ right
264/// │
265/// ```
266Component ResizableSplitLeft(Component main, Component back, int* main_size) {
267 return Make<ResizableSplitLeftBase>(std::move(main), std::move(back),
268 main_size);
269}
270
271/// @brief An horizontal split in between two components, configurable using the
272/// mouse.
273/// @param main The main component of size |main_size|, on the right.
274/// @param back The back component taking the remaining size, on the left.
275/// @param main_size The size of the |main| component.
276/// @ingroup component
277///
278/// ### Example
279///
280/// ```cpp
281/// auto screen = ScreenInteractive::Fullscreen();
282/// int right_size = 10;
283/// auto left = Renderer([] { return text("Left") | center;});
284/// auto right = Renderer([] { return text("right") | center;});
285/// auto split = ResizableSplitRight(right, left, &right_size);
286/// screen.Loop(split);
287/// ```
288///
289/// ### Output
290///
291/// ```bash
292/// │
293/// left │ right
294/// │
295/// ```
297 return Make<ResizableSplitRightBase>(std::move(main), std::move(back),
298 main_size);
299}
300
301/// @brief An vertical split in between two components, configurable using the
302/// mouse.
303/// @param main The main component of size |main_size|, on the top.
304/// @param back The back component taking the remaining size, on the bottom.
305/// @param main_size The size of the |main| component.
306/// @ingroup component
307///
308/// ### Example
309///
310/// ```cpp
311/// auto screen = ScreenInteractive::Fullscreen();
312/// int top_size = 1;
313/// auto top = Renderer([] { return text("Top") | center;});
314/// auto bottom = Renderer([] { return text("Bottom") | center;});
315/// auto split = ResizableSplitTop(top, bottom, &top_size);
316/// screen.Loop(split);
317/// ```
318///
319/// ### Output
320///
321/// ```bash
322/// top
323/// ────────────
324/// bottom
325/// ```
326Component ResizableSplitTop(Component main, Component back, int* main_size) {
327 return Make<ResizableSplitTopBase>(std::move(main), std::move(back),
328 main_size);
329}
330
331/// @brief An vertical split in between two components, configurable using the
332/// mouse.
333/// @param main The main component of size |main_size|, on the bottom.
334/// @param back The back component taking the remaining size, on the top.
335/// @param main_size The size of the |main| component.
336/// @ingroup component
337///
338/// ### Example
339///
340/// ```cpp
341/// auto screen = ScreenInteractive::Fullscreen();
342/// int bottom_size = 1;
343/// auto top = Renderer([] { return text("Top") | center;});
344/// auto bottom = Renderer([] { return text("Bottom") | center;});
345/// auto split = ResizableSplit::Bottom(bottom, top, &bottom_size);
346/// screen.Loop(split);
347/// ```
348///
349/// ### Output
350///
351/// ```bash
352/// top
353/// ────────────
354/// bottom
355/// ```
357 return Make<ResizableSplitBottomBase>(std::move(main), std::move(back),
358 main_size);
359}
360} // namespace ftxui
361
362// Copyright 2021 Arthur Sonzogni. All rights reserved.
363// Use of this source code is governed by the MIT license that can be found in
364// the LICENSE file.
virtual bool OnEvent(Event)
Called in response to an event.
Definition component.cpp:95
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:125
@ HEIGHT
Definition elements.hpp:90
@ WIDTH
Definition elements.hpp:90
Component ResizableSplitTop(Component main, Component back, int *main_size)
An vertical split in between two components, configurable using the mouse.
std::unique_ptr< CapturedMouseInterface > CapturedMouse
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:25
std::shared_ptr< Node > Element
Definition elements.hpp:15
Element yflex(Element)
Expand/Minimize if possible/needed on the Y axis.
Definition flex.cpp:131
Element separator(void)
Definition separator.cpp:61
Element hbox(Elements)
A container displaying elements horizontally one by one.
Definition hbox.cpp:76
Component ResizableSplitRight(Component main, Component back, int *main_size)
An horizontal split in between two components, configurable using the mouse.
Decorator reflect(Box &box)
Definition reflect.cpp:39
Component ResizableSplitBottom(Component main, Component back, int *main_size)
An vertical split in between two components, configurable using the mouse.
void Render(Screen &screen, const Element &node)
Display an element on a ftxui::Screen.
Definition node.cpp:34
Decorator size(Direction, Constraint, int value)
Apply a constraint on the size of an element.
Definition size.cpp:86
@ EQUAL
Definition elements.hpp:91
Component ResizableSplitLeft(Component main, Component back, int *main_size)
An horizontal split in between two components, configurable using the mouse.
std::shared_ptr< ComponentBase > Component
Element vbox(Elements)
A container displaying elements vertically one by one.
Definition vbox.cpp:77