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