tile_set_atlas_source_editor.cpp 124 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749
  1. /*************************************************************************/
  2. /* tile_set_atlas_source_editor.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
  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. #include "tile_set_atlas_source_editor.h"
  31. #include "tiles_editor_plugin.h"
  32. #include "editor/editor_inspector.h"
  33. #include "editor/editor_scale.h"
  34. #include "editor/progress_dialog.h"
  35. #include "editor/editor_node.h"
  36. #include "scene/gui/box_container.h"
  37. #include "scene/gui/button.h"
  38. #include "scene/gui/control.h"
  39. #include "scene/gui/item_list.h"
  40. #include "scene/gui/separator.h"
  41. #include "scene/gui/split_container.h"
  42. #include "scene/gui/tab_container.h"
  43. #include "core/core_string_names.h"
  44. #include "core/math/geometry_2d.h"
  45. #include "core/os/keyboard.h"
  46. void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::set_id(int p_id) {
  47. ERR_FAIL_COND(p_id < 0);
  48. if (source_id == p_id) {
  49. return;
  50. }
  51. ERR_FAIL_COND_MSG(tile_set->has_source(p_id), vformat("Cannot change TileSet Atlas Source ID. Another source exists with id %d.", p_id));
  52. int previous_source = source_id;
  53. source_id = p_id; // source_id must be updated before, because it's used by the source list update.
  54. tile_set->set_source_id(previous_source, p_id);
  55. emit_signal(SNAME("changed"), "id");
  56. }
  57. int TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::get_id() {
  58. return source_id;
  59. }
  60. bool TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_set(const StringName &p_name, const Variant &p_value) {
  61. String name = p_name;
  62. if (name == "name") {
  63. // Use the resource_name property to store the source's name.
  64. name = "resource_name";
  65. }
  66. bool valid = false;
  67. tile_set_atlas_source->set(name, p_value, &valid);
  68. if (valid) {
  69. emit_signal(SNAME("changed"), String(name).utf8().get_data());
  70. }
  71. return valid;
  72. }
  73. bool TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get(const StringName &p_name, Variant &r_ret) const {
  74. if (!tile_set_atlas_source) {
  75. return false;
  76. }
  77. String name = p_name;
  78. if (name == "name") {
  79. // Use the resource_name property to store the source's name.
  80. name = "resource_name";
  81. }
  82. bool valid = false;
  83. r_ret = tile_set_atlas_source->get(name, &valid);
  84. return valid;
  85. }
  86. void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list(List<PropertyInfo> *p_list) const {
  87. p_list->push_back(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, ""));
  88. p_list->push_back(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
  89. p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "suffix:px"));
  90. p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "suffix:px"));
  91. p_list->push_back(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "suffix:px"));
  92. p_list->push_back(PropertyInfo(Variant::BOOL, "use_texture_padding", PROPERTY_HINT_NONE, ""));
  93. }
  94. void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_bind_methods() {
  95. // -- Shape and layout --
  96. ClassDB::bind_method(D_METHOD("set_id", "id"), &TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::set_id);
  97. ClassDB::bind_method(D_METHOD("get_id"), &TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::get_id);
  98. ADD_PROPERTY(PropertyInfo(Variant::INT, "id", PROPERTY_HINT_RANGE, "0," + itos(INT_MAX) + ",1"), "set_id", "get_id");
  99. ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what")));
  100. }
  101. void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id) {
  102. ERR_FAIL_COND(!p_tile_set.is_valid());
  103. ERR_FAIL_COND(!p_tile_set_atlas_source);
  104. ERR_FAIL_COND(p_source_id < 0);
  105. ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
  106. if (p_tile_set == tile_set && p_tile_set_atlas_source == tile_set_atlas_source && p_source_id == source_id) {
  107. return;
  108. }
  109. // Disconnect to changes.
  110. if (tile_set_atlas_source) {
  111. tile_set_atlas_source->disconnect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
  112. }
  113. tile_set = p_tile_set;
  114. tile_set_atlas_source = p_tile_set_atlas_source;
  115. source_id = p_source_id;
  116. // Connect to changes.
  117. if (tile_set_atlas_source) {
  118. if (!tile_set_atlas_source->is_connected(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed))) {
  119. tile_set_atlas_source->connect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
  120. }
  121. }
  122. notify_property_list_changed();
  123. }
  124. // -- Proxy object used by the tile inspector --
  125. bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_name, const Variant &p_value) {
  126. if (!tile_set_atlas_source) {
  127. return false;
  128. }
  129. // ID and size related properties.
  130. if (tiles.size() == 1) {
  131. const Vector2i &coords = tiles.front()->get().tile;
  132. const int &alternative = tiles.front()->get().alternative;
  133. if (alternative == 0) {
  134. Vector<String> components = String(p_name).split("/", true, 2);
  135. if (p_name == "atlas_coords") {
  136. Vector2i as_vector2i = Vector2i(p_value);
  137. bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(as_vector2i, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
  138. ERR_FAIL_COND_V(!has_room_for_tile, false);
  139. if (tiles_set_atlas_source_editor->selection.front()->get().tile == coords) {
  140. tiles_set_atlas_source_editor->selection.clear();
  141. tiles_set_atlas_source_editor->selection.insert({ as_vector2i, 0 });
  142. tiles_set_atlas_source_editor->_update_tile_id_label();
  143. }
  144. tile_set_atlas_source->move_tile_in_atlas(coords, as_vector2i);
  145. tiles.clear();
  146. tiles.insert({ as_vector2i, 0 });
  147. emit_signal(SNAME("changed"), "atlas_coords");
  148. return true;
  149. } else if (p_name == "size_in_atlas") {
  150. Vector2i as_vector2i = Vector2i(p_value);
  151. bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(coords, as_vector2i, tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
  152. ERR_FAIL_COND_V_EDMSG(!has_room_for_tile, false, "Invalid size or not enough room in the atlas for the tile.");
  153. tile_set_atlas_source->move_tile_in_atlas(coords, TileSetSource::INVALID_ATLAS_COORDS, as_vector2i);
  154. emit_signal(SNAME("changed"), "size_in_atlas");
  155. return true;
  156. }
  157. } else if (alternative > 0) {
  158. if (p_name == "alternative_id") {
  159. int as_int = int(p_value);
  160. ERR_FAIL_COND_V(as_int < 0, false);
  161. ERR_FAIL_COND_V_MSG(tile_set_atlas_source->has_alternative_tile(coords, as_int), false, vformat("Cannot change alternative tile ID. Another alternative exists with id %d for tile at coords %s.", as_int, coords));
  162. if (tiles_set_atlas_source_editor->selection.front()->get().alternative == alternative) {
  163. tiles_set_atlas_source_editor->selection.clear();
  164. tiles_set_atlas_source_editor->selection.insert({ coords, as_int });
  165. }
  166. int previous_alternative_tile = alternative;
  167. tiles.clear();
  168. tiles.insert({ coords, as_int }); // tiles must be updated before.
  169. tile_set_atlas_source->set_alternative_tile_id(coords, previous_alternative_tile, as_int);
  170. emit_signal(SNAME("changed"), "alternative_id");
  171. return true;
  172. }
  173. }
  174. }
  175. // Animation.
  176. // Check if all tiles have an alternative_id of 0.
  177. bool all_alternatve_id_zero = true;
  178. for (TileSelection tile : tiles) {
  179. if (tile.alternative != 0) {
  180. all_alternatve_id_zero = false;
  181. break;
  182. }
  183. }
  184. if (all_alternatve_id_zero) {
  185. Vector<String> components = String(p_name).split("/", true, 2);
  186. if (p_name == "animation_columns") {
  187. for (TileSelection tile : tiles) {
  188. bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), p_value, tile_set_atlas_source->get_tile_animation_separation(tile.tile), tile_set_atlas_source->get_tile_animation_frames_count(tile.tile), tile.tile);
  189. if (!has_room_for_tile) {
  190. ERR_PRINT("No room for tile");
  191. } else {
  192. tile_set_atlas_source->set_tile_animation_columns(tile.tile, p_value);
  193. }
  194. }
  195. emit_signal(SNAME("changed"), "animation_columns");
  196. return true;
  197. } else if (p_name == "animation_separation") {
  198. for (TileSelection tile : tiles) {
  199. bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile), tile.tile);
  200. if (!has_room_for_tile) {
  201. ERR_PRINT("No room for tile");
  202. } else {
  203. tile_set_atlas_source->set_tile_animation_separation(tile.tile, p_value);
  204. }
  205. }
  206. emit_signal(SNAME("changed"), "animation_separation");
  207. return true;
  208. } else if (p_name == "animation_speed") {
  209. for (TileSelection tile : tiles) {
  210. tile_set_atlas_source->set_tile_animation_speed(tile.tile, p_value);
  211. }
  212. emit_signal(SNAME("changed"), "animation_speed");
  213. return true;
  214. } else if (p_name == "animation_frames_count") {
  215. for (TileSelection tile : tiles) {
  216. bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), tile_set_atlas_source->get_tile_animation_separation(tile.tile), p_value, tile.tile);
  217. if (!has_room_for_tile) {
  218. ERR_PRINT("No room for tile");
  219. } else {
  220. tile_set_atlas_source->set_tile_animation_frames_count(tile.tile, p_value);
  221. }
  222. }
  223. notify_property_list_changed();
  224. emit_signal(SNAME("changed"), "animation_separation");
  225. return true;
  226. } else if (components.size() == 2 && components[0].begins_with("animation_frame_") && components[0].trim_prefix("animation_frame_").is_valid_int()) {
  227. for (TileSelection tile : tiles) {
  228. int frame = components[0].trim_prefix("animation_frame_").to_int();
  229. if (frame < 0 || frame >= tile_set_atlas_source->get_tile_animation_frames_count(tile.tile)) {
  230. ERR_PRINT(vformat("No tile animation frame with index %d", frame));
  231. } else {
  232. if (components[1] == "duration") {
  233. tile_set_atlas_source->set_tile_animation_frame_duration(tile.tile, frame, p_value);
  234. return true;
  235. }
  236. }
  237. }
  238. }
  239. }
  240. // Other properties.
  241. bool any_valid = false;
  242. for (const TileSelection &E : tiles) {
  243. const Vector2i &coords = E.tile;
  244. const int &alternative = E.alternative;
  245. bool valid = false;
  246. TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
  247. ERR_FAIL_COND_V(!tile_data, false);
  248. tile_data->set(p_name, p_value, &valid);
  249. any_valid |= valid;
  250. }
  251. if (any_valid) {
  252. emit_signal(SNAME("changed"), String(p_name).utf8().get_data());
  253. }
  254. return any_valid;
  255. }
  256. bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_name, Variant &r_ret) const {
  257. if (!tile_set_atlas_source) {
  258. return false;
  259. }
  260. // ID and size related properties.s
  261. if (tiles.size() == 1) {
  262. const Vector2i &coords = tiles.front()->get().tile;
  263. const int &alternative = tiles.front()->get().alternative;
  264. if (alternative == 0) {
  265. Vector<String> components = String(p_name).split("/", true, 2);
  266. if (p_name == "atlas_coords") {
  267. r_ret = coords;
  268. return true;
  269. } else if (p_name == "size_in_atlas") {
  270. r_ret = tile_set_atlas_source->get_tile_size_in_atlas(coords);
  271. return true;
  272. }
  273. } else if (alternative > 0) {
  274. if (p_name == "alternative_id") {
  275. r_ret = alternative;
  276. return true;
  277. }
  278. }
  279. }
  280. // Animation.
  281. // Check if all tiles have an alternative_id of 0.
  282. bool all_alternatve_id_zero = true;
  283. for (TileSelection tile : tiles) {
  284. if (tile.alternative != 0) {
  285. all_alternatve_id_zero = false;
  286. break;
  287. }
  288. }
  289. if (all_alternatve_id_zero) {
  290. const Vector2i &coords = tiles.front()->get().tile;
  291. Vector<String> components = String(p_name).split("/", true, 2);
  292. if (p_name == "animation_columns") {
  293. r_ret = tile_set_atlas_source->get_tile_animation_columns(coords);
  294. return true;
  295. } else if (p_name == "animation_separation") {
  296. r_ret = tile_set_atlas_source->get_tile_animation_separation(coords);
  297. return true;
  298. } else if (p_name == "animation_speed") {
  299. r_ret = tile_set_atlas_source->get_tile_animation_speed(coords);
  300. return true;
  301. } else if (p_name == "animation_frames_count") {
  302. r_ret = tile_set_atlas_source->get_tile_animation_frames_count(coords);
  303. return true;
  304. } else if (components.size() == 2 && components[0].begins_with("animation_frame_") && components[0].trim_prefix("animation_frame_").is_valid_int()) {
  305. int frame = components[0].trim_prefix("animation_frame_").to_int();
  306. if (components[1] == "duration") {
  307. if (frame < 0 || frame >= tile_set_atlas_source->get_tile_animation_frames_count(coords)) {
  308. return false;
  309. }
  310. r_ret = tile_set_atlas_source->get_tile_animation_frame_duration(coords, frame);
  311. return true;
  312. }
  313. }
  314. }
  315. for (const TileSelection &E : tiles) {
  316. // Return the first tile with a property matching the name.
  317. // Note: It's a little bit annoying, but the behavior is the same the one in MultiNodeEdit.
  318. const Vector2i &coords = E.tile;
  319. const int &alternative = E.alternative;
  320. TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
  321. ERR_FAIL_COND_V(!tile_data, false);
  322. bool valid = false;
  323. r_ret = tile_data->get(p_name, &valid);
  324. if (valid) {
  325. return true;
  326. }
  327. }
  328. return false;
  329. }
  330. void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<PropertyInfo> *p_list) const {
  331. if (!tile_set_atlas_source) {
  332. return;
  333. }
  334. // ID and size related properties.
  335. if (tiles.size() == 1) {
  336. if (tiles.front()->get().alternative == 0) {
  337. p_list->push_back(PropertyInfo(Variant::VECTOR2I, "atlas_coords", PROPERTY_HINT_NONE, ""));
  338. p_list->push_back(PropertyInfo(Variant::VECTOR2I, "size_in_atlas", PROPERTY_HINT_NONE, ""));
  339. } else {
  340. p_list->push_back(PropertyInfo(Variant::INT, "alternative_id", PROPERTY_HINT_NONE, ""));
  341. }
  342. }
  343. // Animation.
  344. // Check if all tiles have an alternative_id of 0.
  345. bool all_alternatve_id_zero = true;
  346. for (TileSelection tile : tiles) {
  347. if (tile.alternative != 0) {
  348. all_alternatve_id_zero = false;
  349. break;
  350. }
  351. }
  352. if (all_alternatve_id_zero) {
  353. p_list->push_back(PropertyInfo(Variant::NIL, "Animation", PROPERTY_HINT_NONE, "animation_", PROPERTY_USAGE_GROUP));
  354. p_list->push_back(PropertyInfo(Variant::INT, "animation_columns", PROPERTY_HINT_NONE, ""));
  355. p_list->push_back(PropertyInfo(Variant::VECTOR2I, "animation_separation", PROPERTY_HINT_NONE, "suffix:px"));
  356. p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_speed", PROPERTY_HINT_NONE, ""));
  357. p_list->push_back(PropertyInfo(Variant::INT, "animation_frames_count", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, "Frames,animation_frame_"));
  358. // Not optimal, but returns value for the first tile. This is similar to what MultiNodeEdit does.
  359. if (tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile) == 1) {
  360. p_list->push_back(PropertyInfo(Variant::FLOAT, "animation_frame_0/duration", PROPERTY_HINT_NONE, "suffix:s", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY));
  361. } else {
  362. for (int i = 0; i < tile_set_atlas_source->get_tile_animation_frames_count(tiles.front()->get().tile); i++) {
  363. p_list->push_back(PropertyInfo(Variant::FLOAT, vformat("animation_frame_%d/duration", i), PROPERTY_HINT_NONE, "suffix:s"));
  364. }
  365. }
  366. }
  367. // Get the list of properties common to all tiles (similar to what's done in MultiNodeEdit).
  368. struct PropertyId {
  369. int occurence_id = 0;
  370. String property;
  371. bool operator<(const PropertyId &p_other) const {
  372. return occurence_id == p_other.occurence_id ? property < p_other.property : occurence_id < p_other.occurence_id;
  373. }
  374. };
  375. struct PLData {
  376. int uses = 0;
  377. PropertyInfo property_info;
  378. };
  379. RBMap<PropertyId, PLData> usage;
  380. List<PLData *> data_list;
  381. for (const TileSelection &E : tiles) {
  382. const Vector2i &coords = E.tile;
  383. const int &alternative = E.alternative;
  384. TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
  385. ERR_FAIL_COND(!tile_data);
  386. List<PropertyInfo> list;
  387. tile_data->get_property_list(&list);
  388. HashMap<String, int> counts; // Counts the number of time a property appears (useful for groups that may appear more than once)
  389. for (List<PropertyInfo>::Element *E_property = list.front(); E_property; E_property = E_property->next()) {
  390. const String &property_string = E_property->get().name;
  391. if (!tile_data->is_allowing_transform() && (property_string == "flip_h" || property_string == "flip_v" || property_string == "transpose")) {
  392. continue;
  393. }
  394. if (!counts.has(property_string)) {
  395. counts[property_string] = 1;
  396. } else {
  397. counts[property_string] += 1;
  398. }
  399. PropertyInfo stored_property_info = E_property->get();
  400. stored_property_info.usage |= PROPERTY_USAGE_STORAGE; // Ignore the storage flag in comparing properties.
  401. PropertyId id = { counts[property_string], property_string };
  402. if (!usage.has(id)) {
  403. usage[id] = { 1, stored_property_info };
  404. data_list.push_back(&usage[id]);
  405. } else if (usage[id].property_info == stored_property_info) {
  406. usage[id].uses += 1;
  407. }
  408. }
  409. }
  410. // Add only properties that are common to all tiles.
  411. for (const PLData *E : data_list) {
  412. if (E->uses == tiles.size()) {
  413. p_list->push_back(E->property_info);
  414. }
  415. }
  416. }
  417. void TileSetAtlasSourceEditor::AtlasTileProxyObject::edit(TileSetAtlasSource *p_tile_set_atlas_source, RBSet<TileSelection> p_tiles) {
  418. ERR_FAIL_COND(!p_tile_set_atlas_source);
  419. ERR_FAIL_COND(p_tiles.is_empty());
  420. for (const TileSelection &E : p_tiles) {
  421. ERR_FAIL_COND(E.tile == TileSetSource::INVALID_ATLAS_COORDS);
  422. ERR_FAIL_COND(E.alternative < 0);
  423. }
  424. // Disconnect to changes.
  425. for (const TileSelection &E : tiles) {
  426. const Vector2i &coords = E.tile;
  427. const int &alternative = E.alternative;
  428. if (tile_set_atlas_source && tile_set_atlas_source->has_tile(coords) && tile_set_atlas_source->has_alternative_tile(coords, alternative)) {
  429. TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
  430. if (tile_data->is_connected(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed))) {
  431. tile_data->disconnect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
  432. }
  433. }
  434. }
  435. tile_set_atlas_source = p_tile_set_atlas_source;
  436. tiles = RBSet<TileSelection>(p_tiles);
  437. // Connect to changes.
  438. for (const TileSelection &E : p_tiles) {
  439. const Vector2i &coords = E.tile;
  440. const int &alternative = E.alternative;
  441. if (tile_set_atlas_source->has_tile(coords) && tile_set_atlas_source->has_alternative_tile(coords, alternative)) {
  442. TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
  443. if (!tile_data->is_connected(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed))) {
  444. tile_data->connect(CoreStringNames::get_singleton()->property_list_changed, callable_mp((Object *)this, &Object::notify_property_list_changed));
  445. }
  446. }
  447. }
  448. notify_property_list_changed();
  449. }
  450. void TileSetAtlasSourceEditor::AtlasTileProxyObject::_bind_methods() {
  451. ADD_SIGNAL(MethodInfo("changed", PropertyInfo(Variant::STRING, "what")));
  452. }
  453. void TileSetAtlasSourceEditor::_inspector_property_selected(String p_property) {
  454. selected_property = p_property;
  455. _update_atlas_view();
  456. _update_current_tile_data_editor();
  457. }
  458. void TileSetAtlasSourceEditor::_update_tile_id_label() {
  459. if (selection.size() == 1) {
  460. TileSelection selected = selection.front()->get();
  461. tool_tile_id_label->set_text(vformat("%d, %s, %d", tile_set_atlas_source_id, selected.tile, selected.alternative));
  462. tool_tile_id_label->set_tooltip_text(vformat(TTR("Selected tile:\nSource: %d\nAtlas coordinates: %s\nAlternative: %d"), tile_set_atlas_source_id, selected.tile, selected.alternative));
  463. tool_tile_id_label->show();
  464. } else {
  465. tool_tile_id_label->hide();
  466. }
  467. }
  468. void TileSetAtlasSourceEditor::_update_source_inspector() {
  469. // Update the proxy object.
  470. atlas_source_proxy_object->edit(tile_set, tile_set_atlas_source, tile_set_atlas_source_id);
  471. }
  472. void TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles() {
  473. // Fix selected.
  474. for (RBSet<TileSelection>::Element *E = selection.front(); E; E = E->next()) {
  475. TileSelection selected = E->get();
  476. if (!tile_set_atlas_source->has_tile(selected.tile) || !tile_set_atlas_source->has_alternative_tile(selected.tile, selected.alternative)) {
  477. selection.erase(E);
  478. }
  479. }
  480. // Fix hovered.
  481. if (!tile_set_atlas_source->has_tile(hovered_base_tile_coords)) {
  482. hovered_base_tile_coords = TileSetSource::INVALID_ATLAS_COORDS;
  483. }
  484. Vector2i coords = Vector2i(hovered_alternative_tile_coords.x, hovered_alternative_tile_coords.y);
  485. int alternative = hovered_alternative_tile_coords.z;
  486. if (!tile_set_atlas_source->has_tile(coords) || !tile_set_atlas_source->has_alternative_tile(coords, alternative)) {
  487. hovered_alternative_tile_coords = Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE);
  488. }
  489. }
  490. void TileSetAtlasSourceEditor::_update_atlas_source_inspector() {
  491. // Update visibility.
  492. bool visible = tools_button_group->get_pressed_button() == tool_setup_atlas_source_button;
  493. atlas_source_inspector_label->set_visible(visible);
  494. atlas_source_inspector->set_visible(visible);
  495. }
  496. void TileSetAtlasSourceEditor::_update_tile_inspector() {
  497. // Update visibility.
  498. if (tools_button_group->get_pressed_button() == tool_select_button) {
  499. if (!selection.is_empty()) {
  500. tile_proxy_object->edit(tile_set_atlas_source, selection);
  501. }
  502. tile_inspector_label->show();
  503. tile_inspector->set_visible(!selection.is_empty());
  504. tile_inspector_no_tile_selected_label->set_visible(selection.is_empty());
  505. } else {
  506. tile_inspector_label->hide();
  507. tile_inspector->hide();
  508. tile_inspector_no_tile_selected_label->hide();
  509. }
  510. }
  511. void TileSetAtlasSourceEditor::_update_tile_data_editors() {
  512. String previously_selected;
  513. if (tile_data_editors_tree && tile_data_editors_tree->get_selected()) {
  514. previously_selected = tile_data_editors_tree->get_selected()->get_metadata(0);
  515. }
  516. tile_data_editors_tree->clear();
  517. TreeItem *root = tile_data_editors_tree->create_item();
  518. TreeItem *group;
  519. #define ADD_TILE_DATA_EDITOR_GROUP(text) \
  520. group = tile_data_editors_tree->create_item(root); \
  521. group->set_custom_bg_color(0, group_color); \
  522. group->set_selectable(0, false); \
  523. group->set_disable_folding(true); \
  524. group->set_text(0, text);
  525. TreeItem *item;
  526. #define ADD_TILE_DATA_EDITOR(parent, text, property) \
  527. item = tile_data_editors_tree->create_item(parent); \
  528. item->set_text(0, text); \
  529. item->set_metadata(0, property); \
  530. if (property == previously_selected) { \
  531. item->select(0); \
  532. }
  533. // Theming.
  534. tile_data_editors_tree->add_theme_constant_override("v_separation", 1);
  535. tile_data_editors_tree->add_theme_constant_override("h_separation", 3);
  536. Color group_color = get_theme_color(SNAME("prop_category"), SNAME("Editor"));
  537. // List of editors.
  538. // --- Rendering ---
  539. ADD_TILE_DATA_EDITOR_GROUP("Rendering");
  540. ADD_TILE_DATA_EDITOR(group, "Texture Offset", "texture_offset");
  541. if (!tile_data_editors.has("texture_offset")) {
  542. TileDataTextureOffsetEditor *tile_data_texture_offset_editor = memnew(TileDataTextureOffsetEditor);
  543. tile_data_texture_offset_editor->hide();
  544. tile_data_texture_offset_editor->setup_property_editor(Variant::VECTOR2, "texture_offset");
  545. tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
  546. tile_data_texture_offset_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
  547. tile_data_editors["texture_offset"] = tile_data_texture_offset_editor;
  548. }
  549. ADD_TILE_DATA_EDITOR(group, "Modulate", "modulate");
  550. if (!tile_data_editors.has("modulate")) {
  551. TileDataDefaultEditor *tile_data_modulate_editor = memnew(TileDataDefaultEditor());
  552. tile_data_modulate_editor->hide();
  553. tile_data_modulate_editor->setup_property_editor(Variant::COLOR, "modulate", "", Color(1.0, 1.0, 1.0, 1.0));
  554. tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
  555. tile_data_modulate_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
  556. tile_data_editors["modulate"] = tile_data_modulate_editor;
  557. }
  558. ADD_TILE_DATA_EDITOR(group, "Z Index", "z_index");
  559. if (!tile_data_editors.has("z_index")) {
  560. TileDataDefaultEditor *tile_data_z_index_editor = memnew(TileDataDefaultEditor());
  561. tile_data_z_index_editor->hide();
  562. tile_data_z_index_editor->setup_property_editor(Variant::INT, "z_index");
  563. tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
  564. tile_data_z_index_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
  565. tile_data_editors["z_index"] = tile_data_z_index_editor;
  566. }
  567. ADD_TILE_DATA_EDITOR(group, "Y Sort Origin", "y_sort_origin");
  568. if (!tile_data_editors.has("y_sort_origin")) {
  569. TileDataYSortEditor *tile_data_y_sort_editor = memnew(TileDataYSortEditor);
  570. tile_data_y_sort_editor->hide();
  571. tile_data_y_sort_editor->setup_property_editor(Variant::INT, "y_sort_origin");
  572. tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
  573. tile_data_y_sort_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
  574. tile_data_editors["y_sort_origin"] = tile_data_y_sort_editor;
  575. }
  576. for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
  577. ADD_TILE_DATA_EDITOR(group, vformat("Occlusion Layer %d", i), vformat("occlusion_layer_%d", i));
  578. if (!tile_data_editors.has(vformat("occlusion_layer_%d", i))) {
  579. TileDataOcclusionShapeEditor *tile_data_occlusion_shape_editor = memnew(TileDataOcclusionShapeEditor());
  580. tile_data_occlusion_shape_editor->hide();
  581. tile_data_occlusion_shape_editor->set_occlusion_layer(i);
  582. tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
  583. tile_data_occlusion_shape_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
  584. tile_data_editors[vformat("occlusion_layer_%d", i)] = tile_data_occlusion_shape_editor;
  585. }
  586. }
  587. for (int i = tile_set->get_occlusion_layers_count(); tile_data_editors.has(vformat("occlusion_layer_%d", i)); i++) {
  588. tile_data_editors[vformat("occlusion_layer_%d", i)]->queue_delete();
  589. tile_data_editors.erase(vformat("occlusion_layer_%d", i));
  590. }
  591. // --- Rendering ---
  592. ADD_TILE_DATA_EDITOR(root, "Terrains", "terrain_set");
  593. if (!tile_data_editors.has("terrain_set")) {
  594. TileDataTerrainsEditor *tile_data_terrains_editor = memnew(TileDataTerrainsEditor);
  595. tile_data_terrains_editor->hide();
  596. tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
  597. tile_data_terrains_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
  598. tile_data_editors["terrain_set"] = tile_data_terrains_editor;
  599. }
  600. // --- Miscellaneous ---
  601. ADD_TILE_DATA_EDITOR(root, "Probability", "probability");
  602. if (!tile_data_editors.has("probability")) {
  603. TileDataDefaultEditor *tile_data_probability_editor = memnew(TileDataDefaultEditor());
  604. tile_data_probability_editor->hide();
  605. tile_data_probability_editor->setup_property_editor(Variant::FLOAT, "probability", "", 1.0);
  606. tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
  607. tile_data_probability_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
  608. tile_data_editors["probability"] = tile_data_probability_editor;
  609. }
  610. // --- Physics ---
  611. ADD_TILE_DATA_EDITOR_GROUP("Physics");
  612. for (int i = 0; i < tile_set->get_physics_layers_count(); i++) {
  613. ADD_TILE_DATA_EDITOR(group, vformat("Physics Layer %d", i), vformat("physics_layer_%d", i));
  614. if (!tile_data_editors.has(vformat("physics_layer_%d", i))) {
  615. TileDataCollisionEditor *tile_data_collision_editor = memnew(TileDataCollisionEditor());
  616. tile_data_collision_editor->hide();
  617. tile_data_collision_editor->set_physics_layer(i);
  618. tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
  619. tile_data_collision_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
  620. tile_data_editors[vformat("physics_layer_%d", i)] = tile_data_collision_editor;
  621. }
  622. }
  623. for (int i = tile_set->get_physics_layers_count(); tile_data_editors.has(vformat("physics_layer_%d", i)); i++) {
  624. tile_data_editors[vformat("physics_layer_%d", i)]->queue_delete();
  625. tile_data_editors.erase(vformat("physics_layer_%d", i));
  626. }
  627. // --- Navigation ---
  628. ADD_TILE_DATA_EDITOR_GROUP("Navigation");
  629. for (int i = 0; i < tile_set->get_navigation_layers_count(); i++) {
  630. ADD_TILE_DATA_EDITOR(group, vformat("Navigation Layer %d", i), vformat("navigation_layer_%d", i));
  631. if (!tile_data_editors.has(vformat("navigation_layer_%d", i))) {
  632. TileDataNavigationEditor *tile_data_navigation_editor = memnew(TileDataNavigationEditor());
  633. tile_data_navigation_editor->hide();
  634. tile_data_navigation_editor->set_navigation_layer(i);
  635. tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
  636. tile_data_navigation_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
  637. tile_data_editors[vformat("navigation_layer_%d", i)] = tile_data_navigation_editor;
  638. }
  639. }
  640. for (int i = tile_set->get_navigation_layers_count(); tile_data_editors.has(vformat("navigation_layer_%d", i)); i++) {
  641. tile_data_editors[vformat("navigation_layer_%d", i)]->queue_delete();
  642. tile_data_editors.erase(vformat("navigation_layer_%d", i));
  643. }
  644. // --- Custom Data ---
  645. ADD_TILE_DATA_EDITOR_GROUP("Custom Data");
  646. for (int i = 0; i < tile_set->get_custom_data_layers_count(); i++) {
  647. if (tile_set->get_custom_data_layer_name(i).is_empty()) {
  648. ADD_TILE_DATA_EDITOR(group, vformat("Custom Data %d", i), vformat("custom_data_%d", i));
  649. } else {
  650. ADD_TILE_DATA_EDITOR(group, tile_set->get_custom_data_layer_name(i), vformat("custom_data_%d", i));
  651. }
  652. if (!tile_data_editors.has(vformat("custom_data_%d", i))) {
  653. TileDataDefaultEditor *tile_data_custom_data_editor = memnew(TileDataDefaultEditor());
  654. tile_data_custom_data_editor->hide();
  655. tile_data_custom_data_editor->setup_property_editor(tile_set->get_custom_data_layer_type(i), vformat("custom_data_%d", i), tile_set->get_custom_data_layer_name(i));
  656. tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)tile_atlas_control_unscaled, &Control::queue_redraw));
  657. tile_data_custom_data_editor->connect("needs_redraw", callable_mp((CanvasItem *)alternative_tiles_control_unscaled, &Control::queue_redraw));
  658. tile_data_editors[vformat("custom_data_%d", i)] = tile_data_custom_data_editor;
  659. }
  660. }
  661. for (int i = tile_set->get_custom_data_layers_count(); tile_data_editors.has(vformat("custom_data_%d", i)); i++) {
  662. tile_data_editors[vformat("custom_data_%d", i)]->queue_delete();
  663. tile_data_editors.erase(vformat("custom_data_%d", i));
  664. }
  665. #undef ADD_TILE_DATA_EDITOR_GROUP
  666. #undef ADD_TILE_DATA_EDITOR
  667. // Add tile data editors as children.
  668. for (KeyValue<String, TileDataEditor *> &E : tile_data_editors) {
  669. // Tile Data Editor.
  670. TileDataEditor *tile_data_editor = E.value;
  671. if (!tile_data_editor->is_inside_tree()) {
  672. tile_data_painting_editor_container->add_child(tile_data_editor);
  673. }
  674. tile_data_editor->set_tile_set(tile_set);
  675. // Toolbar.
  676. Control *toolbar = tile_data_editor->get_toolbar();
  677. if (!toolbar->is_inside_tree()) {
  678. tool_settings_tile_data_toolbar_container->add_child(toolbar);
  679. }
  680. toolbar->hide();
  681. }
  682. // Update visibility.
  683. bool is_visible = tools_button_group->get_pressed_button() == tool_paint_button;
  684. tile_data_editor_dropdown_button->set_visible(is_visible);
  685. if (tile_data_editors_tree->get_selected()) {
  686. tile_data_editor_dropdown_button->set_text(tile_data_editors_tree->get_selected()->get_text(0));
  687. } else {
  688. tile_data_editor_dropdown_button->set_text(TTR("Select a property editor"));
  689. }
  690. tile_data_editors_label->set_visible(is_visible);
  691. }
  692. void TileSetAtlasSourceEditor::_update_current_tile_data_editor() {
  693. // Find the property to use.
  694. String property;
  695. if (tools_button_group->get_pressed_button() == tool_select_button && tile_inspector->is_visible() && !tile_inspector->get_selected_path().is_empty()) {
  696. Vector<String> components = tile_inspector->get_selected_path().split("/");
  697. if (components.size() >= 1) {
  698. property = components[0];
  699. // Workaround for terrains as they don't have a common first component.
  700. if (property.begins_with("terrains_")) {
  701. property = "terrain_set";
  702. }
  703. }
  704. } else if (tools_button_group->get_pressed_button() == tool_paint_button && tile_data_editors_tree->get_selected()) {
  705. property = tile_data_editors_tree->get_selected()->get_metadata(0);
  706. tile_data_editor_dropdown_button->set_text(tile_data_editors_tree->get_selected()->get_text(0));
  707. }
  708. // Hide all editors but the current one.
  709. for (const KeyValue<String, TileDataEditor *> &E : tile_data_editors) {
  710. E.value->hide();
  711. E.value->get_toolbar()->hide();
  712. }
  713. if (tile_data_editors.has(property)) {
  714. current_tile_data_editor = tile_data_editors[property];
  715. } else {
  716. current_tile_data_editor = nullptr;
  717. }
  718. // Get the correct editor for the TileData's property.
  719. if (current_tile_data_editor) {
  720. current_tile_data_editor_toolbar = current_tile_data_editor->get_toolbar();
  721. current_property = property;
  722. current_tile_data_editor->set_visible(tools_button_group->get_pressed_button() == tool_paint_button);
  723. current_tile_data_editor_toolbar->set_visible(tools_button_group->get_pressed_button() == tool_paint_button);
  724. }
  725. }
  726. void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_draw() {
  727. if (!has_theme_icon(SNAME("arrow"), SNAME("OptionButton"))) {
  728. return;
  729. }
  730. RID ci = tile_data_editor_dropdown_button->get_canvas_item();
  731. Ref<Texture2D> arrow = Control::get_theme_icon(SNAME("arrow"), SNAME("OptionButton"));
  732. Color clr = Color(1, 1, 1);
  733. if (get_theme_constant(SNAME("modulate_arrow"))) {
  734. switch (tile_data_editor_dropdown_button->get_draw_mode()) {
  735. case BaseButton::DRAW_PRESSED:
  736. clr = get_theme_color(SNAME("font_pressed_color"));
  737. break;
  738. case BaseButton::DRAW_HOVER:
  739. clr = get_theme_color(SNAME("font_hover_color"));
  740. break;
  741. case BaseButton::DRAW_DISABLED:
  742. clr = get_theme_color(SNAME("font_disabled_color"));
  743. break;
  744. default:
  745. if (tile_data_editor_dropdown_button->has_focus()) {
  746. clr = get_theme_color(SNAME("font_focus_color"));
  747. } else {
  748. clr = get_theme_color(SNAME("font_color"));
  749. }
  750. }
  751. }
  752. Size2 size = tile_data_editor_dropdown_button->get_size();
  753. Point2 ofs;
  754. if (is_layout_rtl()) {
  755. ofs = Point2(get_theme_constant(SNAME("arrow_margin"), SNAME("OptionButton")), int(Math::abs((size.height - arrow->get_height()) / 2)));
  756. } else {
  757. ofs = Point2(size.width - arrow->get_width() - get_theme_constant(SNAME("arrow_margin"), SNAME("OptionButton")), int(Math::abs((size.height - arrow->get_height()) / 2)));
  758. }
  759. arrow->draw(ci, ofs, clr);
  760. }
  761. void TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed() {
  762. Size2 size = tile_data_editor_dropdown_button->get_size();
  763. tile_data_editors_popup->set_position(tile_data_editor_dropdown_button->get_screen_position() + Size2(0, size.height * get_global_transform().get_scale().y));
  764. tile_data_editors_popup->set_size(Size2(size.width, 0));
  765. tile_data_editors_popup->popup();
  766. }
  767. void TileSetAtlasSourceEditor::_tile_data_editors_tree_selected() {
  768. tile_data_editors_popup->call_deferred(SNAME("hide"));
  769. _update_current_tile_data_editor();
  770. tile_atlas_control->queue_redraw();
  771. tile_atlas_control_unscaled->queue_redraw();
  772. alternative_tiles_control->queue_redraw();
  773. alternative_tiles_control_unscaled->queue_redraw();
  774. }
  775. void TileSetAtlasSourceEditor::_update_atlas_view() {
  776. // Update the atlas display.
  777. tile_atlas_view->set_atlas_source(*tile_set, tile_set_atlas_source, tile_set_atlas_source_id);
  778. // Create a bunch of buttons to add alternative tiles.
  779. for (int i = 0; i < alternative_tiles_control->get_child_count(); i++) {
  780. alternative_tiles_control->get_child(i)->queue_delete();
  781. }
  782. Vector2i pos;
  783. Vector2 texture_region_base_size = tile_set_atlas_source->get_texture_region_size();
  784. int texture_region_base_size_min = MIN(texture_region_base_size.x, texture_region_base_size.y);
  785. for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
  786. Vector2i tile_id = tile_set_atlas_source->get_tile_id(i);
  787. int alternative_count = tile_set_atlas_source->get_alternative_tiles_count(tile_id);
  788. if (alternative_count > 1) {
  789. // Compute the right extremity of alternative.
  790. int y_increment = 0;
  791. pos.x = 0;
  792. for (int j = 1; j < alternative_count; j++) {
  793. int alternative_id = tile_set_atlas_source->get_alternative_tile_id(tile_id, j);
  794. Rect2i rect = tile_atlas_view->get_alternative_tile_rect(tile_id, alternative_id);
  795. pos.x = MAX(pos.x, rect.get_end().x);
  796. y_increment = MAX(y_increment, rect.size.y);
  797. }
  798. // Create and position the button.
  799. Button *button = memnew(Button);
  800. alternative_tiles_control->add_child(button);
  801. button->set_flat(true);
  802. button->set_icon(get_theme_icon(SNAME("Add"), SNAME("EditorIcons")));
  803. button->add_theme_style_override("normal", memnew(StyleBoxEmpty));
  804. button->add_theme_style_override("hover", memnew(StyleBoxEmpty));
  805. button->add_theme_style_override("focus", memnew(StyleBoxEmpty));
  806. button->add_theme_style_override("pressed", memnew(StyleBoxEmpty));
  807. button->connect("pressed", callable_mp(tile_set_atlas_source, &TileSetAtlasSource::create_alternative_tile).bind(tile_id, TileSetSource::INVALID_TILE_ALTERNATIVE));
  808. button->set_rect(Rect2(Vector2(pos.x, pos.y + (y_increment - texture_region_base_size.y) / 2.0), Vector2(texture_region_base_size_min, texture_region_base_size_min)));
  809. button->set_expand_icon(true);
  810. pos.y += y_increment;
  811. }
  812. }
  813. tile_atlas_view->set_padding(Side::SIDE_RIGHT, texture_region_base_size_min);
  814. // Redraw everything.
  815. tile_atlas_control->queue_redraw();
  816. tile_atlas_control_unscaled->queue_redraw();
  817. alternative_tiles_control->queue_redraw();
  818. alternative_tiles_control_unscaled->queue_redraw();
  819. tile_atlas_view->queue_redraw();
  820. // Synchronize atlas view.
  821. TilesEditorPlugin::get_singleton()->synchronize_atlas_view(tile_atlas_view);
  822. }
  823. void TileSetAtlasSourceEditor::_update_toolbar() {
  824. // Show the tools and settings.
  825. if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) {
  826. if (current_tile_data_editor_toolbar) {
  827. current_tile_data_editor_toolbar->hide();
  828. }
  829. tool_settings_vsep->show();
  830. tools_settings_erase_button->show();
  831. tool_advanced_menu_buttom->show();
  832. } else if (tools_button_group->get_pressed_button() == tool_select_button) {
  833. if (current_tile_data_editor_toolbar) {
  834. current_tile_data_editor_toolbar->hide();
  835. }
  836. tool_settings_vsep->hide();
  837. tools_settings_erase_button->hide();
  838. tool_advanced_menu_buttom->hide();
  839. } else if (tools_button_group->get_pressed_button() == tool_paint_button) {
  840. if (current_tile_data_editor_toolbar) {
  841. current_tile_data_editor_toolbar->show();
  842. }
  843. tool_settings_vsep->hide();
  844. tools_settings_erase_button->hide();
  845. tool_advanced_menu_buttom->hide();
  846. }
  847. }
  848. void TileSetAtlasSourceEditor::_tile_atlas_control_mouse_exited() {
  849. hovered_base_tile_coords = TileSetSource::INVALID_ATLAS_COORDS;
  850. tile_atlas_control->queue_redraw();
  851. tile_atlas_control_unscaled->queue_redraw();
  852. tile_atlas_view->queue_redraw();
  853. }
  854. void TileSetAtlasSourceEditor::_tile_atlas_view_transform_changed() {
  855. tile_atlas_control->queue_redraw();
  856. tile_atlas_control_unscaled->queue_redraw();
  857. }
  858. void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEvent> &p_event) {
  859. // Update the hovered coords.
  860. hovered_base_tile_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
  861. // Forward the event to the current tile data editor if we are in the painting mode.
  862. if (tools_button_group->get_pressed_button() == tool_paint_button) {
  863. if (current_tile_data_editor) {
  864. current_tile_data_editor->forward_painting_atlas_gui_input(tile_atlas_view, tile_set_atlas_source, p_event);
  865. }
  866. // Update only what's needed.
  867. tile_set_changed_needs_update = false;
  868. tile_atlas_control->queue_redraw();
  869. tile_atlas_control_unscaled->queue_redraw();
  870. alternative_tiles_control->queue_redraw();
  871. alternative_tiles_control_unscaled->queue_redraw();
  872. tile_atlas_view->queue_redraw();
  873. return;
  874. } else {
  875. // Handle the event.
  876. Ref<InputEventMouseMotion> mm = p_event;
  877. if (mm.is_valid()) {
  878. Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
  879. Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos);
  880. Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
  881. Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
  882. if (drag_type == DRAG_TYPE_NONE) {
  883. if (selection.size() == 1) {
  884. // Change the cursor depending on the hovered thing.
  885. TileSelection selected = selection.front()->get();
  886. if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
  887. Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
  888. Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
  889. Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
  890. Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
  891. Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
  892. const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
  893. const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
  894. CursorShape cursor_shape = CURSOR_ARROW;
  895. bool can_grow[4];
  896. for (int i = 0; i < 4; i++) {
  897. can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
  898. can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
  899. }
  900. for (int i = 0; i < 4; i++) {
  901. Vector2 pos = rect.position + rect.size * coords[i];
  902. if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
  903. cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
  904. }
  905. Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
  906. if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
  907. cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
  908. }
  909. }
  910. tile_atlas_control->set_default_cursor_shape(cursor_shape);
  911. }
  912. }
  913. } else if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) {
  914. // Create big tile.
  915. new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
  916. Rect2i new_rect = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
  917. new_rect.size += Vector2i(1, 1);
  918. // Check if the new tile can fit in the new rect.
  919. if (tile_set_atlas_source->has_room_for_tile(new_rect.position, new_rect.size, tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) {
  920. // Move and resize the tile.
  921. tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size);
  922. drag_current_tile = new_rect.position;
  923. }
  924. } else if (drag_type == DRAG_TYPE_CREATE_TILES) {
  925. // Create tiles.
  926. last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
  927. new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
  928. Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords);
  929. for (int i = 0; i < line.size(); i++) {
  930. if (tile_set_atlas_source->get_tile_at_coords(line[i]) == TileSetSource::INVALID_ATLAS_COORDS) {
  931. tile_set_atlas_source->create_tile(line[i]);
  932. drag_modified_tiles.insert(line[i]);
  933. }
  934. }
  935. drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position();
  936. } else if (drag_type == DRAG_TYPE_REMOVE_TILES) {
  937. // Remove tiles.
  938. last_base_tiles_coords = last_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
  939. new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
  940. Vector<Point2i> line = Geometry2D::bresenham_line(last_base_tiles_coords, new_base_tiles_coords);
  941. for (int i = 0; i < line.size(); i++) {
  942. Vector2i base_tile_coords = tile_set_atlas_source->get_tile_at_coords(line[i]);
  943. if (base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
  944. drag_modified_tiles.insert(base_tile_coords);
  945. }
  946. }
  947. drag_last_mouse_pos = tile_atlas_control->get_local_mouse_position();
  948. } else if (drag_type == DRAG_TYPE_MOVE_TILE) {
  949. // Move tile.
  950. Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
  951. Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset);
  952. coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
  953. if (drag_current_tile != coords && tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile), tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) {
  954. tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords);
  955. selection.clear();
  956. selection.insert({ coords, 0 });
  957. drag_current_tile = coords;
  958. // Update only what's needed.
  959. tile_set_changed_needs_update = false;
  960. _update_tile_inspector();
  961. _update_atlas_view();
  962. _update_tile_id_label();
  963. _update_current_tile_data_editor();
  964. }
  965. } else if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) {
  966. if (Vector2(drag_start_mouse_pos).distance_to(tile_atlas_control->get_local_mouse_position()) > 5.0 * EDSCALE) {
  967. drag_type = DRAG_TYPE_NONE;
  968. }
  969. } else if (drag_type >= DRAG_TYPE_RESIZE_TOP_LEFT && drag_type <= DRAG_TYPE_RESIZE_LEFT) {
  970. // Resizing a tile.
  971. new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(-1, -1)).min(grid_size);
  972. Rect2i old_rect = Rect2i(drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
  973. Rect2i new_rect = old_rect;
  974. if (drag_type == DRAG_TYPE_RESIZE_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT) {
  975. new_rect.position.x = MIN(new_base_tiles_coords.x + 1, old_rect.get_end().x - 1);
  976. new_rect.size.x = old_rect.get_end().x - new_rect.position.x;
  977. }
  978. if (drag_type == DRAG_TYPE_RESIZE_TOP || drag_type == DRAG_TYPE_RESIZE_TOP_LEFT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT) {
  979. new_rect.position.y = MIN(new_base_tiles_coords.y + 1, old_rect.get_end().y - 1);
  980. new_rect.size.y = old_rect.get_end().y - new_rect.position.y;
  981. }
  982. if (drag_type == DRAG_TYPE_RESIZE_RIGHT || drag_type == DRAG_TYPE_RESIZE_TOP_RIGHT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) {
  983. new_rect.set_end(Vector2i(MAX(new_base_tiles_coords.x, old_rect.position.x + 1), new_rect.get_end().y));
  984. }
  985. if (drag_type == DRAG_TYPE_RESIZE_BOTTOM || drag_type == DRAG_TYPE_RESIZE_BOTTOM_LEFT || drag_type == DRAG_TYPE_RESIZE_BOTTOM_RIGHT) {
  986. new_rect.set_end(Vector2i(new_rect.get_end().x, MAX(new_base_tiles_coords.y, old_rect.position.y + 1)));
  987. }
  988. if (tile_set_atlas_source->has_room_for_tile(new_rect.position, new_rect.size, tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) {
  989. tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, new_rect.position, new_rect.size);
  990. selection.clear();
  991. selection.insert({ new_rect.position, 0 });
  992. drag_current_tile = new_rect.position;
  993. // Update only what's needed.
  994. tile_set_changed_needs_update = false;
  995. _update_tile_inspector();
  996. _update_atlas_view();
  997. _update_tile_id_label();
  998. _update_current_tile_data_editor();
  999. }
  1000. }
  1001. // Redraw for the hovered tile.
  1002. tile_atlas_control->queue_redraw();
  1003. tile_atlas_control_unscaled->queue_redraw();
  1004. alternative_tiles_control->queue_redraw();
  1005. alternative_tiles_control_unscaled->queue_redraw();
  1006. tile_atlas_view->queue_redraw();
  1007. return;
  1008. }
  1009. Ref<InputEventMouseButton> mb = p_event;
  1010. if (mb.is_valid()) {
  1011. Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
  1012. if (mb->get_button_index() == MouseButton::LEFT) {
  1013. if (mb->is_pressed()) {
  1014. // Left click pressed.
  1015. if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) {
  1016. if (tools_settings_erase_button->is_pressed()) {
  1017. // Erasing
  1018. if (mb->is_ctrl_pressed() || mb->is_shift_pressed()) {
  1019. // Remove tiles using rect.
  1020. // Setup the dragging info.
  1021. drag_type = DRAG_TYPE_REMOVE_TILES_USING_RECT;
  1022. drag_start_mouse_pos = mouse_local_pos;
  1023. drag_last_mouse_pos = drag_start_mouse_pos;
  1024. } else {
  1025. // Remove tiles.
  1026. // Setup the dragging info.
  1027. drag_type = DRAG_TYPE_REMOVE_TILES;
  1028. drag_start_mouse_pos = mouse_local_pos;
  1029. drag_last_mouse_pos = drag_start_mouse_pos;
  1030. // Remove a first tile.
  1031. Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
  1032. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  1033. coords = tile_set_atlas_source->get_tile_at_coords(coords);
  1034. }
  1035. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  1036. drag_modified_tiles.insert(coords);
  1037. }
  1038. }
  1039. } else {
  1040. // Creating
  1041. if (mb->is_shift_pressed()) {
  1042. // Create a big tile.
  1043. Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos);
  1044. if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
  1045. // Setup the dragging info, only if we start on an empty tile.
  1046. drag_type = DRAG_TYPE_CREATE_BIG_TILE;
  1047. drag_start_mouse_pos = mouse_local_pos;
  1048. drag_last_mouse_pos = drag_start_mouse_pos;
  1049. drag_current_tile = coords;
  1050. // Create a tile.
  1051. tile_set_atlas_source->create_tile(coords);
  1052. }
  1053. } else if (mb->is_ctrl_pressed()) {
  1054. // Create tiles using rect.
  1055. drag_type = DRAG_TYPE_CREATE_TILES_USING_RECT;
  1056. drag_start_mouse_pos = mouse_local_pos;
  1057. drag_last_mouse_pos = drag_start_mouse_pos;
  1058. } else {
  1059. // Create tiles.
  1060. // Setup the dragging info.
  1061. drag_type = DRAG_TYPE_CREATE_TILES;
  1062. drag_start_mouse_pos = mouse_local_pos;
  1063. drag_last_mouse_pos = drag_start_mouse_pos;
  1064. // Create a first tile if needed.
  1065. Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
  1066. if (coords != TileSetSource::INVALID_ATLAS_COORDS && tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
  1067. tile_set_atlas_source->create_tile(coords);
  1068. drag_modified_tiles.insert(coords);
  1069. }
  1070. }
  1071. }
  1072. } else if (tools_button_group->get_pressed_button() == tool_select_button) {
  1073. // Dragging a handle.
  1074. drag_type = DRAG_TYPE_NONE;
  1075. if (selection.size() == 1) {
  1076. TileSelection selected = selection.front()->get();
  1077. if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
  1078. Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
  1079. Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
  1080. Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
  1081. Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
  1082. const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
  1083. const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
  1084. CursorShape cursor_shape = CURSOR_ARROW;
  1085. bool can_grow[4];
  1086. for (int i = 0; i < 4; i++) {
  1087. can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
  1088. can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
  1089. }
  1090. for (int i = 0; i < 4; i++) {
  1091. Vector2 pos = rect.position + rect.size * coords[i];
  1092. if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
  1093. drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP_LEFT + i * 2);
  1094. drag_start_mouse_pos = mouse_local_pos;
  1095. drag_last_mouse_pos = drag_start_mouse_pos;
  1096. drag_current_tile = selected.tile;
  1097. drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
  1098. cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
  1099. }
  1100. Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
  1101. if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
  1102. drag_type = (DragType)((int)DRAG_TYPE_RESIZE_TOP + i * 2);
  1103. drag_start_mouse_pos = mouse_local_pos;
  1104. drag_last_mouse_pos = drag_start_mouse_pos;
  1105. drag_current_tile = selected.tile;
  1106. drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
  1107. cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
  1108. }
  1109. }
  1110. tile_atlas_control->set_default_cursor_shape(cursor_shape);
  1111. }
  1112. }
  1113. // Selecting then dragging a tile.
  1114. if (drag_type == DRAG_TYPE_NONE) {
  1115. TileSelection selected = { TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE };
  1116. Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos);
  1117. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  1118. coords = tile_set_atlas_source->get_tile_at_coords(coords);
  1119. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  1120. selected = { coords, 0 };
  1121. }
  1122. }
  1123. bool shift = mb->is_shift_pressed();
  1124. if (!shift && selection.size() == 1 && selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) {
  1125. // Start move dragging.
  1126. drag_type = DRAG_TYPE_MOVE_TILE;
  1127. drag_start_mouse_pos = mouse_local_pos;
  1128. drag_last_mouse_pos = drag_start_mouse_pos;
  1129. drag_current_tile = selected.tile;
  1130. drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
  1131. tile_atlas_control->set_default_cursor_shape(CURSOR_MOVE);
  1132. } else {
  1133. // Start selection dragging.
  1134. drag_type = DRAG_TYPE_RECT_SELECT;
  1135. drag_start_mouse_pos = mouse_local_pos;
  1136. drag_last_mouse_pos = drag_start_mouse_pos;
  1137. }
  1138. }
  1139. }
  1140. } else {
  1141. // Left click released.
  1142. _end_dragging();
  1143. }
  1144. tile_atlas_control->queue_redraw();
  1145. tile_atlas_control_unscaled->queue_redraw();
  1146. alternative_tiles_control->queue_redraw();
  1147. alternative_tiles_control_unscaled->queue_redraw();
  1148. tile_atlas_view->queue_redraw();
  1149. return;
  1150. } else if (mb->get_button_index() == MouseButton::RIGHT) {
  1151. // Right click pressed.
  1152. if (mb->is_pressed()) {
  1153. drag_type = DRAG_TYPE_MAY_POPUP_MENU;
  1154. drag_start_mouse_pos = tile_atlas_control->get_local_mouse_position();
  1155. } else {
  1156. // Right click released.
  1157. _end_dragging();
  1158. }
  1159. tile_atlas_control->queue_redraw();
  1160. tile_atlas_control_unscaled->queue_redraw();
  1161. alternative_tiles_control->queue_redraw();
  1162. alternative_tiles_control_unscaled->queue_redraw();
  1163. tile_atlas_view->queue_redraw();
  1164. return;
  1165. }
  1166. }
  1167. }
  1168. }
  1169. void TileSetAtlasSourceEditor::_end_dragging() {
  1170. switch (drag_type) {
  1171. case DRAG_TYPE_CREATE_TILES:
  1172. undo_redo->create_action(TTR("Create tiles"));
  1173. for (const Vector2i &E : drag_modified_tiles) {
  1174. undo_redo->add_do_method(tile_set_atlas_source, "create_tile", E);
  1175. undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", E);
  1176. }
  1177. undo_redo->commit_action(false);
  1178. break;
  1179. case DRAG_TYPE_CREATE_BIG_TILE:
  1180. undo_redo->create_action(TTR("Create a tile"));
  1181. undo_redo->add_do_method(tile_set_atlas_source, "create_tile", drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
  1182. undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", drag_current_tile);
  1183. undo_redo->commit_action(false);
  1184. break;
  1185. case DRAG_TYPE_REMOVE_TILES: {
  1186. List<PropertyInfo> list;
  1187. tile_set_atlas_source->get_property_list(&list);
  1188. HashMap<Vector2i, List<const PropertyInfo *>> per_tile = _group_properties_per_tiles(list, tile_set_atlas_source);
  1189. undo_redo->create_action(TTR("Remove tiles"));
  1190. for (const Vector2i &E : drag_modified_tiles) {
  1191. Vector2i coords = E;
  1192. undo_redo->add_do_method(tile_set_atlas_source, "remove_tile", coords);
  1193. undo_redo->add_undo_method(tile_set_atlas_source, "create_tile", coords);
  1194. if (per_tile.has(coords)) {
  1195. for (List<const PropertyInfo *>::Element *E_property = per_tile[coords].front(); E_property; E_property = E_property->next()) {
  1196. String property = E_property->get()->name;
  1197. Variant value = tile_set_atlas_source->get(property);
  1198. if (value.get_type() != Variant::NIL) {
  1199. undo_redo->add_undo_method(tile_set_atlas_source, "set", E_property->get()->name, value);
  1200. }
  1201. }
  1202. }
  1203. }
  1204. undo_redo->commit_action();
  1205. } break;
  1206. case DRAG_TYPE_CREATE_TILES_USING_RECT: {
  1207. Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
  1208. Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
  1209. Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
  1210. area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
  1211. undo_redo->create_action(TTR("Create tiles"));
  1212. for (int x = area.get_position().x; x < area.get_end().x; x++) {
  1213. for (int y = area.get_position().y; y < area.get_end().y; y++) {
  1214. Vector2i coords = Vector2i(x, y);
  1215. if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
  1216. undo_redo->add_do_method(tile_set_atlas_source, "create_tile", coords);
  1217. undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", coords);
  1218. }
  1219. }
  1220. }
  1221. undo_redo->commit_action();
  1222. } break;
  1223. case DRAG_TYPE_REMOVE_TILES_USING_RECT: {
  1224. Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
  1225. Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
  1226. Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
  1227. area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
  1228. List<PropertyInfo> list;
  1229. tile_set_atlas_source->get_property_list(&list);
  1230. HashMap<Vector2i, List<const PropertyInfo *>> per_tile = _group_properties_per_tiles(list, tile_set_atlas_source);
  1231. RBSet<Vector2i> to_delete;
  1232. for (int x = area.get_position().x; x < area.get_end().x; x++) {
  1233. for (int y = area.get_position().y; y < area.get_end().y; y++) {
  1234. Vector2i coords = tile_set_atlas_source->get_tile_at_coords(Vector2i(x, y));
  1235. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  1236. to_delete.insert(coords);
  1237. }
  1238. }
  1239. }
  1240. undo_redo->create_action(TTR("Remove tiles"));
  1241. undo_redo->add_do_method(this, "_set_selection_from_array", Array());
  1242. for (const Vector2i &E : to_delete) {
  1243. Vector2i coords = E;
  1244. undo_redo->add_do_method(tile_set_atlas_source, "remove_tile", coords);
  1245. undo_redo->add_undo_method(tile_set_atlas_source, "create_tile", coords);
  1246. if (per_tile.has(coords)) {
  1247. for (List<const PropertyInfo *>::Element *E_property = per_tile[coords].front(); E_property; E_property = E_property->next()) {
  1248. String property = E_property->get()->name;
  1249. Variant value = tile_set_atlas_source->get(property);
  1250. if (value.get_type() != Variant::NIL) {
  1251. undo_redo->add_undo_method(tile_set_atlas_source, "set", E_property->get()->name, value);
  1252. }
  1253. }
  1254. }
  1255. }
  1256. undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
  1257. undo_redo->commit_action();
  1258. } break;
  1259. case DRAG_TYPE_MOVE_TILE:
  1260. if (drag_current_tile != drag_start_tile_shape.position) {
  1261. undo_redo->create_action(TTR("Move a tile"));
  1262. undo_redo->add_do_method(tile_set_atlas_source, "move_tile_in_atlas", drag_start_tile_shape.position, drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
  1263. undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
  1264. undo_redo->add_undo_method(tile_set_atlas_source, "move_tile_in_atlas", drag_current_tile, drag_start_tile_shape.position, drag_start_tile_shape.size);
  1265. Array array;
  1266. array.push_back(drag_start_tile_shape.position);
  1267. array.push_back(0);
  1268. undo_redo->add_undo_method(this, "_set_selection_from_array", array);
  1269. undo_redo->commit_action(false);
  1270. }
  1271. break;
  1272. case DRAG_TYPE_RECT_SELECT: {
  1273. Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
  1274. Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
  1275. ERR_FAIL_COND(start_base_tiles_coords == TileSetSource::INVALID_ATLAS_COORDS);
  1276. ERR_FAIL_COND(new_base_tiles_coords == TileSetSource::INVALID_ATLAS_COORDS);
  1277. Rect2i region = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
  1278. region.size += Vector2i(1, 1);
  1279. undo_redo->create_action(TTR("Select tiles"));
  1280. undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
  1281. // Determine if we clear, then add or remove to the selection.
  1282. bool add_to_selection = true;
  1283. if (Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
  1284. Vector2i coords = tile_set_atlas_source->get_tile_at_coords(start_base_tiles_coords);
  1285. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  1286. if (selection.has({ coords, 0 })) {
  1287. add_to_selection = false;
  1288. }
  1289. }
  1290. } else {
  1291. selection.clear();
  1292. }
  1293. // Modify the selection.
  1294. for (int x = region.position.x; x < region.get_end().x; x++) {
  1295. for (int y = region.position.y; y < region.get_end().y; y++) {
  1296. Vector2i coords = Vector2i(x, y);
  1297. coords = tile_set_atlas_source->get_tile_at_coords(coords);
  1298. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  1299. if (add_to_selection && !selection.has({ coords, 0 })) {
  1300. selection.insert({ coords, 0 });
  1301. } else if (!add_to_selection && selection.has({ coords, 0 })) {
  1302. selection.erase({ coords, 0 });
  1303. }
  1304. }
  1305. }
  1306. }
  1307. _update_tile_inspector();
  1308. _update_tile_id_label();
  1309. _update_current_tile_data_editor();
  1310. undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
  1311. undo_redo->commit_action(false);
  1312. } break;
  1313. case DRAG_TYPE_MAY_POPUP_MENU: {
  1314. Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
  1315. TileSelection selected = { tile_atlas_view->get_atlas_tile_coords_at_pos(mouse_local_pos), 0 };
  1316. if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
  1317. selected.tile = tile_set_atlas_source->get_tile_at_coords(selected.tile);
  1318. }
  1319. // Set the selection if needed.
  1320. if (selection.size() <= 1) {
  1321. if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
  1322. undo_redo->create_action(TTR("Select tiles"));
  1323. undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
  1324. selection.clear();
  1325. selection.insert(selected);
  1326. undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
  1327. undo_redo->commit_action(false);
  1328. _update_tile_inspector();
  1329. _update_tile_id_label();
  1330. _update_current_tile_data_editor();
  1331. }
  1332. }
  1333. // Pops up the correct menu, depending on whether we have a tile or not.
  1334. if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selection.has(selected)) {
  1335. // We have a tile.
  1336. menu_option_coords = selected.tile;
  1337. menu_option_alternative = 0;
  1338. base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
  1339. } else if (hovered_base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
  1340. // We don't have a tile, but can create one.
  1341. menu_option_coords = hovered_base_tile_coords;
  1342. menu_option_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE;
  1343. empty_base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
  1344. }
  1345. } break;
  1346. case DRAG_TYPE_RESIZE_TOP_LEFT:
  1347. case DRAG_TYPE_RESIZE_TOP:
  1348. case DRAG_TYPE_RESIZE_TOP_RIGHT:
  1349. case DRAG_TYPE_RESIZE_RIGHT:
  1350. case DRAG_TYPE_RESIZE_BOTTOM_RIGHT:
  1351. case DRAG_TYPE_RESIZE_BOTTOM:
  1352. case DRAG_TYPE_RESIZE_BOTTOM_LEFT:
  1353. case DRAG_TYPE_RESIZE_LEFT:
  1354. if (drag_start_tile_shape != Rect2i(drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile))) {
  1355. undo_redo->create_action(TTR("Resize a tile"));
  1356. undo_redo->add_do_method(tile_set_atlas_source, "move_tile_in_atlas", drag_start_tile_shape.position, drag_current_tile, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile));
  1357. undo_redo->add_do_method(this, "_set_selection_from_array", _get_selection_as_array());
  1358. undo_redo->add_undo_method(tile_set_atlas_source, "move_tile_in_atlas", drag_current_tile, drag_start_tile_shape.position, drag_start_tile_shape.size);
  1359. Array array;
  1360. array.push_back(drag_start_tile_shape.position);
  1361. array.push_back(0);
  1362. undo_redo->add_undo_method(this, "_set_selection_from_array", array);
  1363. undo_redo->commit_action(false);
  1364. }
  1365. break;
  1366. default:
  1367. break;
  1368. }
  1369. drag_modified_tiles.clear();
  1370. drag_type = DRAG_TYPE_NONE;
  1371. tile_atlas_control->set_default_cursor_shape(CURSOR_ARROW);
  1372. }
  1373. HashMap<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_properties_per_tiles(const List<PropertyInfo> &r_list, const TileSetAtlasSource *p_atlas) {
  1374. // Group properties per tile.
  1375. HashMap<Vector2i, List<const PropertyInfo *>> per_tile;
  1376. for (const List<PropertyInfo>::Element *E_property = r_list.front(); E_property; E_property = E_property->next()) {
  1377. Vector<String> components = String(E_property->get().name).split("/", true, 1);
  1378. if (components.size() >= 1) {
  1379. Vector<String> coord_arr = components[0].split(":");
  1380. if (coord_arr.size() == 2 && coord_arr[0].is_valid_int() && coord_arr[1].is_valid_int()) {
  1381. Vector2i coords = Vector2i(coord_arr[0].to_int(), coord_arr[1].to_int());
  1382. per_tile[coords].push_back(&(E_property->get()));
  1383. }
  1384. }
  1385. }
  1386. return per_tile;
  1387. }
  1388. void TileSetAtlasSourceEditor::_menu_option(int p_option) {
  1389. switch (p_option) {
  1390. case TILE_DELETE: {
  1391. List<PropertyInfo> list;
  1392. tile_set_atlas_source->get_property_list(&list);
  1393. HashMap<Vector2i, List<const PropertyInfo *>> per_tile = _group_properties_per_tiles(list, tile_set_atlas_source);
  1394. undo_redo->create_action(TTR("Remove tile"));
  1395. // Remove tiles
  1396. RBSet<Vector2i> removed;
  1397. for (const TileSelection &E : selection) {
  1398. TileSelection selected = E;
  1399. if (selected.alternative == 0) {
  1400. // Remove a tile.
  1401. undo_redo->add_do_method(tile_set_atlas_source, "remove_tile", selected.tile);
  1402. undo_redo->add_undo_method(tile_set_atlas_source, "create_tile", selected.tile);
  1403. removed.insert(selected.tile);
  1404. if (per_tile.has(selected.tile)) {
  1405. for (List<const PropertyInfo *>::Element *E_property = per_tile[selected.tile].front(); E_property; E_property = E_property->next()) {
  1406. String property = E_property->get()->name;
  1407. Variant value = tile_set_atlas_source->get(property);
  1408. if (value.get_type() != Variant::NIL) {
  1409. undo_redo->add_undo_method(tile_set_atlas_source, "set", E_property->get()->name, value);
  1410. }
  1411. }
  1412. }
  1413. }
  1414. }
  1415. // Remove alternatives
  1416. for (const TileSelection &E : selection) {
  1417. TileSelection selected = E;
  1418. if (selected.alternative > 0 && !removed.has(selected.tile)) {
  1419. // Remove an alternative tile.
  1420. undo_redo->add_do_method(tile_set_atlas_source, "remove_alternative_tile", selected.tile, selected.alternative);
  1421. undo_redo->add_undo_method(tile_set_atlas_source, "create_alternative_tile", selected.tile, selected.alternative);
  1422. if (per_tile.has(selected.tile)) {
  1423. for (List<const PropertyInfo *>::Element *E_property = per_tile[selected.tile].front(); E_property; E_property = E_property->next()) {
  1424. Vector<String> components = E_property->get()->name.split("/", true, 2);
  1425. if (components.size() >= 2 && components[1].is_valid_int() && components[1].to_int() == selected.alternative) {
  1426. String property = E_property->get()->name;
  1427. Variant value = tile_set_atlas_source->get(property);
  1428. if (value.get_type() != Variant::NIL) {
  1429. undo_redo->add_undo_method(tile_set_atlas_source, "set", E_property->get()->name, value);
  1430. }
  1431. }
  1432. }
  1433. }
  1434. }
  1435. }
  1436. undo_redo->commit_action();
  1437. _update_fix_selected_and_hovered_tiles();
  1438. _update_tile_id_label();
  1439. } break;
  1440. case TILE_CREATE: {
  1441. undo_redo->create_action(TTR("Create a tile"));
  1442. undo_redo->add_do_method(tile_set_atlas_source, "create_tile", menu_option_coords);
  1443. Array array;
  1444. array.push_back(menu_option_coords);
  1445. array.push_back(0);
  1446. undo_redo->add_do_method(this, "_set_selection_from_array", array);
  1447. undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", menu_option_coords);
  1448. undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
  1449. undo_redo->commit_action();
  1450. _update_tile_id_label();
  1451. } break;
  1452. case TILE_CREATE_ALTERNATIVE: {
  1453. undo_redo->create_action(TTR("Create tile alternatives"));
  1454. Array array;
  1455. for (const TileSelection &E : selection) {
  1456. if (E.alternative == 0) {
  1457. int next_id = tile_set_atlas_source->get_next_alternative_tile_id(E.tile);
  1458. undo_redo->add_do_method(tile_set_atlas_source, "create_alternative_tile", E.tile, next_id);
  1459. array.push_back(E.tile);
  1460. array.push_back(next_id);
  1461. undo_redo->add_undo_method(tile_set_atlas_source, "remove_alternative_tile", E.tile, next_id);
  1462. }
  1463. }
  1464. undo_redo->add_do_method(this, "_set_selection_from_array", array);
  1465. undo_redo->add_undo_method(this, "_set_selection_from_array", _get_selection_as_array());
  1466. undo_redo->commit_action();
  1467. _update_tile_id_label();
  1468. } break;
  1469. case ADVANCED_AUTO_CREATE_TILES: {
  1470. _auto_create_tiles();
  1471. } break;
  1472. case ADVANCED_AUTO_REMOVE_TILES: {
  1473. _auto_remove_tiles();
  1474. } break;
  1475. }
  1476. }
  1477. void TileSetAtlasSourceEditor::_unhandled_key_input(const Ref<InputEvent> &p_event) {
  1478. // Check for shortcuts.
  1479. if (ED_IS_SHORTCUT("tiles_editor/delete_tile", p_event)) {
  1480. if (tools_button_group->get_pressed_button() == tool_select_button && !selection.is_empty()) {
  1481. _menu_option(TILE_DELETE);
  1482. accept_event();
  1483. }
  1484. }
  1485. }
  1486. void TileSetAtlasSourceEditor::_set_selection_from_array(Array p_selection) {
  1487. ERR_FAIL_COND((p_selection.size() % 2) != 0);
  1488. selection.clear();
  1489. for (int i = 0; i < p_selection.size() / 2; i++) {
  1490. TileSelection selected = { p_selection[i * 2], p_selection[i * 2 + 1] };
  1491. if (tile_set_atlas_source->has_tile(selected.tile) && tile_set_atlas_source->has_alternative_tile(selected.tile, selected.alternative)) {
  1492. selection.insert(selected);
  1493. }
  1494. }
  1495. _update_tile_inspector();
  1496. _update_tile_id_label();
  1497. _update_atlas_view();
  1498. _update_current_tile_data_editor();
  1499. }
  1500. Array TileSetAtlasSourceEditor::_get_selection_as_array() {
  1501. Array output;
  1502. for (const TileSelection &E : selection) {
  1503. output.push_back(E.tile);
  1504. output.push_back(E.alternative);
  1505. }
  1506. return output;
  1507. }
  1508. void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
  1509. // Colors.
  1510. Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
  1511. Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
  1512. // Draw the selected tile.
  1513. if (tools_button_group->get_pressed_button() == tool_select_button) {
  1514. for (const TileSelection &E : selection) {
  1515. TileSelection selected = E;
  1516. if (selected.alternative == 0) {
  1517. // Draw the rect.
  1518. for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(selected.tile); frame++) {
  1519. Color color = selection_color;
  1520. if (frame > 0) {
  1521. color.a *= 0.3;
  1522. }
  1523. Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile, frame);
  1524. tile_atlas_control->draw_rect(region, color, false);
  1525. }
  1526. }
  1527. }
  1528. if (selection.size() == 1) {
  1529. // Draw the resize handles (only when it's possible to expand).
  1530. TileSelection selected = selection.front()->get();
  1531. if (selected.alternative == 0) {
  1532. Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
  1533. Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
  1534. Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
  1535. Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
  1536. const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
  1537. const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
  1538. bool can_grow[4];
  1539. for (int i = 0; i < 4; i++) {
  1540. can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
  1541. can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
  1542. }
  1543. for (int i = 0; i < 4; i++) {
  1544. Vector2 pos = rect.position + rect.size * coords[i];
  1545. if (can_grow[i] && can_grow[(i + 3) % 4]) {
  1546. tile_atlas_control->draw_texture_rect(resize_handle, Rect2(pos, zoomed_size), false);
  1547. } else {
  1548. tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2(pos, zoomed_size), false);
  1549. }
  1550. Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
  1551. if (can_grow[i]) {
  1552. tile_atlas_control->draw_texture_rect(resize_handle, Rect2((pos + next_pos) / 2.0, zoomed_size), false);
  1553. } else {
  1554. tile_atlas_control->draw_texture_rect(resize_handle_disabled, Rect2((pos + next_pos) / 2.0, zoomed_size), false);
  1555. }
  1556. }
  1557. }
  1558. }
  1559. }
  1560. if (drag_type == DRAG_TYPE_REMOVE_TILES) {
  1561. // Draw the tiles to be removed.
  1562. for (const Vector2i &E : drag_modified_tiles) {
  1563. for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(E); frame++) {
  1564. tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(E, frame), Color(0.0, 0.0, 0.0), false);
  1565. }
  1566. }
  1567. } else if (drag_type == DRAG_TYPE_RECT_SELECT || drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT) {
  1568. // Draw tiles to be removed.
  1569. Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
  1570. Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
  1571. Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
  1572. area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
  1573. Color color = Color(0.0, 0.0, 0.0);
  1574. if (drag_type == DRAG_TYPE_RECT_SELECT) {
  1575. color = selection_color.lightened(0.2);
  1576. }
  1577. RBSet<Vector2i> to_paint;
  1578. for (int x = area.get_position().x; x < area.get_end().x; x++) {
  1579. for (int y = area.get_position().y; y < area.get_end().y; y++) {
  1580. Vector2i coords = tile_set_atlas_source->get_tile_at_coords(Vector2i(x, y));
  1581. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  1582. to_paint.insert(coords);
  1583. }
  1584. }
  1585. }
  1586. for (const Vector2i &E : to_paint) {
  1587. Vector2i coords = E;
  1588. tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(coords), color, false);
  1589. }
  1590. } else if (drag_type == DRAG_TYPE_CREATE_TILES_USING_RECT) {
  1591. // Draw tiles to be created.
  1592. Vector2i margins = tile_set_atlas_source->get_margins();
  1593. Vector2i separation = tile_set_atlas_source->get_separation();
  1594. Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
  1595. Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
  1596. Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
  1597. Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
  1598. area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
  1599. for (int x = area.get_position().x; x < area.get_end().x; x++) {
  1600. for (int y = area.get_position().y; y < area.get_end().y; y++) {
  1601. Vector2i coords = Vector2i(x, y);
  1602. if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
  1603. Vector2i origin = margins + (coords * (tile_size + separation));
  1604. tile_atlas_control->draw_rect(Rect2i(origin, tile_size), Color(1.0, 1.0, 1.0), false);
  1605. }
  1606. }
  1607. }
  1608. }
  1609. // Draw the hovered tile.
  1610. if (drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT || drag_type == DRAG_TYPE_CREATE_TILES_USING_RECT) {
  1611. // Draw the rect.
  1612. Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
  1613. Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
  1614. Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
  1615. area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
  1616. Vector2i margins = tile_set_atlas_source->get_margins();
  1617. Vector2i separation = tile_set_atlas_source->get_separation();
  1618. Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
  1619. Vector2i origin = margins + (area.position * (tile_size + separation));
  1620. tile_atlas_control->draw_rect(Rect2i(origin, area.size * tile_size), Color(1.0, 1.0, 1.0), false);
  1621. } else {
  1622. Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
  1623. if (hovered_base_tile_coords.x >= 0 && hovered_base_tile_coords.y >= 0 && hovered_base_tile_coords.x < grid_size.x && hovered_base_tile_coords.y < grid_size.y) {
  1624. Vector2i hovered_tile = tile_set_atlas_source->get_tile_at_coords(hovered_base_tile_coords);
  1625. if (hovered_tile != TileSetSource::INVALID_ATLAS_COORDS) {
  1626. // Draw existing hovered tile.
  1627. for (int frame = 0; frame < tile_set_atlas_source->get_tile_animation_frames_count(hovered_tile); frame++) {
  1628. Color color = Color(1.0, 1.0, 1.0);
  1629. if (frame > 0) {
  1630. color.a *= 0.3;
  1631. }
  1632. tile_atlas_control->draw_rect(tile_set_atlas_source->get_tile_texture_region(hovered_tile, frame), color, false);
  1633. }
  1634. } else {
  1635. // Draw empty tile, only in add/remove tiles mode.
  1636. if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) {
  1637. Vector2i margins = tile_set_atlas_source->get_margins();
  1638. Vector2i separation = tile_set_atlas_source->get_separation();
  1639. Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
  1640. Vector2i origin = margins + (hovered_base_tile_coords * (tile_size + separation));
  1641. tile_atlas_control->draw_rect(Rect2i(origin, tile_size), Color(1.0, 1.0, 1.0), false);
  1642. }
  1643. }
  1644. }
  1645. }
  1646. }
  1647. void TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw() {
  1648. if (current_tile_data_editor) {
  1649. // Draw the preview of the selected property.
  1650. for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
  1651. Vector2i coords = tile_set_atlas_source->get_tile_id(i);
  1652. Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(coords);
  1653. Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(coords, 0);
  1654. Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
  1655. xform.translate_local(position);
  1656. if (tools_button_group->get_pressed_button() == tool_select_button && selection.has({ coords, 0 })) {
  1657. continue;
  1658. }
  1659. TileMapCell cell;
  1660. cell.source_id = tile_set_atlas_source_id;
  1661. cell.set_atlas_coords(coords);
  1662. cell.alternative_tile = 0;
  1663. current_tile_data_editor->draw_over_tile(tile_atlas_control_unscaled, xform, cell);
  1664. }
  1665. // Draw the selection on top of other.
  1666. if (tools_button_group->get_pressed_button() == tool_select_button) {
  1667. for (const TileSelection &E : selection) {
  1668. if (E.alternative != 0) {
  1669. continue;
  1670. }
  1671. Rect2i texture_region = tile_set_atlas_source->get_tile_texture_region(E.tile);
  1672. Vector2i position = texture_region.get_center() + tile_set_atlas_source->get_tile_effective_texture_offset(E.tile, 0);
  1673. Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
  1674. xform.translate_local(position);
  1675. TileMapCell cell;
  1676. cell.source_id = tile_set_atlas_source_id;
  1677. cell.set_atlas_coords(E.tile);
  1678. cell.alternative_tile = 0;
  1679. current_tile_data_editor->draw_over_tile(tile_atlas_control_unscaled, xform, cell, true);
  1680. }
  1681. }
  1682. // Call the TileData's editor custom draw function.
  1683. if (tools_button_group->get_pressed_button() == tool_paint_button) {
  1684. Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
  1685. current_tile_data_editor->forward_draw_over_atlas(tile_atlas_view, tile_set_atlas_source, tile_atlas_control_unscaled, xform);
  1686. }
  1687. }
  1688. }
  1689. void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<InputEvent> &p_event) {
  1690. // Update the hovered alternative tile.
  1691. hovered_alternative_tile_coords = tile_atlas_view->get_alternative_tile_at_pos(alternative_tiles_control->get_local_mouse_position());
  1692. // Forward the event to the current tile data editor if we are in the painting mode.
  1693. if (tools_button_group->get_pressed_button() == tool_paint_button) {
  1694. if (current_tile_data_editor) {
  1695. current_tile_data_editor->forward_painting_alternatives_gui_input(tile_atlas_view, tile_set_atlas_source, p_event);
  1696. }
  1697. tile_atlas_control->queue_redraw();
  1698. tile_atlas_control_unscaled->queue_redraw();
  1699. alternative_tiles_control->queue_redraw();
  1700. alternative_tiles_control_unscaled->queue_redraw();
  1701. tile_atlas_view->queue_redraw();
  1702. return;
  1703. }
  1704. Ref<InputEventMouseMotion> mm = p_event;
  1705. if (mm.is_valid()) {
  1706. tile_atlas_control->queue_redraw();
  1707. tile_atlas_control_unscaled->queue_redraw();
  1708. alternative_tiles_control->queue_redraw();
  1709. alternative_tiles_control_unscaled->queue_redraw();
  1710. if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) {
  1711. if (Vector2(drag_start_mouse_pos).distance_to(alternative_tiles_control->get_local_mouse_position()) > 5.0 * EDSCALE) {
  1712. drag_type = DRAG_TYPE_NONE;
  1713. }
  1714. }
  1715. }
  1716. Ref<InputEventMouseButton> mb = p_event;
  1717. if (mb.is_valid()) {
  1718. Vector2 mouse_local_pos = alternative_tiles_control->get_local_mouse_position();
  1719. if (mb->get_button_index() == MouseButton::LEFT) {
  1720. if (mb->is_pressed()) {
  1721. // Left click pressed.
  1722. if (tools_button_group->get_pressed_button() == tool_select_button) {
  1723. Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos);
  1724. selection.clear();
  1725. TileSelection selected = { Vector2i(tile.x, tile.y), int(tile.z) };
  1726. if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
  1727. selection.insert(selected);
  1728. }
  1729. _update_tile_inspector();
  1730. _update_tile_id_label();
  1731. }
  1732. }
  1733. } else if (mb->get_button_index() == MouseButton::RIGHT) {
  1734. if (mb->is_pressed()) {
  1735. drag_type = DRAG_TYPE_MAY_POPUP_MENU;
  1736. drag_start_mouse_pos = alternative_tiles_control->get_local_mouse_position();
  1737. } else {
  1738. if (drag_type == DRAG_TYPE_MAY_POPUP_MENU) {
  1739. // Right click released and wasn't dragged too far
  1740. Vector3 tile = tile_atlas_view->get_alternative_tile_at_pos(mouse_local_pos);
  1741. selection.clear();
  1742. TileSelection selected = { Vector2i(tile.x, tile.y), int(tile.z) };
  1743. if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS) {
  1744. selection.insert(selected);
  1745. }
  1746. _update_tile_inspector();
  1747. _update_tile_id_label();
  1748. if (selection.size() == 1) {
  1749. selected = selection.front()->get();
  1750. menu_option_coords = selected.tile;
  1751. menu_option_alternative = selected.alternative;
  1752. alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
  1753. }
  1754. }
  1755. drag_type = DRAG_TYPE_NONE;
  1756. }
  1757. }
  1758. tile_atlas_control->queue_redraw();
  1759. tile_atlas_control_unscaled->queue_redraw();
  1760. alternative_tiles_control->queue_redraw();
  1761. alternative_tiles_control_unscaled->queue_redraw();
  1762. }
  1763. }
  1764. void TileSetAtlasSourceEditor::_tile_alternatives_control_mouse_exited() {
  1765. hovered_alternative_tile_coords = Vector3i(TileSetSource::INVALID_ATLAS_COORDS.x, TileSetSource::INVALID_ATLAS_COORDS.y, TileSetSource::INVALID_TILE_ALTERNATIVE);
  1766. tile_atlas_control->queue_redraw();
  1767. tile_atlas_control_unscaled->queue_redraw();
  1768. alternative_tiles_control->queue_redraw();
  1769. alternative_tiles_control_unscaled->queue_redraw();
  1770. }
  1771. void TileSetAtlasSourceEditor::_tile_alternatives_control_draw() {
  1772. Color grid_color = EditorSettings::get_singleton()->get("editors/tiles_editor/grid_color");
  1773. Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
  1774. // Update the hovered alternative tile.
  1775. if (tools_button_group->get_pressed_button() == tool_select_button) {
  1776. // Draw hovered tile.
  1777. Vector2i coords = Vector2(hovered_alternative_tile_coords.x, hovered_alternative_tile_coords.y);
  1778. if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
  1779. Rect2i rect = tile_atlas_view->get_alternative_tile_rect(coords, hovered_alternative_tile_coords.z);
  1780. if (rect != Rect2i()) {
  1781. alternative_tiles_control->draw_rect(rect, Color(1.0, 1.0, 1.0), false);
  1782. }
  1783. }
  1784. // Draw selected tile.
  1785. for (const TileSelection &E : selection) {
  1786. TileSelection selected = E;
  1787. if (selected.alternative >= 1) {
  1788. Rect2i rect = tile_atlas_view->get_alternative_tile_rect(selected.tile, selected.alternative);
  1789. if (rect != Rect2i()) {
  1790. alternative_tiles_control->draw_rect(rect, selection_color, false);
  1791. }
  1792. }
  1793. }
  1794. }
  1795. }
  1796. void TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw() {
  1797. // Draw the preview of the selected property.
  1798. if (current_tile_data_editor) {
  1799. // Draw the preview of the currently selected property.
  1800. for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
  1801. Vector2i coords = tile_set_atlas_source->get_tile_id(i);
  1802. for (int j = 0; j < tile_set_atlas_source->get_alternative_tiles_count(coords); j++) {
  1803. int alternative_tile = tile_set_atlas_source->get_alternative_tile_id(coords, j);
  1804. if (alternative_tile == 0) {
  1805. continue;
  1806. }
  1807. Rect2i rect = tile_atlas_view->get_alternative_tile_rect(coords, alternative_tile);
  1808. Vector2 position = rect.get_center();
  1809. Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform();
  1810. xform.translate_local(position);
  1811. if (tools_button_group->get_pressed_button() == tool_select_button && selection.has({ coords, alternative_tile })) {
  1812. continue;
  1813. }
  1814. TileMapCell cell;
  1815. cell.source_id = tile_set_atlas_source_id;
  1816. cell.set_atlas_coords(coords);
  1817. cell.alternative_tile = alternative_tile;
  1818. current_tile_data_editor->draw_over_tile(alternative_tiles_control_unscaled, xform, cell);
  1819. }
  1820. }
  1821. // Draw the selection on top of other.
  1822. if (tools_button_group->get_pressed_button() == tool_select_button) {
  1823. for (const TileSelection &E : selection) {
  1824. if (E.alternative == 0) {
  1825. continue;
  1826. }
  1827. Rect2i rect = tile_atlas_view->get_alternative_tile_rect(E.tile, E.alternative);
  1828. Vector2 position = rect.get_center();
  1829. Transform2D xform = alternative_tiles_control->get_parent_control()->get_transform();
  1830. xform.translate_local(position);
  1831. TileMapCell cell;
  1832. cell.source_id = tile_set_atlas_source_id;
  1833. cell.set_atlas_coords(E.tile);
  1834. cell.alternative_tile = E.alternative;
  1835. current_tile_data_editor->draw_over_tile(alternative_tiles_control_unscaled, xform, cell, true);
  1836. }
  1837. }
  1838. // Call the TileData's editor custom draw function.
  1839. if (tools_button_group->get_pressed_button() == tool_paint_button) {
  1840. Transform2D xform = tile_atlas_control->get_parent_control()->get_transform();
  1841. current_tile_data_editor->forward_draw_over_alternatives(tile_atlas_view, tile_set_atlas_source, alternative_tiles_control_unscaled, xform);
  1842. }
  1843. }
  1844. }
  1845. void TileSetAtlasSourceEditor::_tile_set_changed() {
  1846. tile_set_changed_needs_update = true;
  1847. }
  1848. void TileSetAtlasSourceEditor::_tile_proxy_object_changed(String p_what) {
  1849. tile_set_changed_needs_update = false; // Avoid updating too many things.
  1850. _update_atlas_view();
  1851. }
  1852. void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what) {
  1853. if (p_what == "texture" && !atlas_source_proxy_object->get("texture").is_null()) {
  1854. confirm_auto_create_tiles->popup_centered();
  1855. } else if (p_what == "id") {
  1856. emit_signal(SNAME("source_id_changed"), atlas_source_proxy_object->get_id());
  1857. }
  1858. }
  1859. void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
  1860. Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
  1861. ERR_FAIL_COND(!undo_redo.is_valid());
  1862. #define ADD_UNDO(obj, property) undo_redo->add_undo_property(obj, property, obj->get(property));
  1863. AtlasTileProxyObject *tile_data_proxy = Object::cast_to<AtlasTileProxyObject>(p_edited);
  1864. if (tile_data_proxy) {
  1865. UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(tile_data_proxy).undo_redo;
  1866. internal_undo_redo->start_force_keep_in_merge_ends();
  1867. Vector<String> components = String(p_property).split("/", true, 2);
  1868. if (components.size() == 2 && components[1] == "polygons_count") {
  1869. int layer_index = components[0].trim_prefix("physics_layer_").to_int();
  1870. int new_polygons_count = p_new_value;
  1871. int old_polygons_count = tile_data_proxy->get(vformat("physics_layer_%d/polygons_count", layer_index));
  1872. if (new_polygons_count < old_polygons_count) {
  1873. for (int i = new_polygons_count; i < old_polygons_count; i++) {
  1874. ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/points", layer_index, i));
  1875. ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/one_way", layer_index, i));
  1876. ADD_UNDO(tile_data_proxy, vformat("physics_layer_%d/polygon_%d/one_way_margin", layer_index, i));
  1877. }
  1878. }
  1879. } else if (p_property == "terrain_set") {
  1880. int current_terrain_set = tile_data_proxy->get("terrain_set");
  1881. ADD_UNDO(tile_data_proxy, "terrain");
  1882. for (int i = 0; i < TileSet::CELL_NEIGHBOR_MAX; i++) {
  1883. TileSet::CellNeighbor bit = TileSet::CellNeighbor(i);
  1884. if (tile_set->is_valid_terrain_peering_bit(current_terrain_set, bit)) {
  1885. ADD_UNDO(tile_data_proxy, "terrains_peering_bit/" + String(TileSet::CELL_NEIGHBOR_ENUM_TO_TEXT[i]));
  1886. }
  1887. }
  1888. }
  1889. internal_undo_redo->end_force_keep_in_merge_ends();
  1890. }
  1891. TileSetAtlasSourceProxyObject *atlas_source_proxy = Object::cast_to<TileSetAtlasSourceProxyObject>(p_edited);
  1892. if (atlas_source_proxy) {
  1893. TileSetAtlasSource *atlas_source = atlas_source_proxy->get_edited();
  1894. ERR_FAIL_COND(!atlas_source);
  1895. UndoRedo *internal_undo_redo = undo_redo->get_history_for_object(atlas_source).undo_redo;
  1896. internal_undo_redo->start_force_keep_in_merge_ends();
  1897. PackedVector2Array arr;
  1898. if (p_property == "texture") {
  1899. arr = atlas_source->get_tiles_to_be_removed_on_change(p_new_value, atlas_source->get_margins(), atlas_source->get_separation(), atlas_source->get_texture_region_size());
  1900. } else if (p_property == "margins") {
  1901. arr = atlas_source->get_tiles_to_be_removed_on_change(atlas_source->get_texture(), p_new_value, atlas_source->get_separation(), atlas_source->get_texture_region_size());
  1902. } else if (p_property == "separation") {
  1903. arr = atlas_source->get_tiles_to_be_removed_on_change(atlas_source->get_texture(), atlas_source->get_margins(), p_new_value, atlas_source->get_texture_region_size());
  1904. } else if (p_property == "texture_region_size") {
  1905. arr = atlas_source->get_tiles_to_be_removed_on_change(atlas_source->get_texture(), atlas_source->get_margins(), atlas_source->get_separation(), p_new_value);
  1906. }
  1907. if (!arr.is_empty()) {
  1908. // Get all properties assigned to a tile.
  1909. List<PropertyInfo> properties;
  1910. atlas_source->get_property_list(&properties);
  1911. for (int i = 0; i < arr.size(); i++) {
  1912. Vector2i coords = arr[i];
  1913. String prefix = vformat("%d:%d/", coords.x, coords.y);
  1914. for (PropertyInfo pi : properties) {
  1915. if (pi.name.begins_with(prefix)) {
  1916. ADD_UNDO(atlas_source, pi.name);
  1917. }
  1918. }
  1919. }
  1920. }
  1921. internal_undo_redo->end_force_keep_in_merge_ends();
  1922. }
  1923. #undef ADD_UNDO
  1924. }
  1925. void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id) {
  1926. ERR_FAIL_COND(!p_tile_set.is_valid());
  1927. ERR_FAIL_COND(!p_tile_set_atlas_source);
  1928. ERR_FAIL_COND(p_source_id < 0);
  1929. ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
  1930. if (p_tile_set == tile_set && p_tile_set_atlas_source == tile_set_atlas_source && p_source_id == tile_set_atlas_source_id) {
  1931. return;
  1932. }
  1933. // Remove listener for old objects.
  1934. if (tile_set.is_valid()) {
  1935. tile_set->disconnect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
  1936. }
  1937. // Clear the selection.
  1938. selection.clear();
  1939. // Change the edited object.
  1940. tile_set = p_tile_set;
  1941. tile_set_atlas_source = p_tile_set_atlas_source;
  1942. tile_set_atlas_source_id = p_source_id;
  1943. // Add the listener again.
  1944. if (tile_set.is_valid()) {
  1945. tile_set->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_set_changed));
  1946. }
  1947. // Update everything.
  1948. _update_source_inspector();
  1949. // Update the selected tile.
  1950. _update_fix_selected_and_hovered_tiles();
  1951. _update_tile_id_label();
  1952. _update_atlas_view();
  1953. _update_atlas_source_inspector();
  1954. _update_tile_inspector();
  1955. _update_tile_data_editors();
  1956. _update_current_tile_data_editor();
  1957. }
  1958. void TileSetAtlasSourceEditor::init_source() {
  1959. confirm_auto_create_tiles->popup_centered();
  1960. }
  1961. void TileSetAtlasSourceEditor::_auto_create_tiles() {
  1962. if (!tile_set_atlas_source) {
  1963. return;
  1964. }
  1965. Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
  1966. if (texture.is_valid()) {
  1967. Vector2i margins = tile_set_atlas_source->get_margins();
  1968. Vector2i separation = tile_set_atlas_source->get_separation();
  1969. Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
  1970. Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
  1971. undo_redo->create_action(TTR("Create tiles in non-transparent texture regions"));
  1972. for (int y = 0; y < grid_size.y; y++) {
  1973. for (int x = 0; x < grid_size.x; x++) {
  1974. // Check if we have a tile at the coord
  1975. Vector2i coords = Vector2i(x, y);
  1976. if (tile_set_atlas_source->get_tile_at_coords(coords) == TileSetSource::INVALID_ATLAS_COORDS) {
  1977. // Check if the texture is empty at the given coords.
  1978. Rect2i region = Rect2i(margins + (coords * (texture_region_size + separation)), texture_region_size);
  1979. bool is_opaque = false;
  1980. for (int region_x = region.get_position().x; region_x < region.get_end().x; region_x++) {
  1981. for (int region_y = region.get_position().y; region_y < region.get_end().y; region_y++) {
  1982. if (texture->is_pixel_opaque(region_x, region_y)) {
  1983. is_opaque = true;
  1984. break;
  1985. }
  1986. }
  1987. if (is_opaque) {
  1988. break;
  1989. }
  1990. }
  1991. // If we do have opaque pixels, create a tile.
  1992. if (is_opaque) {
  1993. undo_redo->add_do_method(tile_set_atlas_source, "create_tile", coords);
  1994. undo_redo->add_undo_method(tile_set_atlas_source, "remove_tile", coords);
  1995. }
  1996. }
  1997. }
  1998. }
  1999. undo_redo->commit_action();
  2000. }
  2001. }
  2002. void TileSetAtlasSourceEditor::_auto_remove_tiles() {
  2003. if (!tile_set_atlas_source) {
  2004. return;
  2005. }
  2006. Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
  2007. if (texture.is_valid()) {
  2008. Vector2i margins = tile_set_atlas_source->get_margins();
  2009. Vector2i separation = tile_set_atlas_source->get_separation();
  2010. Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
  2011. Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
  2012. undo_redo->create_action(TTR("Remove tiles in fully transparent texture regions"));
  2013. List<PropertyInfo> list;
  2014. tile_set_atlas_source->get_property_list(&list);
  2015. HashMap<Vector2i, List<const PropertyInfo *>> per_tile = _group_properties_per_tiles(list, tile_set_atlas_source);
  2016. for (int i = 0; i < tile_set_atlas_source->get_tiles_count(); i++) {
  2017. Vector2i coords = tile_set_atlas_source->get_tile_id(i);
  2018. Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(coords);
  2019. // Skip tiles outside texture.
  2020. if ((coords.x + size_in_atlas.x) > grid_size.x || (coords.y + size_in_atlas.y) > grid_size.y) {
  2021. continue;
  2022. }
  2023. // Check if the texture is empty at the given coords.
  2024. Rect2i region = Rect2i(margins + (coords * (texture_region_size + separation)), texture_region_size * size_in_atlas);
  2025. bool is_opaque = false;
  2026. for (int region_x = region.get_position().x; region_x < region.get_end().x; region_x++) {
  2027. for (int region_y = region.get_position().y; region_y < region.get_end().y; region_y++) {
  2028. if (texture->is_pixel_opaque(region_x, region_y)) {
  2029. is_opaque = true;
  2030. break;
  2031. }
  2032. }
  2033. if (is_opaque) {
  2034. break;
  2035. }
  2036. }
  2037. // If we do have opaque pixels, create a tile.
  2038. if (!is_opaque) {
  2039. undo_redo->add_do_method(tile_set_atlas_source, "remove_tile", coords);
  2040. undo_redo->add_undo_method(tile_set_atlas_source, "create_tile", coords);
  2041. if (per_tile.has(coords)) {
  2042. for (List<const PropertyInfo *>::Element *E_property = per_tile[coords].front(); E_property; E_property = E_property->next()) {
  2043. String property = E_property->get()->name;
  2044. Variant value = tile_set_atlas_source->get(property);
  2045. if (value.get_type() != Variant::NIL) {
  2046. undo_redo->add_undo_method(tile_set_atlas_source, "set", E_property->get()->name, value);
  2047. }
  2048. }
  2049. }
  2050. }
  2051. }
  2052. undo_redo->commit_action();
  2053. }
  2054. }
  2055. void TileSetAtlasSourceEditor::_notification(int p_what) {
  2056. switch (p_what) {
  2057. case NOTIFICATION_ENTER_TREE:
  2058. case NOTIFICATION_THEME_CHANGED: {
  2059. tool_setup_atlas_source_button->set_icon(get_theme_icon(SNAME("Tools"), SNAME("EditorIcons")));
  2060. tool_select_button->set_icon(get_theme_icon(SNAME("ToolSelect"), SNAME("EditorIcons")));
  2061. tool_paint_button->set_icon(get_theme_icon(SNAME("CanvasItem"), SNAME("EditorIcons")));
  2062. tools_settings_erase_button->set_icon(get_theme_icon(SNAME("Eraser"), SNAME("EditorIcons")));
  2063. tool_advanced_menu_buttom->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
  2064. resize_handle = get_theme_icon(SNAME("EditorHandle"), SNAME("EditorIcons"));
  2065. resize_handle_disabled = get_theme_icon(SNAME("EditorHandleDisabled"), SNAME("EditorIcons"));
  2066. } break;
  2067. case NOTIFICATION_INTERNAL_PROCESS: {
  2068. if (tile_set_changed_needs_update) {
  2069. // Update everything.
  2070. _update_source_inspector();
  2071. // Update the selected tile.
  2072. _update_fix_selected_and_hovered_tiles();
  2073. _update_tile_id_label();
  2074. _update_atlas_view();
  2075. _update_atlas_source_inspector();
  2076. _update_tile_inspector();
  2077. _update_tile_data_editors();
  2078. _update_current_tile_data_editor();
  2079. tile_set_changed_needs_update = false;
  2080. }
  2081. } break;
  2082. }
  2083. }
  2084. void TileSetAtlasSourceEditor::_bind_methods() {
  2085. ClassDB::bind_method(D_METHOD("_unhandled_key_input"), &TileSetAtlasSourceEditor::_unhandled_key_input);
  2086. ClassDB::bind_method(D_METHOD("_set_selection_from_array"), &TileSetAtlasSourceEditor::_set_selection_from_array);
  2087. ADD_SIGNAL(MethodInfo("source_id_changed", PropertyInfo(Variant::INT, "source_id")));
  2088. }
  2089. TileSetAtlasSourceEditor::TileSetAtlasSourceEditor() {
  2090. undo_redo = EditorNode::get_undo_redo();
  2091. set_process_unhandled_key_input(true);
  2092. set_process_internal(true);
  2093. // -- Right side --
  2094. HSplitContainer *split_container_right_side = memnew(HSplitContainer);
  2095. split_container_right_side->set_h_size_flags(SIZE_EXPAND_FILL);
  2096. add_child(split_container_right_side);
  2097. // Middle panel.
  2098. ScrollContainer *middle_panel = memnew(ScrollContainer);
  2099. middle_panel->set_horizontal_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
  2100. middle_panel->set_custom_minimum_size(Size2i(200, 0) * EDSCALE);
  2101. split_container_right_side->add_child(middle_panel);
  2102. VBoxContainer *middle_vbox_container = memnew(VBoxContainer);
  2103. middle_vbox_container->set_h_size_flags(SIZE_EXPAND_FILL);
  2104. middle_panel->add_child(middle_vbox_container);
  2105. // Tile inspector.
  2106. tile_inspector_label = memnew(Label);
  2107. tile_inspector_label->set_text(TTR("Tile Properties:"));
  2108. tile_inspector_label->set_theme_type_variation("HeaderSmall");
  2109. middle_vbox_container->add_child(tile_inspector_label);
  2110. tile_proxy_object = memnew(AtlasTileProxyObject(this));
  2111. tile_proxy_object->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_proxy_object_changed));
  2112. tile_inspector = memnew(EditorInspector);
  2113. tile_inspector->set_undo_redo(undo_redo);
  2114. tile_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
  2115. tile_inspector->edit(tile_proxy_object);
  2116. tile_inspector->set_use_folding(true);
  2117. tile_inspector->connect("property_selected", callable_mp(this, &TileSetAtlasSourceEditor::_inspector_property_selected));
  2118. middle_vbox_container->add_child(tile_inspector);
  2119. tile_inspector_no_tile_selected_label = memnew(Label);
  2120. tile_inspector_no_tile_selected_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
  2121. tile_inspector_no_tile_selected_label->set_text(TTR("No tiles selected."));
  2122. middle_vbox_container->add_child(tile_inspector_no_tile_selected_label);
  2123. // Property values palette.
  2124. tile_data_editors_popup = memnew(Popup);
  2125. tile_data_editors_label = memnew(Label);
  2126. tile_data_editors_label->set_text(TTR("Paint Properties:"));
  2127. tile_data_editors_label->set_theme_type_variation("HeaderSmall");
  2128. middle_vbox_container->add_child(tile_data_editors_label);
  2129. tile_data_editor_dropdown_button = memnew(Button);
  2130. tile_data_editor_dropdown_button->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_draw));
  2131. tile_data_editor_dropdown_button->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editor_dropdown_button_pressed));
  2132. middle_vbox_container->add_child(tile_data_editor_dropdown_button);
  2133. tile_data_editor_dropdown_button->add_child(tile_data_editors_popup);
  2134. tile_data_editors_tree = memnew(Tree);
  2135. tile_data_editors_tree->set_hide_root(true);
  2136. tile_data_editors_tree->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
  2137. tile_data_editors_tree->set_h_scroll_enabled(false);
  2138. tile_data_editors_tree->set_v_scroll_enabled(false);
  2139. tile_data_editors_tree->connect("item_selected", callable_mp(this, &TileSetAtlasSourceEditor::_tile_data_editors_tree_selected));
  2140. tile_data_editors_popup->add_child(tile_data_editors_tree);
  2141. tile_data_painting_editor_container = memnew(VBoxContainer);
  2142. tile_data_painting_editor_container->set_h_size_flags(SIZE_EXPAND_FILL);
  2143. middle_vbox_container->add_child(tile_data_painting_editor_container);
  2144. // Atlas source inspector.
  2145. atlas_source_inspector_label = memnew(Label);
  2146. atlas_source_inspector_label->set_text(TTR("Atlas Properties:"));
  2147. atlas_source_inspector_label->set_theme_type_variation("HeaderSmall");
  2148. middle_vbox_container->add_child(atlas_source_inspector_label);
  2149. atlas_source_proxy_object = memnew(TileSetAtlasSourceProxyObject());
  2150. atlas_source_proxy_object->connect("changed", callable_mp(this, &TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed));
  2151. atlas_source_inspector = memnew(EditorInspector);
  2152. atlas_source_inspector->set_undo_redo(undo_redo);
  2153. atlas_source_inspector->set_vertical_scroll_mode(ScrollContainer::SCROLL_MODE_DISABLED);
  2154. atlas_source_inspector->edit(atlas_source_proxy_object);
  2155. middle_vbox_container->add_child(atlas_source_inspector);
  2156. // Right panel.
  2157. VBoxContainer *right_panel = memnew(VBoxContainer);
  2158. right_panel->set_h_size_flags(SIZE_EXPAND_FILL);
  2159. right_panel->set_v_size_flags(SIZE_EXPAND_FILL);
  2160. split_container_right_side->add_child(right_panel);
  2161. // -- Dialogs --
  2162. confirm_auto_create_tiles = memnew(AcceptDialog);
  2163. confirm_auto_create_tiles->set_title(TTR("Auto Create Tiles in Non-Transparent Texture Regions?"));
  2164. confirm_auto_create_tiles->set_text(TTR("The atlas's texture was modified.\nWould you like to automatically create tiles in the atlas?"));
  2165. confirm_auto_create_tiles->set_ok_button_text(TTR("Yes"));
  2166. confirm_auto_create_tiles->add_cancel_button()->set_text(TTR("No"));
  2167. confirm_auto_create_tiles->connect("confirmed", callable_mp(this, &TileSetAtlasSourceEditor::_auto_create_tiles));
  2168. add_child(confirm_auto_create_tiles);
  2169. // -- Toolbox --
  2170. tools_button_group.instantiate();
  2171. tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_fix_selected_and_hovered_tiles).unbind(1));
  2172. tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_id_label).unbind(1));
  2173. tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_source_inspector).unbind(1));
  2174. tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_inspector).unbind(1));
  2175. tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_tile_data_editors).unbind(1));
  2176. tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_current_tile_data_editor).unbind(1));
  2177. tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_atlas_view).unbind(1));
  2178. tools_button_group->connect("pressed", callable_mp(this, &TileSetAtlasSourceEditor::_update_toolbar).unbind(1));
  2179. toolbox = memnew(HBoxContainer);
  2180. right_panel->add_child(toolbox);
  2181. tool_setup_atlas_source_button = memnew(Button);
  2182. tool_setup_atlas_source_button->set_flat(true);
  2183. tool_setup_atlas_source_button->set_toggle_mode(true);
  2184. tool_setup_atlas_source_button->set_pressed(true);
  2185. tool_setup_atlas_source_button->set_button_group(tools_button_group);
  2186. tool_setup_atlas_source_button->set_tooltip_text(TTR("Atlas setup. Add/Remove tiles tool (use the shift key to create big tiles, control for rectangle editing)."));
  2187. toolbox->add_child(tool_setup_atlas_source_button);
  2188. tool_select_button = memnew(Button);
  2189. tool_select_button->set_flat(true);
  2190. tool_select_button->set_toggle_mode(true);
  2191. tool_select_button->set_pressed(false);
  2192. tool_select_button->set_button_group(tools_button_group);
  2193. tool_select_button->set_tooltip_text(TTR("Select tiles."));
  2194. toolbox->add_child(tool_select_button);
  2195. tool_paint_button = memnew(Button);
  2196. tool_paint_button->set_flat(true);
  2197. tool_paint_button->set_toggle_mode(true);
  2198. tool_paint_button->set_button_group(tools_button_group);
  2199. tool_paint_button->set_tooltip_text(TTR("Paint properties."));
  2200. toolbox->add_child(tool_paint_button);
  2201. // Tool settings.
  2202. tool_settings = memnew(HBoxContainer);
  2203. toolbox->add_child(tool_settings);
  2204. tool_settings_vsep = memnew(VSeparator);
  2205. tool_settings->add_child(tool_settings_vsep);
  2206. tool_settings_tile_data_toolbar_container = memnew(HBoxContainer);
  2207. tool_settings->add_child(tool_settings_tile_data_toolbar_container);
  2208. tools_settings_erase_button = memnew(Button);
  2209. tools_settings_erase_button->set_flat(true);
  2210. tools_settings_erase_button->set_toggle_mode(true);
  2211. tools_settings_erase_button->set_shortcut(ED_SHORTCUT("tiles_editor/eraser", "Eraser", Key::E));
  2212. tools_settings_erase_button->set_shortcut_context(this);
  2213. tool_settings->add_child(tools_settings_erase_button);
  2214. tool_advanced_menu_buttom = memnew(MenuButton);
  2215. tool_advanced_menu_buttom->set_flat(true);
  2216. tool_advanced_menu_buttom->get_popup()->add_item(TTR("Create Tiles in Non-Transparent Texture Regions"), ADVANCED_AUTO_CREATE_TILES);
  2217. tool_advanced_menu_buttom->get_popup()->add_item(TTR("Remove Tiles in Fully Transparent Texture Regions"), ADVANCED_AUTO_REMOVE_TILES);
  2218. tool_advanced_menu_buttom->get_popup()->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
  2219. toolbox->add_child(tool_advanced_menu_buttom);
  2220. _update_toolbar();
  2221. // Right side of toolbar.
  2222. Control *middle_space = memnew(Control);
  2223. middle_space->set_h_size_flags(SIZE_EXPAND_FILL);
  2224. toolbox->add_child(middle_space);
  2225. tool_tile_id_label = memnew(Label);
  2226. tool_tile_id_label->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  2227. toolbox->add_child(tool_tile_id_label);
  2228. _update_tile_id_label();
  2229. // Tile atlas view.
  2230. tile_atlas_view = memnew(TileAtlasView);
  2231. tile_atlas_view->set_h_size_flags(SIZE_EXPAND_FILL);
  2232. tile_atlas_view->set_v_size_flags(SIZE_EXPAND_FILL);
  2233. tile_atlas_view->connect("transform_changed", callable_mp(TilesEditorPlugin::get_singleton(), &TilesEditorPlugin::set_atlas_view_transform));
  2234. tile_atlas_view->connect("transform_changed", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_view_transform_changed).unbind(2));
  2235. right_panel->add_child(tile_atlas_view);
  2236. base_tile_popup_menu = memnew(PopupMenu);
  2237. base_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete", TTR("Delete"), Key::KEY_DELETE), TILE_DELETE);
  2238. base_tile_popup_menu->add_item(TTR("Create an Alternative Tile"), TILE_CREATE_ALTERNATIVE);
  2239. base_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
  2240. tile_atlas_view->add_child(base_tile_popup_menu);
  2241. empty_base_tile_popup_menu = memnew(PopupMenu);
  2242. empty_base_tile_popup_menu->add_item(TTR("Create a Tile"), TILE_CREATE);
  2243. empty_base_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
  2244. tile_atlas_view->add_child(empty_base_tile_popup_menu);
  2245. tile_atlas_control = memnew(Control);
  2246. tile_atlas_control->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_draw));
  2247. tile_atlas_control->connect("mouse_exited", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_mouse_exited));
  2248. tile_atlas_control->connect("gui_input", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_gui_input));
  2249. tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control);
  2250. tile_atlas_control_unscaled = memnew(Control);
  2251. tile_atlas_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_atlas_control_unscaled_draw));
  2252. tile_atlas_view->add_control_over_atlas_tiles(tile_atlas_control_unscaled, false);
  2253. tile_atlas_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  2254. alternative_tile_popup_menu = memnew(PopupMenu);
  2255. alternative_tile_popup_menu->add_shortcut(ED_SHORTCUT("tiles_editor/delete_tile", TTR("Delete"), Key::KEY_DELETE), TILE_DELETE);
  2256. alternative_tile_popup_menu->connect("id_pressed", callable_mp(this, &TileSetAtlasSourceEditor::_menu_option));
  2257. tile_atlas_view->add_child(alternative_tile_popup_menu);
  2258. alternative_tiles_control = memnew(Control);
  2259. alternative_tiles_control->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_draw));
  2260. alternative_tiles_control->connect("mouse_exited", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_mouse_exited));
  2261. alternative_tiles_control->connect("gui_input", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input));
  2262. tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control);
  2263. alternative_tiles_control_unscaled = memnew(Control);
  2264. alternative_tiles_control_unscaled->connect("draw", callable_mp(this, &TileSetAtlasSourceEditor::_tile_alternatives_control_unscaled_draw));
  2265. tile_atlas_view->add_control_over_alternative_tiles(alternative_tiles_control_unscaled, false);
  2266. alternative_tiles_control_unscaled->set_mouse_filter(Control::MOUSE_FILTER_IGNORE);
  2267. tile_atlas_view_missing_source_label = memnew(Label);
  2268. tile_atlas_view_missing_source_label->set_text(TTR("Add or select an atlas texture to the left panel."));
  2269. tile_atlas_view_missing_source_label->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_CENTER);
  2270. tile_atlas_view_missing_source_label->set_vertical_alignment(VERTICAL_ALIGNMENT_CENTER);
  2271. tile_atlas_view_missing_source_label->set_h_size_flags(SIZE_EXPAND_FILL);
  2272. tile_atlas_view_missing_source_label->set_v_size_flags(SIZE_EXPAND_FILL);
  2273. tile_atlas_view_missing_source_label->hide();
  2274. right_panel->add_child(tile_atlas_view_missing_source_label);
  2275. EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(callable_mp(this, &TileSetAtlasSourceEditor::_undo_redo_inspector_callback));
  2276. // Inspector plugin.
  2277. Ref<EditorInspectorPluginTileData> tile_data_inspector_plugin;
  2278. tile_data_inspector_plugin.instantiate();
  2279. EditorInspector::add_inspector_plugin(tile_data_inspector_plugin);
  2280. }
  2281. TileSetAtlasSourceEditor::~TileSetAtlasSourceEditor() {
  2282. memdelete(tile_proxy_object);
  2283. memdelete(atlas_source_proxy_object);
  2284. }
  2285. ////// EditorPropertyTilePolygon //////
  2286. void EditorPropertyTilePolygon::_add_focusable_children(Node *p_node) {
  2287. Control *control = Object::cast_to<Control>(p_node);
  2288. if (control && control->get_focus_mode() != Control::FOCUS_NONE) {
  2289. add_focusable(control);
  2290. }
  2291. for (int i = 0; i < p_node->get_child_count(); i++) {
  2292. _add_focusable_children(p_node->get_child(i));
  2293. }
  2294. }
  2295. void EditorPropertyTilePolygon::_polygons_changed() {
  2296. if (String(count_property).is_empty()) {
  2297. if (base_type == "OccluderPolygon2D") {
  2298. // Single OccluderPolygon2D.
  2299. Ref<OccluderPolygon2D> occluder;
  2300. if (generic_tile_polygon_editor->get_polygon_count() >= 1) {
  2301. occluder.instantiate();
  2302. occluder->set_polygon(generic_tile_polygon_editor->get_polygon(0));
  2303. }
  2304. emit_changed(get_edited_property(), occluder);
  2305. } else if (base_type == "NavigationPolygon") {
  2306. Ref<NavigationPolygon> navigation_polygon;
  2307. if (generic_tile_polygon_editor->get_polygon_count() >= 1) {
  2308. navigation_polygon.instantiate();
  2309. for (int i = 0; i < generic_tile_polygon_editor->get_polygon_count(); i++) {
  2310. Vector<Vector2> polygon = generic_tile_polygon_editor->get_polygon(i);
  2311. navigation_polygon->add_outline(polygon);
  2312. }
  2313. navigation_polygon->make_polygons_from_outlines();
  2314. }
  2315. emit_changed(get_edited_property(), navigation_polygon);
  2316. }
  2317. } else {
  2318. if (base_type.is_empty()) {
  2319. // Multiple array of vertices.
  2320. Vector<String> changed_properties;
  2321. Array values;
  2322. int count = generic_tile_polygon_editor->get_polygon_count();
  2323. changed_properties.push_back(count_property);
  2324. values.push_back(count);
  2325. for (int i = 0; i < count; i++) {
  2326. changed_properties.push_back(vformat(element_pattern, i));
  2327. values.push_back(generic_tile_polygon_editor->get_polygon(i));
  2328. }
  2329. emit_signal(SNAME("multiple_properties_changed"), changed_properties, values, false);
  2330. }
  2331. }
  2332. }
  2333. void EditorPropertyTilePolygon::update_property() {
  2334. TileSetAtlasSourceEditor::AtlasTileProxyObject *atlas_tile_proxy_object = Object::cast_to<TileSetAtlasSourceEditor::AtlasTileProxyObject>(get_edited_object());
  2335. ERR_FAIL_COND(!atlas_tile_proxy_object);
  2336. ERR_FAIL_COND(atlas_tile_proxy_object->get_edited_tiles().is_empty());
  2337. TileSetAtlasSource *tile_set_atlas_source = atlas_tile_proxy_object->get_edited_tile_set_atlas_source();
  2338. generic_tile_polygon_editor->set_tile_set(Ref<TileSet>(tile_set_atlas_source->get_tile_set()));
  2339. // Set the background
  2340. Vector2i coords = atlas_tile_proxy_object->get_edited_tiles().front()->get().tile;
  2341. int alternative = atlas_tile_proxy_object->get_edited_tiles().front()->get().alternative;
  2342. TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
  2343. generic_tile_polygon_editor->set_background(tile_set_atlas_source->get_texture(), tile_set_atlas_source->get_tile_texture_region(coords), tile_set_atlas_source->get_tile_effective_texture_offset(coords, alternative), tile_data->get_flip_h(), tile_data->get_flip_v(), tile_data->get_transpose(), tile_data->get_modulate());
  2344. // Reset the polygons.
  2345. generic_tile_polygon_editor->clear_polygons();
  2346. if (String(count_property).is_empty()) {
  2347. if (base_type == "OccluderPolygon2D") {
  2348. // Single OccluderPolygon2D.
  2349. Ref<OccluderPolygon2D> occluder = get_edited_object()->get(get_edited_property());
  2350. generic_tile_polygon_editor->clear_polygons();
  2351. if (occluder.is_valid()) {
  2352. generic_tile_polygon_editor->add_polygon(occluder->get_polygon());
  2353. }
  2354. } else if (base_type == "NavigationPolygon") {
  2355. // Single OccluderPolygon2D.
  2356. Ref<NavigationPolygon> navigation_polygon = get_edited_object()->get(get_edited_property());
  2357. generic_tile_polygon_editor->clear_polygons();
  2358. if (navigation_polygon.is_valid()) {
  2359. for (int i = 0; i < navigation_polygon->get_outline_count(); i++) {
  2360. generic_tile_polygon_editor->add_polygon(navigation_polygon->get_outline(i));
  2361. }
  2362. }
  2363. }
  2364. } else {
  2365. int count = get_edited_object()->get(count_property);
  2366. if (base_type.is_empty()) {
  2367. // Multiple array of vertices.
  2368. generic_tile_polygon_editor->clear_polygons();
  2369. for (int i = 0; i < count; i++) {
  2370. generic_tile_polygon_editor->add_polygon(get_edited_object()->get(vformat(element_pattern, i)));
  2371. }
  2372. }
  2373. }
  2374. }
  2375. void EditorPropertyTilePolygon::setup_single_mode(const StringName &p_property, const String &p_base_type) {
  2376. set_object_and_property(nullptr, p_property);
  2377. base_type = p_base_type;
  2378. generic_tile_polygon_editor->set_multiple_polygon_mode(false);
  2379. }
  2380. void EditorPropertyTilePolygon::setup_multiple_mode(const StringName &p_property, const StringName &p_count_property, const String &p_element_pattern, const String &p_base_type) {
  2381. set_object_and_property(nullptr, p_property);
  2382. count_property = p_count_property;
  2383. element_pattern = p_element_pattern;
  2384. base_type = p_base_type;
  2385. generic_tile_polygon_editor->set_multiple_polygon_mode(true);
  2386. }
  2387. EditorPropertyTilePolygon::EditorPropertyTilePolygon() {
  2388. // Setup the polygon editor.
  2389. generic_tile_polygon_editor = memnew(GenericTilePolygonEditor);
  2390. generic_tile_polygon_editor->set_use_undo_redo(false);
  2391. generic_tile_polygon_editor->clear_polygons();
  2392. add_child(generic_tile_polygon_editor);
  2393. generic_tile_polygon_editor->connect("polygons_changed", callable_mp(this, &EditorPropertyTilePolygon::_polygons_changed));
  2394. // Add all focussable children of generic_tile_polygon_editor as focussable.
  2395. _add_focusable_children(generic_tile_polygon_editor);
  2396. }
  2397. ////// EditorInspectorPluginTileData //////
  2398. bool EditorInspectorPluginTileData::can_handle(Object *p_object) {
  2399. return Object::cast_to<TileSetAtlasSourceEditor::AtlasTileProxyObject>(p_object) != nullptr;
  2400. }
  2401. bool EditorInspectorPluginTileData::parse_property(Object *p_object, const Variant::Type p_type, const String &p_path, const PropertyHint p_hint, const String &p_hint_text, const uint32_t p_usage, const bool p_wide) {
  2402. Vector<String> components = String(p_path).split("/", true, 2);
  2403. if (components.size() == 2 && components[0].begins_with("occlusion_layer_") && components[0].trim_prefix("occlusion_layer_").is_valid_int()) {
  2404. // Occlusion layers.
  2405. int layer_index = components[0].trim_prefix("occlusion_layer_").to_int();
  2406. ERR_FAIL_COND_V(layer_index < 0, false);
  2407. if (components[1] == "polygon") {
  2408. EditorPropertyTilePolygon *ep = memnew(EditorPropertyTilePolygon);
  2409. ep->setup_single_mode(p_path, "OccluderPolygon2D");
  2410. add_property_editor(p_path, ep);
  2411. return true;
  2412. }
  2413. } else if (components.size() >= 2 && components[0].begins_with("physics_layer_") && components[0].trim_prefix("physics_layer_").is_valid_int()) {
  2414. // Physics layers.
  2415. int layer_index = components[0].trim_prefix("physics_layer_").to_int();
  2416. ERR_FAIL_COND_V(layer_index < 0, false);
  2417. if (components[1] == "polygons_count") {
  2418. EditorPropertyTilePolygon *ep = memnew(EditorPropertyTilePolygon);
  2419. ep->setup_multiple_mode(vformat("physics_layer_%d/polygons", layer_index), vformat("physics_layer_%d/polygons_count", layer_index), vformat("physics_layer_%d/polygon_%%d/points", layer_index), "");
  2420. Vector<String> properties;
  2421. properties.push_back(p_path);
  2422. int count = p_object->get(vformat("physics_layer_%d/polygons_count", layer_index));
  2423. for (int i = 0; i < count; i++) {
  2424. properties.push_back(vformat(vformat("physics_layer_%d/polygon_%d/points", layer_index, i)));
  2425. }
  2426. add_property_editor_for_multiple_properties("Polygons", properties, ep);
  2427. return true;
  2428. } else if (components.size() == 3 && components[1].begins_with("polygon_") && components[1].trim_prefix("polygon_").is_valid_int()) {
  2429. int polygon_index = components[1].trim_prefix("polygon_").to_int();
  2430. ERR_FAIL_COND_V(polygon_index < 0, false);
  2431. if (components[2] == "points") {
  2432. return true;
  2433. }
  2434. }
  2435. } else if (components.size() == 2 && components[0].begins_with("navigation_layer_") && components[0].trim_prefix("navigation_layer_").is_valid_int()) {
  2436. // Navigation layers.
  2437. int layer_index = components[0].trim_prefix("navigation_layer_").to_int();
  2438. ERR_FAIL_COND_V(layer_index < 0, false);
  2439. if (components[1] == "polygon") {
  2440. EditorPropertyTilePolygon *ep = memnew(EditorPropertyTilePolygon);
  2441. ep->setup_single_mode(p_path, "NavigationPolygon");
  2442. add_property_editor(p_path, ep);
  2443. return true;
  2444. }
  2445. }
  2446. return false;
  2447. }