1 | /**************************************************************************/ |
2 | /* editor_data.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 EDITOR_DATA_H |
32 | #define EDITOR_DATA_H |
33 | |
34 | #include "core/templates/list.h" |
35 | #include "scene/resources/texture.h" |
36 | |
37 | class ConfigFile; |
38 | class EditorPlugin; |
39 | class EditorUndoRedoManager; |
40 | |
41 | /** |
42 | * Stores the history of objects which have been selected for editing in the Editor & the Inspector. |
43 | * |
44 | * Used in the editor to set & access the currently edited object, as well as the history of objects which have been edited. |
45 | */ |
46 | class EditorSelectionHistory { |
47 | // Stores the object & property (if relevant). |
48 | struct _Object { |
49 | Ref<RefCounted> ref; |
50 | ObjectID object; |
51 | String property; |
52 | bool inspector_only = false; |
53 | }; |
54 | |
55 | // Represents the selection of an object for editing. |
56 | struct HistoryElement { |
57 | // The sub-resources of the parent object (first in the path) that have been edited. |
58 | // For example, Node2D -> nested resource -> nested resource, if edited each individually in their own inspector. |
59 | Vector<_Object> path; |
60 | // The current point in the path. This is always equal to the last item in the path - it is never decremented. |
61 | int level = 0; |
62 | }; |
63 | friend class EditorData; |
64 | |
65 | Vector<HistoryElement> history; |
66 | int current_elem_idx; // The current history element being edited. |
67 | |
68 | public: |
69 | void cleanup_history(); |
70 | |
71 | bool is_at_beginning() const; |
72 | bool is_at_end() const; |
73 | |
74 | // Adds an object to the selection history. A property name can be passed if the target is a subresource of the given object. |
75 | // If the object should not change the main screen plugin, it can be set as inspector only. |
76 | void add_object(ObjectID p_object, const String &p_property = String(), bool p_inspector_only = false); |
77 | |
78 | int get_history_len(); |
79 | int get_history_pos(); |
80 | |
81 | // Gets an object from the history. The most recent object would be the object with p_obj = get_history_len() - 1. |
82 | ObjectID get_history_obj(int p_obj) const; |
83 | |
84 | bool next(); |
85 | bool previous(); |
86 | ObjectID get_current(); |
87 | bool is_current_inspector_only() const; |
88 | |
89 | // Gets the size of the path of the current history item. |
90 | int get_path_size() const; |
91 | // Gets the object of the current history item, if valid. |
92 | ObjectID get_path_object(int p_index) const; |
93 | // Gets the property of the current history item. |
94 | String get_path_property(int p_index) const; |
95 | |
96 | void clear(); |
97 | |
98 | EditorSelectionHistory(); |
99 | }; |
100 | |
101 | class EditorSelection; |
102 | |
103 | class EditorData { |
104 | public: |
105 | struct CustomType { |
106 | String name; |
107 | Ref<Script> script; |
108 | Ref<Texture2D> icon; |
109 | }; |
110 | |
111 | struct EditedScene { |
112 | Node *root = nullptr; |
113 | String path; |
114 | uint64_t file_modified_time = 0; |
115 | Dictionary editor_states; |
116 | List<Node *> selection; |
117 | Vector<EditorSelectionHistory::HistoryElement> history_stored; |
118 | int history_current = 0; |
119 | Dictionary custom_state; |
120 | NodePath live_edit_root; |
121 | int history_id = 0; |
122 | uint64_t last_checked_version = 0; |
123 | }; |
124 | |
125 | private: |
126 | Vector<EditorPlugin *> editor_plugins; |
127 | HashMap<StringName, EditorPlugin *> extension_editor_plugins; |
128 | |
129 | struct PropertyData { |
130 | String name; |
131 | Variant value; |
132 | }; |
133 | HashMap<String, Vector<CustomType>> custom_types; |
134 | |
135 | List<PropertyData> clipboard; |
136 | EditorUndoRedoManager *undo_redo_manager; |
137 | Vector<Callable> undo_redo_callbacks; |
138 | HashMap<StringName, Callable> move_element_functions; |
139 | |
140 | Vector<EditedScene> edited_scene; |
141 | int current_edited_scene = -1; |
142 | int last_created_scene = 1; |
143 | |
144 | bool _find_updated_instances(Node *p_root, Node *p_node, HashSet<String> &checked_paths); |
145 | |
146 | HashMap<StringName, String> _script_class_icon_paths; |
147 | HashMap<String, StringName> _script_class_file_to_path; |
148 | HashMap<Ref<Script>, Ref<Texture>> _script_icon_cache; |
149 | |
150 | Ref<Texture2D> _load_script_icon(const String &p_path) const; |
151 | |
152 | public: |
153 | EditorPlugin *get_handling_main_editor(Object *p_object); |
154 | Vector<EditorPlugin *> get_handling_sub_editors(Object *p_object); |
155 | EditorPlugin *get_editor_by_name(String p_name); |
156 | |
157 | void copy_object_params(Object *p_object); |
158 | void paste_object_params(Object *p_object); |
159 | |
160 | Dictionary get_editor_plugin_states() const; |
161 | Dictionary get_scene_editor_states(int p_idx) const; |
162 | void set_editor_plugin_states(const Dictionary &p_states); |
163 | void get_editor_breakpoints(List<String> *p_breakpoints); |
164 | void clear_editor_states(); |
165 | void save_editor_external_data(); |
166 | void apply_changes_in_editors(); |
167 | |
168 | void add_editor_plugin(EditorPlugin *p_plugin); |
169 | void remove_editor_plugin(EditorPlugin *p_plugin); |
170 | |
171 | int get_editor_plugin_count() const; |
172 | EditorPlugin *get_editor_plugin(int p_idx); |
173 | |
174 | void add_extension_editor_plugin(const StringName &p_class_name, EditorPlugin *p_plugin); |
175 | void remove_extension_editor_plugin(const StringName &p_class_name); |
176 | bool has_extension_editor_plugin(const StringName &p_class_name); |
177 | EditorPlugin *get_extension_editor_plugin(const StringName &p_class_name); |
178 | |
179 | void add_undo_redo_inspector_hook_callback(Callable p_callable); // Callbacks should have this signature: void (Object* undo_redo, Object *modified_object, String property, Variant new_value) |
180 | void remove_undo_redo_inspector_hook_callback(Callable p_callable); |
181 | const Vector<Callable> get_undo_redo_inspector_hook_callback(); |
182 | |
183 | void add_move_array_element_function(const StringName &p_class, Callable p_callable); // Function should have this signature: void (Object* undo_redo, Object *modified_object, String array_prefix, int element_index, int new_position) |
184 | void remove_move_array_element_function(const StringName &p_class); |
185 | Callable get_move_array_element_function(const StringName &p_class) const; |
186 | |
187 | void save_editor_global_states(); |
188 | |
189 | void add_custom_type(const String &p_type, const String &p_inherits, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon); |
190 | Variant instantiate_custom_type(const String &p_type, const String &p_inherits); |
191 | void remove_custom_type(const String &p_type); |
192 | const HashMap<String, Vector<CustomType>> &get_custom_types() const { return custom_types; } |
193 | const CustomType *get_custom_type_by_name(const String &p_name) const; |
194 | const CustomType *get_custom_type_by_path(const String &p_path) const; |
195 | bool is_type_recognized(const String &p_type) const; |
196 | |
197 | void instantiate_object_properties(Object *p_object); |
198 | |
199 | int add_edited_scene(int p_at_pos); |
200 | void move_edited_scene_index(int p_idx, int p_to_idx); |
201 | void remove_scene(int p_idx); |
202 | void set_edited_scene(int p_idx); |
203 | void set_edited_scene_root(Node *p_root); |
204 | int get_edited_scene() const; |
205 | int get_edited_scene_from_path(const String &p_path) const; |
206 | Node *get_edited_scene_root(int p_idx = -1); |
207 | int get_edited_scene_count() const; |
208 | Vector<EditedScene> get_edited_scenes() const; |
209 | |
210 | String get_scene_title(int p_idx, bool p_always_strip_extension = false) const; |
211 | String get_scene_path(int p_idx) const; |
212 | String get_scene_type(int p_idx) const; |
213 | void set_scene_path(int p_idx, const String &p_path); |
214 | Ref<Script> get_scene_root_script(int p_idx) const; |
215 | void set_scene_modified_time(int p_idx, uint64_t p_time); |
216 | uint64_t get_scene_modified_time(int p_idx) const; |
217 | void clear_edited_scenes(); |
218 | void set_edited_scene_live_edit_root(const NodePath &p_root); |
219 | NodePath get_edited_scene_live_edit_root(); |
220 | bool check_and_update_scene(int p_idx); |
221 | void move_edited_scene_to_index(int p_idx); |
222 | |
223 | bool call_build(); |
224 | |
225 | void set_scene_as_saved(int p_idx); |
226 | bool is_scene_changed(int p_idx); |
227 | |
228 | int get_scene_history_id_from_path(const String &p_path) const; |
229 | int get_current_edited_scene_history_id() const; |
230 | int get_scene_history_id(int p_idx) const; |
231 | |
232 | void set_plugin_window_layout(Ref<ConfigFile> p_layout); |
233 | void get_plugin_window_layout(Ref<ConfigFile> p_layout); |
234 | |
235 | void save_edited_scene_state(EditorSelection *p_selection, EditorSelectionHistory *p_history, const Dictionary &p_custom); |
236 | Dictionary restore_edited_scene_state(EditorSelection *p_selection, EditorSelectionHistory *p_history); |
237 | void notify_edited_scene_changed(); |
238 | void notify_resource_saved(const Ref<Resource> &p_resource); |
239 | |
240 | bool script_class_is_parent(const String &p_class, const String &p_inherits); |
241 | StringName script_class_get_base(const String &p_class) const; |
242 | Variant script_class_instance(const String &p_class); |
243 | |
244 | Ref<Script> script_class_load_script(const String &p_class) const; |
245 | |
246 | StringName script_class_get_name(const String &p_path) const; |
247 | void script_class_set_name(const String &p_path, const StringName &p_class); |
248 | |
249 | String script_class_get_icon_path(const String &p_class) const; |
250 | void script_class_set_icon_path(const String &p_class, const String &p_icon_path); |
251 | void script_class_clear_icon_paths() { _script_class_icon_paths.clear(); } |
252 | void script_class_save_icon_paths(); |
253 | void script_class_load_icon_paths(); |
254 | |
255 | Ref<Texture2D> extension_class_get_icon(const String &p_class) const; |
256 | |
257 | Ref<Texture2D> get_script_icon(const Ref<Script> &p_script); |
258 | void clear_script_icon_cache(); |
259 | |
260 | EditorData(); |
261 | ~EditorData(); |
262 | }; |
263 | |
264 | /** |
265 | * Stores and provides access to the nodes currently selected in the editor. |
266 | * |
267 | * This provides a central location for storing "selected" nodes, as a selection can be triggered from multiple places, |
268 | * such as the SceneTreeDock or a main screen editor plugin (e.g. CanvasItemEditor). |
269 | */ |
270 | class EditorSelection : public Object { |
271 | GDCLASS(EditorSelection, Object); |
272 | |
273 | // Contains the selected nodes and corresponding metadata. |
274 | // Metadata objects come from calling _get_editor_data on the editor_plugins, passing the selected node. |
275 | HashMap<Node *, Object *> selection; |
276 | |
277 | // Tracks whether the selection change signal has been emitted. |
278 | // Prevents multiple signals being called in one frame. |
279 | bool emitted = false; |
280 | |
281 | bool changed = false; |
282 | bool node_list_changed = false; |
283 | |
284 | void _node_removed(Node *p_node); |
285 | |
286 | // Editor plugins which are related to selection. |
287 | List<Object *> editor_plugins; |
288 | List<Node *> selected_node_list; |
289 | |
290 | void _update_node_list(); |
291 | TypedArray<Node> _get_transformable_selected_nodes(); |
292 | void _emit_change(); |
293 | |
294 | protected: |
295 | static void _bind_methods(); |
296 | |
297 | public: |
298 | void add_node(Node *p_node); |
299 | void remove_node(Node *p_node); |
300 | bool is_selected(Node *p_node) const; |
301 | |
302 | template <class T> |
303 | T *get_node_editor_data(Node *p_node) { |
304 | if (!selection.has(p_node)) { |
305 | return nullptr; |
306 | } |
307 | return Object::cast_to<T>(selection[p_node]); |
308 | } |
309 | |
310 | // Adds an editor plugin which can provide metadata for selected nodes. |
311 | void add_editor_plugin(Object *p_object); |
312 | |
313 | void update(); |
314 | void clear(); |
315 | |
316 | // Returns all the selected nodes. |
317 | TypedArray<Node> get_selected_nodes(); |
318 | // Returns only the top level selected nodes. |
319 | // That is, if the selection includes some node and a child of that node, only the parent is returned. |
320 | List<Node *> &get_selected_node_list(); |
321 | // Returns all the selected nodes (list version of "get_selected_nodes"). |
322 | List<Node *> get_full_selected_node_list(); |
323 | // Returns the map of selected objects and their metadata. |
324 | HashMap<Node *, Object *> &get_selection() { return selection; } |
325 | |
326 | EditorSelection(); |
327 | ~EditorSelection(); |
328 | }; |
329 | |
330 | #endif // EDITOR_DATA_H |
331 | |