FTXUI 6.1.9 C++ functional terminal UI.

Loading...
Searching...
No Matches
src/ftxui/component/window.cpp
Go to the documentation of this file.
1// Copyright 2023 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#define NOMINMAX
5#include <algorithm>
6#include <ftxui/component/component.hpp>
7#include <ftxui/component/component_base.hpp>
8#include <ftxui/component/component_options.hpp>
9#include <ftxui/component/screen_interactive.hpp> // for ScreenInteractive
10#include <memory>
11#include <utility>
12#include "ftxui/dom/elements.hpp" // for text, window, hbox, vbox, size, clear_under, reflect, emptyElement
13#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator
14#include "ftxui/screen/color.hpp" // for Color
15#include "ftxui/screen/screen.hpp" // for Screen
16
17 namespace ftxui {
18
19 namespace {
20
21 Decorator PositionAndSize(int left, int top, int width, int height) {
22 return [=](Element element) {
23 element |= size(WIDTH, EQUAL, width);
24 element |= size(HEIGHT, EQUAL, height);
25
26 auto padding_left = emptyElement() | size(WIDTH, EQUAL, left);
27 auto padding_top = emptyElement() | size(HEIGHT, EQUAL, top);
28
29 return vbox({
30 padding_top,
31 hbox({
32 padding_left,
33 element,
34 }),
35 });
36 };
37}
38
39 class ResizeDecorator : public NodeDecorator {
40 public:
41 ResizeDecorator(Element child,
42 bool resize_left,
43 bool resize_right,
44 bool resize_top,
45 bool resize_down,
46 Color color)
47 : NodeDecorator(std::move(child)),
48 color_(color),
49 resize_left_(resize_left),
50 resize_right_(resize_right),
51 resize_top_(resize_top),
52 resize_down_(resize_down) {}
53
54 void Render(Screen& screen) override {
55 NodeDecorator::Render(screen);
56
57 if (resize_left_) {
58 for (int y = box_.y_min; y <= box_.y_max; ++y) {
59 auto& cell = screen.PixelAt(box_.x_min, y);
60 cell.foreground_color = color_;
61 cell.automerge = false;
62 }
63 }
64 if (resize_right_) {
65 for (int y = box_.y_min; y <= box_.y_max; ++y) {
66 auto& cell = screen.PixelAt(box_.x_max, y);
67 cell.foreground_color = color_;
68 cell.automerge = false;
69 }
70 }
71 if (resize_top_) {
72 for (int x = box_.x_min; x <= box_.x_max; ++x) {
73 auto& cell = screen.PixelAt(x, box_.y_min);
74 cell.foreground_color = color_;
75 cell.automerge = false;
76 }
77 }
78 if (resize_down_) {
79 for (int x = box_.x_min; x <= box_.x_max; ++x) {
80 auto& cell = screen.PixelAt(x, box_.y_max);
81 cell.foreground_color = color_;
82 cell.automerge = false;
83 }
84 }
85 }
86
87 Color color_;
88 const bool resize_left_;
89 const bool resize_right_;
90 const bool resize_top_;
91 const bool resize_down_;
92};
93
94 Element DefaultRenderState(const WindowRenderState& state) {
95 Element element = state.inner;
96 if (!state.active) {
97 element |= dim;
98 }
99
100 element = window(text(state.title), element);
101 element |= clear_under;
102
103 const Color color = Color::Red;
104
105 element = std::make_shared<ResizeDecorator>( //
106 element, //
107 state.hover_left, //
108 state.hover_right, //
109 state.hover_top, //
110 state.hover_down, //
111 color //
112 );
113
114 return element;
115}
116
117 class WindowImpl : public ComponentBase, public WindowOptions {
118 public:
119 explicit WindowImpl(WindowOptions option) : WindowOptions(std::move(option)) {
120 if (!inner) {
121 inner = Make<ComponentBase>();
122 }
123 Add(inner);
124 }
125
126 private:
127 Element OnRender() final {
128 auto element = ComponentBase::Render();
129
130 const bool captureable =
131 captured_mouse_ || ScreenInteractive::Active()->CaptureMouse();
132
133 const WindowRenderState state = {
134 element,
135 title(),
136 Active(),
137 drag_,
138 resize_left_ || resize_right_ || resize_down_ || resize_top_,
139 (resize_left_hover_ || resize_left_) && captureable,
140 (resize_right_hover_ || resize_right_) && captureable,
141 (resize_top_hover_ || resize_top_) && captureable,
142 (resize_down_hover_ || resize_down_) && captureable,
143 };
144
145 element = render ? render(state) : DefaultRenderState(state);
146
147 // Position and record the drawn area of the window.
148 element |= reflect(box_window_);
149 element |= PositionAndSize(left(), top(), width(), height());
150 element |= reflect(box_);
151
152 return element;
153 }
154
155 bool OnEvent(Event event) final {
156 if (ComponentBase::OnEvent(event)) {
157 return true;
158 }
159
160 if (!event.is_mouse()) {
161 return false;
162 }
163
164 mouse_hover_ = box_window_.Contain(event.mouse().x, event.mouse().y);
165
166 resize_down_hover_ = false;
167 resize_top_hover_ = false;
168 resize_left_hover_ = false;
169 resize_right_hover_ = false;
170
171 if (mouse_hover_) {
172 resize_left_hover_ = event.mouse().x == left() + box_.x_min;
173 resize_right_hover_ =
174 event.mouse().x == left() + width() - 1 + box_.x_min;
175 resize_top_hover_ = event.mouse().y == top() + box_.y_min;
176 resize_down_hover_ = event.mouse().y == top() + height() - 1 + box_.y_min;
177
178 // Apply the component options:
179 resize_top_hover_ &= resize_top();
180 resize_left_hover_ &= resize_left();
181 resize_down_hover_ &= resize_down();
182 resize_right_hover_ &= resize_right();
183 }
184
185 if (captured_mouse_) {
186 if (event.mouse().motion == Mouse::Released) {
187 captured_mouse_ = nullptr;
188 return true;
189 }
190
191 if (resize_left_) {
192 width() = left() + width() - event.mouse().x + box_.x_min;
193 left() = event.mouse().x - box_.x_min;
194 }
195
196 if (resize_right_) {
197 width() = event.mouse().x - resize_start_x - box_.x_min;
198 }
199
200 if (resize_top_) {
201 height() = top() + height() - event.mouse().y + box_.y_min;
202 top() = event.mouse().y - box_.y_min;
203 }
204
205 if (resize_down_) {
206 height() = event.mouse().y - resize_start_y - box_.y_min;
207 }
208
209 if (drag_) {
210 left() = event.mouse().x - drag_start_x - box_.x_min;
211 top() = event.mouse().y - drag_start_y - box_.y_min;
212 }
213
214 // Clamp the window size.
215 width() = std::max<int>(width(), static_cast<int>(title().size() + 2));
216 height() = std::max<int>(height(), 2);
217
218 return true;
219 }
220
221 resize_left_ = false;
222 resize_right_ = false;
223 resize_top_ = false;
224 resize_down_ = false;
225
226 if (!mouse_hover_) {
227 return false;
228 }
229
230 if (!CaptureMouse(event)) {
231 return true;
232 }
233
234 if (event.mouse().button != Mouse::Left) {
235 return true;
236 }
237 if (event.mouse().motion != Mouse::Pressed) {
238 return true;
239 }
240
241 TakeFocus();
242
243 captured_mouse_ = CaptureMouse(event);
244 if (!captured_mouse_) {
245 return true;
246 }
247
248 resize_left_ = resize_left_hover_;
249 resize_right_ = resize_right_hover_;
250 resize_top_ = resize_top_hover_;
251 resize_down_ = resize_down_hover_;
252
253 resize_start_x = event.mouse().x - width() - box_.x_min;
254 resize_start_y = event.mouse().y - height() - box_.y_min;
255 drag_start_x = event.mouse().x - left() - box_.x_min;
256 drag_start_y = event.mouse().y - top() - box_.y_min;
257
258 // Drag only if we are not resizeing a border yet:
259 drag_ = !resize_right_ && !resize_down_ && !resize_top_ && !resize_left_;
260 return true;
261 }
262
263 Box box_;
264 Box box_window_;
265
266 CapturedMouse captured_mouse_;
267 int drag_start_x = 0;
268 int drag_start_y = 0;
269 int resize_start_x = 0;
270 int resize_start_y = 0;
271
272 bool mouse_hover_ = false;
273 bool drag_ = false;
274 bool resize_top_ = false;
275 bool resize_left_ = false;
276 bool resize_down_ = false;
277 bool resize_right_ = false;
278
279 bool resize_top_hover_ = false;
280 bool resize_left_hover_ = false;
281 bool resize_down_hover_ = false;
282 bool resize_right_hover_ = false;
283};
284
285} // namespace
286
287/// @brief A draggeable / resizeable window. To use multiple of them, they must
288/// be stacked using `Container::Stacked({...})` component;
289///
290/// @param option A struct holding every parameters.
291/// @ingroup component
292/// @see Window
293///
294/// ### Example
295///
296/// ```cpp
297/// auto window_1= Window({
298/// .inner = DummyWindowContent(),
299/// .title = "First window",
300/// });
301///
302/// auto window_2= Window({
303/// .inner = DummyWindowContent(),
304/// .title = "Second window",
305/// });
306///
307/// auto container = Container::Stacked({
308/// window_1,
309/// window_2,
310/// });
311/// ```
312 Component Window(WindowOptions option) {
313 return Make<WindowImpl>(std::move(option));
314}
315
316}; // namespace ftxui
color.hpp
component.hpp
component_base.hpp
component_options.hpp
elements.hpp
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::Render
Element Render()
Draw the component. Build a ftxui::Element to be drawn on the ftxui::Screen representing this ftxui::...
Definition component.cpp:103
ftxui::ScreenInteractive::Active
static ScreenInteractive * Active()
Return the currently active screen, or null if none.
Definition screen_interactive.cpp:596
ftxui::ScreenInteractive::CaptureMouse
CapturedMouse CaptureMouse()
Try to get the unique lock about behing able to capture the mouse.
Definition screen_interactive.cpp:487
ftxui::ComponentBase::OnEvent
virtual bool OnEvent(Event)
Called in response to an event.
Definition component.cpp:151
ftxui::Window
Component Window(WindowOptions option)
A draggeable / resizeable window. To use multiple of them, they must be stacked using Container::Stac...
Definition src/ftxui/component/window.cpp:312
ftxui::Node::Render
friend void Render(Screen &screen, Node *node, Selection &selection)
Definition node.cpp:96
ftxui::window
Element window(Element title, Element content, BorderStyle border=ROUNDED)
Draw window with a title and a border around the element.
Definition src/ftxui/dom/border.cpp:507
ftxui::clear_under
Element clear_under(Element element)
Before drawing |child|, clear the pixels below. This is useful in combination with dbox.
Definition clear_under.cpp:38
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::emptyElement
Element emptyElement()
Definition dom/util.cpp:140
ftxui::text
Element text(std::wstring text)
Display a piece of unicode text.
Definition text.cpp:160
ftxui::dim
Element dim(Element)
Use a light font, for elements with less emphasis.
Definition dim.cpp:33
ftxui::Render
void Render(Screen &screen, const Element &element)
Display an element on a ftxui::Screen.
Definition node.cpp:84
ftxui::vbox
Element vbox(Elements)
A container displaying elements vertically one by one.
Definition vbox.cpp:96
ftxui::Color::Red
@ Red
Definition color.hpp:55
ftxui::Terminal::Color
Color
Color is an enumeration that represents the color support of the terminal.
Definition terminal.hpp:23
ftxui
The FTXUI ftxui:: namespace.
Definition animation.hpp:10
ftxui::HEIGHT
@ HEIGHT
Definition elements.hpp:161
ftxui::WIDTH
@ WIDTH
Definition elements.hpp:161
ftxui::Decorator
std::function< Element(Element)> Decorator
Definition elements.hpp:24
ftxui::CapturedMouse
std::unique_ptr< CapturedMouseInterface > CapturedMouse
Definition captured_mouse.hpp:20
ftxui::Make
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:26
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
node_decorator.hpp
top
std::uint8_t top
Definition screen.cpp:130
left
std::uint8_t left
Definition screen.cpp:129
screen.hpp
screen_interactive.hpp
resize_left_
const bool resize_left_
Definition src/ftxui/component/window.cpp:88
resize_top_
const bool resize_top_
Definition src/ftxui/component/window.cpp:90
resize_right_
const bool resize_right_
Definition src/ftxui/component/window.cpp:89
resize_down_
const bool resize_down_
Definition src/ftxui/component/window.cpp:91
color_
Color color_
Definition src/ftxui/component/window.cpp:87
ftxui::WindowOptions
Definition component_options.hpp:251