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