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// このソースコードの使用は、LICENSEファイルにあるMITライセンスによって管理されています。
3#define NOMINMAX
4#include <algorithm>
8#include <ftxui/component/screen_interactive.hpp> // for ScreenInteractive
9#include <memory>
10#include <utility>
11#include "ftxui/dom/elements.hpp" // for text, window, hbox, vbox, size, clear_under, reflect, emptyElement
12#include "ftxui/dom/node_decorator.hpp" // for NodeDecorator
13#include "ftxui/screen/color.hpp" // for Color
14#include "ftxui/screen/screen.hpp" // for Screen
15
16namespace ftxui {
17
18namespace {
19
20Decorator PositionAndSize(int left, int top, int width, int height) {
21 return [=](Element element) {
22 element |= size(WIDTH, EQUAL, width);
23 element |= size(HEIGHT, EQUAL, height);
24
25 auto padding_left = emptyElement() | size(WIDTH, EQUAL, left);
26 auto padding_top = emptyElement() | size(HEIGHT, EQUAL, top);
27
28 return vbox({
29 padding_top,
30 hbox({
31 padding_left,
32 element,
33 }),
34 });
35 };
36}
37
38class ResizeDecorator : public NodeDecorator {
39 public:
40 ResizeDecorator(Element child,
41 bool resize_left,
42 bool resize_right,
43 bool resize_top,
44 bool resize_down,
45 Color color)
46 : NodeDecorator(std::move(child)),
47 color_(color),
48 resize_left_(resize_left),
49 resize_right_(resize_right),
50 resize_top_(resize_top),
51 resize_down_(resize_down) {}
52
53 void Render(Screen& screen) override {
55
56 if (resize_left_) {
57 for (int y = box_.y_min; y <= box_.y_max; ++y) {
58 auto& cell = screen.PixelAt(box_.x_min, y);
59 cell.foreground_color = color_;
60 cell.automerge = false;
61 }
62 }
63 if (resize_right_) {
64 for (int y = box_.y_min; y <= box_.y_max; ++y) {
65 auto& cell = screen.PixelAt(box_.x_max, y);
66 cell.foreground_color = color_;
67 cell.automerge = false;
68 }
69 }
70 if (resize_top_) {
71 for (int x = box_.x_min; x <= box_.x_max; ++x) {
72 auto& cell = screen.PixelAt(x, box_.y_min);
73 cell.foreground_color = color_;
74 cell.automerge = false;
75 }
76 }
77 if (resize_down_) {
78 for (int x = box_.x_min; x <= box_.x_max; ++x) {
79 auto& cell = screen.PixelAt(x, box_.y_max);
80 cell.foreground_color = color_;
81 cell.automerge = false;
82 }
83 }
84 }
85
86 Color color_;
87 const bool resize_left_;
88 const bool resize_right_;
89 const bool resize_top_;
90 const bool resize_down_;
91};
92
93Element DefaultRenderState(const WindowRenderState& state) {
94 Element element = state.inner;
95 if (!state.active) {
96 element |= dim;
97 }
98
99 element = window(text(state.title), element);
100 element |= clear_under;
101
102 const Color color = Color::Red;
103
104 element = std::make_shared<ResizeDecorator>( //
105 element, //
106 state.hover_left, //
107 state.hover_right, //
108 state.hover_top, //
109 state.hover_down, //
110 color //
111 );
112
113 return element;
114}
115
116class WindowImpl : public ComponentBase, public WindowOptions {
117 public:
118 explicit WindowImpl(WindowOptions option) : WindowOptions(std::move(option)) {
119 if (!inner) {
120 inner = Make<ComponentBase>();
121 }
122 Add(inner);
123 }
124
125 private:
126 Element OnRender() final {
127 auto element = ComponentBase::Render();
128
129 const bool captureable =
130 captured_mouse_ || ScreenInteractive::Active()->CaptureMouse();
131
132 const WindowRenderState state = {
133 element,
134 title(),
135 Active(),
136 drag_,
138 (resize_left_hover_ || resize_left_) && captureable,
139 (resize_right_hover_ || resize_right_) && captureable,
140 (resize_top_hover_ || resize_top_) && captureable,
141 (resize_down_hover_ || resize_down_) && captureable,
142 };
143
144 element = render ? render(state) : DefaultRenderState(state);
145
146 // Position and record the drawn area of the window.
147 element |= reflect(box_window_);
148 element |= PositionAndSize(left(), top(), width(), height());
149 element |= reflect(box_);
150
151 return element;
152 }
153
154 bool OnEvent(Event event) final {
155 if (ComponentBase::OnEvent(event)) {
156 return true;
157 }
158
159 if (!event.is_mouse()) {
160 return false;
161 }
162
163 mouse_hover_ = box_window_.Contain(event.mouse().x, event.mouse().y);
164
165 resize_down_hover_ = false;
166 resize_top_hover_ = false;
167 resize_left_hover_ = false;
168 resize_right_hover_ = false;
169
170 if (mouse_hover_) {
171 resize_left_hover_ = event.mouse().x == left() + box_.x_min;
172 resize_right_hover_ =
173 event.mouse().x == left() + width() - 1 + box_.x_min;
174 resize_top_hover_ = event.mouse().y == top() + box_.y_min;
175 resize_down_hover_ = event.mouse().y == top() + height() - 1 + box_.y_min;
176
177 // Apply the component options:
178 resize_top_hover_ &= resize_top();
179 resize_left_hover_ &= resize_left();
180 resize_down_hover_ &= resize_down();
181 resize_right_hover_ &= resize_right();
182 }
183
184 if (captured_mouse_) {
185 if (event.mouse().motion == Mouse::Released) {
186 captured_mouse_ = nullptr;
187 return true;
188 }
189
190 if (resize_left_) {
191 width() = left() + width() - event.mouse().x + box_.x_min;
192 left() = event.mouse().x - box_.x_min;
193 }
194
195 if (resize_right_) {
196 width() = event.mouse().x - resize_start_x - box_.x_min;
197 }
198
199 if (resize_top_) {
200 height() = top() + height() - event.mouse().y + box_.y_min;
201 top() = event.mouse().y - box_.y_min;
202 }
203
204 if (resize_down_) {
205 height() = event.mouse().y - resize_start_y - box_.y_min;
206 }
207
208 if (drag_) {
209 left() = event.mouse().x - drag_start_x - box_.x_min;
210 top() = event.mouse().y - drag_start_y - box_.y_min;
211 }
212
213 // Clamp the window size.
214 width() = std::max<int>(width(), static_cast<int>(title().size() + 2));
215 height() = std::max<int>(height(), 2);
216
217 return true;
218 }
219
220 resize_left_ = false;
221 resize_right_ = false;
222 resize_top_ = false;
223 resize_down_ = false;
224
225 if (!mouse_hover_) {
226 return false;
227 }
228
229 if (!CaptureMouse(event)) {
230 return true;
231 }
232
233 if (event.mouse().button != Mouse::Left) {
234 return true;
235 }
236 if (event.mouse().motion != Mouse::Pressed) {
237 return true;
238 }
239
240 TakeFocus();
241
242 captured_mouse_ = CaptureMouse(event);
243 if (!captured_mouse_) {
244 return true;
245 }
246
247 resize_left_ = resize_left_hover_;
248 resize_right_ = resize_right_hover_;
249 resize_top_ = resize_top_hover_;
250 resize_down_ = resize_down_hover_;
251
252 resize_start_x = event.mouse().x - width() - box_.x_min;
253 resize_start_y = event.mouse().y - height() - box_.y_min;
254 drag_start_x = event.mouse().x - left() - box_.x_min;
255 drag_start_y = event.mouse().y - top() - box_.y_min;
256
257 // Drag only if we are not resizeing a border yet:
259 return true;
260 }
261
262 Box box_;
263 Box box_window_;
264
265 CapturedMouse captured_mouse_;
266 int drag_start_x = 0;
267 int drag_start_y = 0;
268 int resize_start_x = 0;
269 int resize_start_y = 0;
270
271 bool mouse_hover_ = false;
272 bool drag_ = false;
273 bool resize_top_ = false;
274 bool resize_left_ = false;
275 bool resize_down_ = false;
276 bool resize_right_ = false;
277
278 bool resize_top_hover_ = false;
279 bool resize_left_hover_ = false;
280 bool resize_down_hover_ = false;
281 bool resize_right_hover_ = false;
282};
283
284} // namespace
285
286/// @brief ドラッグ可能/サイズ変更可能なウィンドウ。複数のウィンドウを使用するには、それらを
287/// Container::Stacked({...})コンポーネントを使用してスタックする必要があります。
288///
289/// @param option すべてのパラメータを保持する構造体。
290/// @ingroup component
291/// @see Window
292///
293/// ### 例
294///
295/// ```cpp
296/// auto window_1= Window({
297/// .inner = DummyWindowContent(),
298/// .title = "First window",
299/// });
300///
301/// auto window_2= Window({
302/// .inner = DummyWindowContent(),
303/// .title = "Second window",
304/// });
305///
306/// auto container = Container::Stacked({
307/// window_1,
308/// window_2,
309/// });
310/// ```
312 return Make<WindowImpl>(std::move(option));
313}
314
315}; // namespace ftxui
Element Render()
コンポーネントを描画します。 このftxui::ComponentBaseを表すftxui::Screen上に描画されるftxui::Elementを構築します。レンダリングを変更するにはOnRende...
static ScreenInteractive * Active()
現在アクティブな画面を返します。アクティブな画面がない場合はヌルを返します。
CapturedMouse CaptureMouse()
マウスをキャプチャできることに関するユニークロックを取得しようとします。
virtual bool OnEvent(Event)
イベントに応じて呼び出されます。
Component Window(WindowOptions option)
ドラッグ可能/サイズ変更可能なウィンドウ。複数のウィンドウを使用するには、それらを Container::Stacked({...})コンポーネントを使用してスタックする必要があります。
friend void Render(Screen &screen, Node *node, Selection &selection)
Definition node.cpp:96
Element clear_under(Element element)
|child|を描画する前に、下にあるピクセルをクリアします。これは、 dboxと組み合わせて使用すると便利です。
Element emptyElement()
Definition dom/util.cpp:140
Element text(std::wstring text)
ユニコードテキストを表示します。
Definition text.cpp:160
Element dim(Element)
強調を抑えたい要素に、明るいフォントを使用します。
Definition dim.cpp:33
void Render(Screen &screen, const Element &element)
要素をftxui::Screenに表示します。
Definition node.cpp:84
Element vbox(Elements)
要素を縦に一つずつ表示するコンテナ。
Definition vbox.cpp:94
Color
Colorは、ターミナルの色サポートを表す列挙型です。
Definition terminal.hpp:21
FTXUI ftxui:: 名前空間
Definition animation.hpp:9
std::function< Element(Element)> Decorator
Definition elements.hpp:23
std::unique_ptr< CapturedMouseInterface > CapturedMouse
std::shared_ptr< T > Make(Args &&... args)
Definition component.hpp:26
std::shared_ptr< Node > Element
Definition elements.hpp:21
Element hbox(Elements)
要素を水平方向に1つずつ表示するコンテナ。
Definition hbox.cpp:93
Element window(Element title, Element content, BorderStyle border=ROUNDED)
Decorator reflect(Box &box)
Definition reflect.cpp:42
std::shared_ptr< ComponentBase > Component
std::uint8_t top
Definition screen.cpp:130
std::uint8_t left
Definition screen.cpp:129
const bool resize_left_
const bool resize_top_
const bool resize_right_
const bool resize_down_
return size
Definition string.cpp:1516