1/**************************************************************************/
2/* connections_dialog.h */
3/**************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/**************************************************************************/
8/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/**************************************************************************/
30
31#ifndef CONNECTIONS_DIALOG_H
32#define CONNECTIONS_DIALOG_H
33
34#include "scene/gui/check_button.h"
35#include "scene/gui/dialogs.h"
36#include "scene/gui/tree.h"
37
38class Button;
39class CheckBox;
40class ConnectDialogBinds;
41class EditorInspector;
42class Label;
43class LineEdit;
44class OptionButton;
45class PopupMenu;
46class SceneTreeEditor;
47class SpinBox;
48
49class ConnectDialog : public ConfirmationDialog {
50 GDCLASS(ConnectDialog, ConfirmationDialog);
51
52public:
53 struct ConnectionData {
54 Node *source = nullptr;
55 Node *target = nullptr;
56 StringName signal;
57 StringName method;
58 uint32_t flags = 0;
59 int unbinds = 0;
60 Vector<Variant> binds;
61
62 ConnectionData() {}
63
64 ConnectionData(const Connection &p_connection) {
65 source = Object::cast_to<Node>(p_connection.signal.get_object());
66 signal = p_connection.signal.get_name();
67 target = Object::cast_to<Node>(p_connection.callable.get_object());
68 flags = p_connection.flags;
69
70 Callable base_callable;
71 if (p_connection.callable.is_custom()) {
72 CallableCustomBind *ccb = dynamic_cast<CallableCustomBind *>(p_connection.callable.get_custom());
73 if (ccb) {
74 binds = ccb->get_binds();
75 base_callable = ccb->get_callable();
76 }
77
78 CallableCustomUnbind *ccu = dynamic_cast<CallableCustomUnbind *>(p_connection.callable.get_custom());
79 if (ccu) {
80 unbinds = ccu->get_unbinds();
81 base_callable = ccu->get_callable();
82 }
83 } else {
84 base_callable = p_connection.callable;
85 }
86 method = base_callable.get_method();
87 }
88
89 Callable get_callable() const {
90 if (unbinds > 0) {
91 return Callable(target, method).unbind(unbinds);
92 } else if (!binds.is_empty()) {
93 const Variant **argptrs = (const Variant **)alloca(sizeof(Variant *) * binds.size());
94 for (int i = 0; i < binds.size(); i++) {
95 argptrs[i] = &binds[i];
96 }
97 return Callable(target, method).bindp(argptrs, binds.size());
98 } else {
99 return Callable(target, method);
100 }
101 }
102 };
103
104private:
105 Label *connect_to_label = nullptr;
106 LineEdit *from_signal = nullptr;
107 LineEdit *filter_nodes = nullptr;
108 Node *source = nullptr;
109 ConnectionData source_connection_data;
110 StringName signal;
111 PackedStringArray signal_args;
112 LineEdit *dst_method = nullptr;
113 ConnectDialogBinds *cdbinds = nullptr;
114 bool edit_mode = false;
115 bool first_popup = true;
116 NodePath dst_path;
117 VBoxContainer *vbc_right = nullptr;
118 SceneTreeEditor *tree = nullptr;
119 AcceptDialog *error = nullptr;
120
121 Button *open_method_tree = nullptr;
122 AcceptDialog *method_popup = nullptr;
123 Tree *method_tree = nullptr;
124 Label *empty_tree_label = nullptr;
125 LineEdit *method_search = nullptr;
126 CheckButton *script_methods_only = nullptr;
127 CheckButton *compatible_methods_only = nullptr;
128
129 SpinBox *unbind_count = nullptr;
130 EditorInspector *bind_editor = nullptr;
131 OptionButton *type_list = nullptr;
132 CheckBox *deferred = nullptr;
133 CheckBox *one_shot = nullptr;
134 CheckButton *advanced = nullptr;
135 Vector<Control *> bind_controls;
136
137 Label *error_label = nullptr;
138
139 void ok_pressed() override;
140 void _cancel_pressed();
141 void _item_activated();
142 void _text_submitted(const String &p_text);
143 void _tree_node_selected();
144 void _focus_currently_connected();
145
146 void _method_selected();
147 void _create_method_tree_items(const List<MethodInfo> &p_methods, TreeItem *p_parent_item);
148 List<MethodInfo> _filter_method_list(const List<MethodInfo> &p_methods, const MethodInfo &p_signal, const String &p_search_string) const;
149 void _update_method_tree();
150 void _method_check_button_pressed(const CheckButton *p_button);
151 void _open_method_popup();
152
153 void _unbind_count_changed(double p_count);
154 void _add_bind();
155 void _remove_bind();
156 void _advanced_pressed();
157 void _update_ok_enabled();
158
159protected:
160 void _notification(int p_what);
161 static void _bind_methods();
162
163public:
164 static StringName generate_method_callback_name(Node *p_source, String p_signal_name, Node *p_target);
165 Node *get_source() const;
166 ConnectionData get_source_connection_data() const;
167 StringName get_signal_name() const;
168 PackedStringArray get_signal_args() const;
169 NodePath get_dst_path() const;
170 void set_dst_node(Node *p_node);
171 StringName get_dst_method_name() const;
172 void set_dst_method(const StringName &p_method);
173 int get_unbinds() const;
174 Vector<Variant> get_binds() const;
175 String get_signature(const MethodInfo &p_method, PackedStringArray *r_arg_names = nullptr);
176
177 bool get_deferred() const;
178 bool get_one_shot() const;
179 bool is_editing() const;
180
181 void init(const ConnectionData &p_cd, const PackedStringArray &p_signal_args, bool p_edit = false);
182
183 void popup_dialog(const String p_for_signal);
184 ConnectDialog();
185 ~ConnectDialog();
186};
187
188//////////////////////////////////////////
189
190// Custom Tree needed to use a RichTextLabel as tooltip control
191// when display signal documentation.
192class ConnectionsDockTree : public Tree {
193 virtual Control *make_custom_tooltip(const String &p_text) const;
194};
195
196class ConnectionsDock : public VBoxContainer {
197 GDCLASS(ConnectionsDock, VBoxContainer);
198
199 enum TreeItemType {
200 TREE_ITEM_TYPE_ROOT,
201 TREE_ITEM_TYPE_CLASS,
202 TREE_ITEM_TYPE_SIGNAL,
203 TREE_ITEM_TYPE_CONNECTION,
204 };
205
206 // Right-click context menu options.
207 enum ClassMenuOption {
208 CLASS_MENU_OPEN_DOCS,
209 };
210 enum SignalMenuOption {
211 SIGNAL_MENU_CONNECT,
212 SIGNAL_MENU_DISCONNECT_ALL,
213 SIGNAL_MENU_COPY_NAME,
214 SIGNAL_MENU_OPEN_DOCS,
215 };
216 enum SlotMenuOption {
217 SLOT_MENU_EDIT,
218 SLOT_MENU_GO_TO_METHOD,
219 SLOT_MENU_DISCONNECT,
220 };
221
222 Node *selected_node = nullptr;
223 ConnectionsDockTree *tree = nullptr;
224
225 ConfirmationDialog *disconnect_all_dialog = nullptr;
226 ConnectDialog *connect_dialog = nullptr;
227 Button *connect_button = nullptr;
228 PopupMenu *class_menu = nullptr;
229 String class_menu_doc_class_name;
230 PopupMenu *signal_menu = nullptr;
231 PopupMenu *slot_menu = nullptr;
232 LineEdit *search_box = nullptr;
233
234 HashMap<StringName, HashMap<StringName, String>> descr_cache;
235
236 void _filter_changed(const String &p_text);
237
238 void _make_or_edit_connection();
239 void _connect(const ConnectDialog::ConnectionData &p_cd);
240 void _disconnect(const ConnectDialog::ConnectionData &p_cd);
241 void _disconnect_all();
242
243 void _tree_item_selected();
244 void _tree_item_activated();
245 TreeItemType _get_item_type(const TreeItem &p_item) const;
246 bool _is_connection_inherited(Connection &p_connection);
247
248 void _open_connection_dialog(TreeItem &p_item);
249 void _open_edit_connection_dialog(TreeItem &p_item);
250 void _go_to_method(TreeItem &p_item);
251
252 void _handle_class_menu_option(int p_option);
253 void _class_menu_about_to_popup();
254 void _handle_signal_menu_option(int p_option);
255 void _signal_menu_about_to_popup();
256 void _handle_slot_menu_option(int p_option);
257 void _slot_menu_about_to_popup();
258 void _rmb_pressed(const Ref<InputEvent> &p_event);
259 void _close();
260
261protected:
262 void _connect_pressed();
263 void _notification(int p_what);
264 static void _bind_methods();
265
266public:
267 void set_node(Node *p_node);
268 void update_tree();
269
270 ConnectionsDock();
271 ~ConnectionsDock();
272};
273
274#endif // CONNECTIONS_DIALOG_H
275