1 | /**************************************************************************/ |
2 | /* tile_set_atlas_source_editor.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 TILE_SET_ATLAS_SOURCE_EDITOR_H |
32 | #define TILE_SET_ATLAS_SOURCE_EDITOR_H |
33 | |
34 | #include "tile_atlas_view.h" |
35 | #include "tile_data_editors.h" |
36 | |
37 | #include "scene/gui/split_container.h" |
38 | #include "scene/resources/tile_set.h" |
39 | |
40 | class ; |
41 | class TileSet; |
42 | class Tree; |
43 | class VSeparator; |
44 | |
45 | class TileSetAtlasSourceEditor : public HSplitContainer { |
46 | GDCLASS(TileSetAtlasSourceEditor, HSplitContainer); |
47 | |
48 | public: |
49 | // A class to store which tiles are selected. |
50 | struct TileSelection { |
51 | Vector2i tile = TileSetSource::INVALID_ATLAS_COORDS; |
52 | int alternative = TileSetSource::INVALID_TILE_ALTERNATIVE; |
53 | |
54 | bool operator<(const TileSelection &p_other) const { |
55 | if (tile == p_other.tile) { |
56 | return alternative < p_other.alternative; |
57 | } else { |
58 | return tile < p_other.tile; |
59 | } |
60 | } |
61 | }; |
62 | |
63 | // -- Proxy object for an atlas source, needed by the inspector -- |
64 | class TileSetAtlasSourceProxyObject : public Object { |
65 | GDCLASS(TileSetAtlasSourceProxyObject, Object); |
66 | |
67 | private: |
68 | Ref<TileSet> tile_set; |
69 | Ref<TileSetAtlasSource> tile_set_atlas_source; |
70 | int source_id = TileSet::INVALID_SOURCE; |
71 | |
72 | protected: |
73 | bool _set(const StringName &p_name, const Variant &p_value); |
74 | bool _get(const StringName &p_name, Variant &r_ret) const; |
75 | void _get_property_list(List<PropertyInfo> *p_list) const; |
76 | static void _bind_methods(); |
77 | |
78 | public: |
79 | void set_id(int p_id); |
80 | int get_id() const; |
81 | |
82 | void edit(Ref<TileSet> p_tile_set, Ref<TileSetAtlasSource> p_tile_set_atlas_source, int p_source_id); |
83 | Ref<TileSetAtlasSource> get_edited() { return tile_set_atlas_source; }; |
84 | }; |
85 | |
86 | // -- Proxy object for a tile, needed by the inspector -- |
87 | class AtlasTileProxyObject : public Object { |
88 | GDCLASS(AtlasTileProxyObject, Object); |
89 | |
90 | private: |
91 | TileSetAtlasSourceEditor *tiles_set_atlas_source_editor = nullptr; |
92 | |
93 | Ref<TileSetAtlasSource> tile_set_atlas_source; |
94 | RBSet<TileSelection> tiles = RBSet<TileSelection>(); |
95 | |
96 | protected: |
97 | bool _set(const StringName &p_name, const Variant &p_value); |
98 | bool _get(const StringName &p_name, Variant &r_ret) const; |
99 | void _get_property_list(List<PropertyInfo> *p_list) const; |
100 | |
101 | static void _bind_methods(); |
102 | |
103 | public: |
104 | Ref<TileSetAtlasSource> get_edited_tile_set_atlas_source() const { return tile_set_atlas_source; }; |
105 | RBSet<TileSelection> get_edited_tiles() const { return tiles; }; |
106 | |
107 | // Update the proxyed object. |
108 | void edit(Ref<TileSetAtlasSource> p_tile_set_atlas_source, RBSet<TileSelection> p_tiles = RBSet<TileSelection>()); |
109 | |
110 | AtlasTileProxyObject(TileSetAtlasSourceEditor *p_tiles_set_atlas_source_editor) { |
111 | tiles_set_atlas_source_editor = p_tiles_set_atlas_source_editor; |
112 | } |
113 | }; |
114 | |
115 | class TileAtlasControl : public Control { |
116 | TileSetAtlasSourceEditor *editor = nullptr; |
117 | |
118 | public: |
119 | virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override; |
120 | TileAtlasControl(TileSetAtlasSourceEditor *p_editor) { editor = p_editor; } |
121 | }; |
122 | friend class TileAtlasControl; |
123 | |
124 | private: |
125 | bool read_only = false; |
126 | |
127 | Ref<TileSet> tile_set; |
128 | TileSetAtlasSource *tile_set_atlas_source = nullptr; |
129 | int tile_set_atlas_source_id = TileSet::INVALID_SOURCE; |
130 | Ref<Texture2D> atlas_source_texture; |
131 | |
132 | bool tile_set_changed_needs_update = false; |
133 | |
134 | // -- Properties painting -- |
135 | ScrollContainer *tile_data_editors_scroll = nullptr; |
136 | VBoxContainer *tile_data_painting_editor_container = nullptr; |
137 | Label *tile_data_editors_label = nullptr; |
138 | Button *tile_data_editor_dropdown_button = nullptr; |
139 | Popup * = nullptr; |
140 | Tree *tile_data_editors_tree = nullptr; |
141 | void _tile_data_editor_dropdown_button_draw(); |
142 | void _tile_data_editor_dropdown_button_pressed(); |
143 | |
144 | // -- Tile data editors -- |
145 | String current_property; |
146 | Control *current_tile_data_editor_toolbar = nullptr; |
147 | HashMap<String, TileDataEditor *> tile_data_editors; |
148 | TileDataEditor *current_tile_data_editor = nullptr; |
149 | void _tile_data_editors_tree_selected(); |
150 | |
151 | // -- Inspector -- |
152 | AtlasTileProxyObject *tile_proxy_object = nullptr; |
153 | EditorInspector *tile_inspector = nullptr; |
154 | Label *tile_inspector_no_tile_selected_label = nullptr; |
155 | String selected_property; |
156 | void _inspector_property_selected(String p_property); |
157 | |
158 | TileSetAtlasSourceProxyObject *atlas_source_proxy_object = nullptr; |
159 | EditorInspector *atlas_source_inspector = nullptr; |
160 | |
161 | // -- Atlas view -- |
162 | TileAtlasView *tile_atlas_view = nullptr; |
163 | HBoxContainer *tile_create_help = nullptr; |
164 | |
165 | // Dragging |
166 | enum DragType { |
167 | DRAG_TYPE_NONE = 0, |
168 | DRAG_TYPE_CREATE_TILES, |
169 | DRAG_TYPE_CREATE_TILES_USING_RECT, |
170 | DRAG_TYPE_CREATE_BIG_TILE, |
171 | DRAG_TYPE_REMOVE_TILES, |
172 | DRAG_TYPE_REMOVE_TILES_USING_RECT, |
173 | |
174 | DRAG_TYPE_MOVE_TILE, |
175 | |
176 | DRAG_TYPE_RECT_SELECT, |
177 | |
178 | , |
179 | |
180 | // Warning: keep in this order. |
181 | DRAG_TYPE_RESIZE_TOP_LEFT, |
182 | DRAG_TYPE_RESIZE_TOP, |
183 | DRAG_TYPE_RESIZE_TOP_RIGHT, |
184 | DRAG_TYPE_RESIZE_RIGHT, |
185 | DRAG_TYPE_RESIZE_BOTTOM_RIGHT, |
186 | DRAG_TYPE_RESIZE_BOTTOM, |
187 | DRAG_TYPE_RESIZE_BOTTOM_LEFT, |
188 | DRAG_TYPE_RESIZE_LEFT, |
189 | }; |
190 | DragType drag_type = DRAG_TYPE_NONE; |
191 | Vector2i drag_start_mouse_pos; |
192 | Vector2i drag_last_mouse_pos; |
193 | Vector2i drag_current_tile; |
194 | |
195 | Rect2i drag_start_tile_shape; |
196 | RBSet<Vector2i> drag_modified_tiles; |
197 | void _end_dragging(); |
198 | |
199 | HashMap<Vector2i, List<const PropertyInfo *>> _group_properties_per_tiles(const List<PropertyInfo> &r_list, const TileSetAtlasSource *p_atlas); |
200 | |
201 | // Popup functions. |
202 | enum { |
203 | TILE_CREATE, |
204 | TILE_CREATE_ALTERNATIVE, |
205 | TILE_DELETE, |
206 | |
207 | ADVANCED_AUTO_CREATE_TILES, |
208 | ADVANCED_AUTO_REMOVE_TILES, |
209 | ADVANCED_CLEANUP_TILES, |
210 | }; |
211 | Vector2i ; |
212 | int = TileSetSource::INVALID_TILE_ALTERNATIVE; |
213 | void (int p_option); |
214 | |
215 | // Tool buttons. |
216 | Ref<ButtonGroup> tools_button_group; |
217 | Button *tool_setup_atlas_source_button = nullptr; |
218 | Button *tool_select_button = nullptr; |
219 | Button *tool_paint_button = nullptr; |
220 | Label *tool_tile_id_label = nullptr; |
221 | |
222 | // Tool settings. |
223 | HBoxContainer *tool_settings = nullptr; |
224 | HBoxContainer *tool_settings_tile_data_toolbar_container = nullptr; |
225 | Button *tools_settings_erase_button = nullptr; |
226 | MenuButton * = nullptr; |
227 | TextureRect *outside_tiles_warning = nullptr; |
228 | |
229 | // Selection. |
230 | RBSet<TileSelection> selection; |
231 | |
232 | void _set_selection_from_array(Array p_selection); |
233 | Array _get_selection_as_array(); |
234 | |
235 | // A control on the tile atlas to draw and handle input events. |
236 | Vector2i hovered_base_tile_coords = TileSetSource::INVALID_ATLAS_COORDS; |
237 | |
238 | PopupMenu * = nullptr; |
239 | PopupMenu * = nullptr; |
240 | Ref<Texture2D> resize_handle; |
241 | Ref<Texture2D> resize_handle_disabled; |
242 | Control *tile_atlas_control = nullptr; |
243 | Control *tile_atlas_control_unscaled = nullptr; |
244 | void _tile_atlas_control_draw(); |
245 | void _tile_atlas_control_unscaled_draw(); |
246 | void _tile_atlas_control_mouse_exited(); |
247 | void _tile_atlas_control_gui_input(const Ref<InputEvent> &p_event); |
248 | void _tile_atlas_view_transform_changed(); |
249 | |
250 | // A control over the alternative tiles. |
251 | Vector3i hovered_alternative_tile_coords = Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE); |
252 | |
253 | PopupMenu * = nullptr; |
254 | Control *alternative_tiles_control = nullptr; |
255 | Control *alternative_tiles_control_unscaled = nullptr; |
256 | void _tile_alternatives_control_draw(); |
257 | void _tile_alternatives_control_unscaled_draw(); |
258 | void _tile_alternatives_control_mouse_exited(); |
259 | void _tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event); |
260 | |
261 | // -- Update functions -- |
262 | void _update_tile_id_label(); |
263 | void _update_source_inspector(); |
264 | void _update_fix_selected_and_hovered_tiles(); |
265 | void _update_atlas_source_inspector(); |
266 | void _update_tile_inspector(); |
267 | void _update_tile_data_editors(); |
268 | void _update_current_tile_data_editor(); |
269 | void _update_manage_tile_properties_button(); |
270 | void _update_atlas_view(); |
271 | void _update_toolbar(); |
272 | |
273 | // -- Misc -- |
274 | void _auto_create_tiles(); |
275 | void _auto_remove_tiles(); |
276 | void _cancel_auto_create_tiles(); |
277 | AcceptDialog *confirm_auto_create_tiles = nullptr; |
278 | Vector<Ref<TileSetAtlasSource>> atlases_to_auto_create_tiles; |
279 | Vector2i _get_drag_offset_tile_coords(const Vector2i &p_offset) const; |
280 | |
281 | void _update_source_texture(); |
282 | void _check_outside_tiles(); |
283 | void _cleanup_outside_tiles(); |
284 | |
285 | void _tile_set_changed(); |
286 | void _tile_proxy_object_changed(String p_what); |
287 | void _atlas_source_proxy_object_changed(String p_what); |
288 | |
289 | void _undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value); |
290 | |
291 | protected: |
292 | void _notification(int p_what); |
293 | static void _bind_methods(); |
294 | |
295 | // -- input events -- |
296 | virtual void shortcut_input(const Ref<InputEvent> &p_event) override; |
297 | |
298 | public: |
299 | void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_source, int p_source_id); |
300 | void init_new_atlases(const Vector<Ref<TileSetAtlasSource>> &p_atlases); |
301 | |
302 | TileSetAtlasSourceEditor(); |
303 | ~TileSetAtlasSourceEditor(); |
304 | }; |
305 | |
306 | class EditorPropertyTilePolygon : public EditorProperty { |
307 | GDCLASS(EditorPropertyTilePolygon, EditorProperty); |
308 | |
309 | StringName count_property; |
310 | String element_pattern; |
311 | String base_type; |
312 | |
313 | void _add_focusable_children(Node *p_node); |
314 | |
315 | GenericTilePolygonEditor *generic_tile_polygon_editor = nullptr; |
316 | void _polygons_changed(); |
317 | |
318 | public: |
319 | virtual void update_property() override; |
320 | void setup_single_mode(const StringName &p_property, const String &p_base_type); |
321 | void setup_multiple_mode(const StringName &p_property, const StringName &p_count_property, const String &p_element_pattern, const String &p_base_type); |
322 | EditorPropertyTilePolygon(); |
323 | }; |
324 | |
325 | class EditorInspectorPluginTileData : public EditorInspectorPlugin { |
326 | GDCLASS(EditorInspectorPluginTileData, EditorInspectorPlugin); |
327 | |
328 | void _occlusion_polygon_set_callback(); |
329 | void _polygons_changed(Object *p_generic_tile_polygon_editor, Object *p_object, const String &p_path); |
330 | |
331 | public: |
332 | virtual bool can_handle(Object *p_object) override; |
333 | virtual bool parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const BitField<PropertyUsageFlags> p_usage, const bool p_wide = false) override; |
334 | }; |
335 | |
336 | #endif // TILE_SET_ATLAS_SOURCE_EDITOR_H |
337 | |