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