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