FTXUI 6.1.9 C++ functional terminal UI.

Loading...
Searching...
No Matches
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 <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
18 namespace ftxui {
19 namespace {
20
21 class ResizableSplitBase : public ComponentBase {
22 public:
23 explicit ResizableSplitBase(ResizableSplitOption options)
24 : options_(std::move(options)) {
25 switch (options_->direction()) {
26 case Direction::Left:
27 Add(Container::Horizontal({
28 options_->main,
29 options_->back,
30 }));
31 break;
32 case Direction::Right:
33 Add(Container::Horizontal({
34 options_->back,
35 options_->main,
36 }));
37 break;
38 case Direction::Up:
39 Add(Container::Vertical({
40 options_->main,
41 options_->back,
42 }));
43 break;
44 case Direction::Down:
45 Add(Container::Vertical({
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_) {
75 return ComponentBase::OnEvent(event);
76 }
77
78 switch (options_->direction()) {
79 case Direction::Left:
80 options_->main_size() = std::max(0, event.mouse().x - box_.x_min);
81 return true;
82 case Direction::Right:
83 options_->main_size() = std::max(0, box_.x_max - event.mouse().x);
84 return true;
85 case Direction::Up:
86 options_->main_size() = std::max(0, event.mouse().y - box_.y_min);
87 return true;
88 case Direction::Down:
89 options_->main_size() = std::max(0, box_.y_max - event.mouse().y);
90 return true;
91 }
92
93 // NOTREACHED()
94 return false;
95 }
96
97 Element OnRender() final {
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
112 Element RenderLeft() {
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
122 Element RenderRight() {
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
132 Element RenderTop() {
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
142 Element RenderBottom() {
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:
153 Ref<ResizableSplitOption> options_;
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/// ```
186 Component ResizableSplit(ResizableSplitOption options) {
187 return Make<ResizableSplitBase>(std::move(options));
188}
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/// ```
215 Component ResizableSplitLeft(Component main, Component back, int* main_size) {
216 return ResizableSplit({
217 std::move(main),
218 std::move(back),
219 Direction::Left,
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/// ```
249 Component ResizableSplitRight(Component main, Component back, int* main_size) {
250 return ResizableSplit({
251 std::move(main),
252 std::move(back),
253 Direction::Right,
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/// ```
283 Component ResizableSplitTop(Component main, Component back, int* main_size) {
284 return ResizableSplit({
285 std::move(main),
286 std::move(back),
287 Direction::Up,
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/// ```
317 Component ResizableSplitBottom(Component main, Component back, int* main_size) {
318 return ResizableSplit({
319 std::move(main),
320 std::move(back),
321 Direction::Down,
322 main_size,
323 });
324}
325
326} // namespace ftxui
box.hpp
captured_mouse.hpp
component.hpp
component_base.hpp
component_options.hpp
direction.hpp
elements.hpp
event.hpp
main
int main()
Definition examples/component/button.cpp:33
ftxui::Mouse::Left
@ Left
Definition mouse.hpp:13
ftxui::Mouse::Pressed
@ Pressed
Definition mouse.hpp:25
ftxui::Mouse::Released
@ Released
Definition mouse.hpp:24
ftxui::ComponentBase::OnEvent
virtual bool OnEvent(Event)
Called in response to an event.
Definition component.cpp:151
ftxui::Container::Horizontal
Component Horizontal(Components children)
A list of components, drawn one by one horizontally and navigated horizontally using left/right arrow...
Definition container.cpp:360
ftxui::Container::Vertical
Component Vertical(Components children)
A list of components, drawn one by one vertically and navigated vertically using up/down arrow key or...
Definition container.cpp:317
ftxui::xflex
Element xflex(Element)
Expand/Minimize if possible/needed on the X axis.
Definition flex.cpp:129
ftxui::size
Decorator size(WidthOrHeight, Constraint, int value)
Apply a constraint on the size of an element.
Definition src/ftxui/dom/size.cpp:89
ftxui::yflex
Element yflex(Element)
Expand/Minimize if possible/needed on the Y axis.
Definition flex.cpp:135
ftxui::text
Element text(std::wstring text)
Display a piece of unicode text.
Definition text.cpp:160
ftxui::vbox
Element vbox(Elements)
A container displaying elements vertically one by one.
Definition vbox.cpp:96
ftxui::Direction::Down
@ Down
ftxui::Direction::Up
@ Up
ftxui::Direction::Right
@ Right
ftxui::Direction::Left
@ Left
ftxui::Box::Contain
bool Contain(int x, int y) const
Definition box.cpp:42
ftxui::Box::x_max
int x_max
Definition box.hpp:18
ftxui::Box::y_min
int y_min
Definition box.hpp:19
ftxui::Box::y_max
int y_max
Definition box.hpp:20
ftxui::Box::x_min
int x_min
Definition box.hpp:17
mouse.hpp
ftxui
The FTXUI ftxui:: namespace.
Definition animation.hpp:10
ftxui::HEIGHT
@ HEIGHT
Definition elements.hpp:161
ftxui::WIDTH
@ WIDTH
Definition elements.hpp:161
ftxui::CapturedMouse
std::unique_ptr< CapturedMouseInterface > CapturedMouse
Definition captured_mouse.hpp:20
ftxui::Element
std::shared_ptr< Node > Element
Definition elements.hpp:22
ftxui::hbox
Element hbox(Elements)
A container displaying elements horizontally one by one.
Definition hbox.cpp:94
ftxui::reflect
Decorator reflect(Box &box)
Definition reflect.cpp:43
ftxui::EQUAL
@ EQUAL
Definition elements.hpp:162
ftxui::Component
std::shared_ptr< ComponentBase > Component
Definition component_base.hpp:24
ref.hpp
ftxui::ResizableSplitOption
Definition component_options.hpp:211