editor_properties_array_dict.cpp 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006
  1. /*************************************************************************/
  2. /* editor_properties_array_dict.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2019 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 "editor_properties_array_dict.h"
  31. #include "core/io/marshalls.h"
  32. #include "editor/editor_scale.h"
  33. #include "editor_properties.h"
  34. bool EditorPropertyArrayObject::_set(const StringName &p_name, const Variant &p_value) {
  35. String pn = p_name;
  36. if (pn.begins_with("indices")) {
  37. int idx = pn.get_slicec('/', 1).to_int();
  38. array.set(idx, p_value);
  39. return true;
  40. }
  41. return false;
  42. }
  43. bool EditorPropertyArrayObject::_get(const StringName &p_name, Variant &r_ret) const {
  44. String pn = p_name;
  45. if (pn.begins_with("indices")) {
  46. int idx = pn.get_slicec('/', 1).to_int();
  47. bool valid;
  48. r_ret = array.get(idx, &valid);
  49. if (r_ret.get_type() == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(r_ret)) {
  50. r_ret = Object::cast_to<EncodedObjectAsID>(r_ret)->get_object_id();
  51. }
  52. return valid;
  53. }
  54. return false;
  55. }
  56. void EditorPropertyArrayObject::set_array(const Variant &p_array) {
  57. array = p_array;
  58. }
  59. Variant EditorPropertyArrayObject::get_array() {
  60. return array;
  61. }
  62. EditorPropertyArrayObject::EditorPropertyArrayObject() {
  63. }
  64. ///////////////////
  65. bool EditorPropertyDictionaryObject::_set(const StringName &p_name, const Variant &p_value) {
  66. String pn = p_name;
  67. if (pn == "new_item_key") {
  68. new_item_key = p_value;
  69. return true;
  70. }
  71. if (pn == "new_item_value") {
  72. new_item_value = p_value;
  73. return true;
  74. }
  75. if (pn.begins_with("indices")) {
  76. int idx = pn.get_slicec('/', 1).to_int();
  77. Variant key = dict.get_key_at_index(idx);
  78. dict[key] = p_value;
  79. return true;
  80. }
  81. return false;
  82. }
  83. bool EditorPropertyDictionaryObject::_get(const StringName &p_name, Variant &r_ret) const {
  84. String pn = p_name;
  85. if (pn == "new_item_key") {
  86. r_ret = new_item_key;
  87. return true;
  88. }
  89. if (pn == "new_item_value") {
  90. r_ret = new_item_value;
  91. return true;
  92. }
  93. if (pn.begins_with("indices")) {
  94. int idx = pn.get_slicec('/', 1).to_int();
  95. Variant key = dict.get_key_at_index(idx);
  96. r_ret = dict[key];
  97. if (r_ret.get_type() == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(r_ret)) {
  98. r_ret = Object::cast_to<EncodedObjectAsID>(r_ret)->get_object_id();
  99. }
  100. return true;
  101. }
  102. return false;
  103. }
  104. void EditorPropertyDictionaryObject::set_dict(const Dictionary &p_dict) {
  105. dict = p_dict;
  106. }
  107. Dictionary EditorPropertyDictionaryObject::get_dict() {
  108. return dict;
  109. }
  110. void EditorPropertyDictionaryObject::set_new_item_key(const Variant &p_new_item) {
  111. new_item_key = p_new_item;
  112. }
  113. Variant EditorPropertyDictionaryObject::get_new_item_key() {
  114. return new_item_key;
  115. }
  116. void EditorPropertyDictionaryObject::set_new_item_value(const Variant &p_new_item) {
  117. new_item_value = p_new_item;
  118. }
  119. Variant EditorPropertyDictionaryObject::get_new_item_value() {
  120. return new_item_value;
  121. }
  122. EditorPropertyDictionaryObject::EditorPropertyDictionaryObject() {
  123. }
  124. ///////////////////// ARRAY ///////////////////////////
  125. void EditorPropertyArray::_property_changed(const String &p_prop, Variant p_value, const String &p_name, bool changing) {
  126. if (p_prop.begins_with("indices")) {
  127. int idx = p_prop.get_slice("/", 1).to_int();
  128. Variant array = object->get_array();
  129. array.set(idx, p_value);
  130. emit_changed(get_edited_property(), array, "", true);
  131. if (array.get_type() == Variant::ARRAY) {
  132. array = array.call("duplicate"); //dupe, so undo/redo works better
  133. }
  134. object->set_array(array);
  135. }
  136. }
  137. void EditorPropertyArray::_change_type(Object *p_button, int p_index) {
  138. Button *button = Object::cast_to<Button>(p_button);
  139. Rect2 rect = button->get_global_rect();
  140. change_type->set_as_minsize();
  141. change_type->set_global_position(rect.position + rect.size - Vector2(change_type->get_combined_minimum_size().x, 0));
  142. change_type->popup();
  143. changing_type_idx = p_index;
  144. }
  145. void EditorPropertyArray::_change_type_menu(int p_index) {
  146. Variant value;
  147. Variant::CallError ce;
  148. value = Variant::construct(Variant::Type(p_index), NULL, 0, ce);
  149. Variant array = object->get_array();
  150. array.set(changing_type_idx, value);
  151. emit_changed(get_edited_property(), array, "", true);
  152. if (array.get_type() == Variant::ARRAY) {
  153. array = array.call("duplicate"); //dupe, so undo/redo works better
  154. }
  155. object->set_array(array);
  156. update_property();
  157. }
  158. void EditorPropertyArray::_object_id_selected(const String &p_property, ObjectID p_id) {
  159. emit_signal("object_id_selected", p_property, p_id);
  160. }
  161. void EditorPropertyArray::update_property() {
  162. Variant array = get_edited_object()->get(get_edited_property());
  163. String arrtype = "";
  164. switch (array_type) {
  165. case Variant::ARRAY: {
  166. arrtype = "Array";
  167. } break;
  168. // arrays
  169. case Variant::POOL_BYTE_ARRAY: {
  170. arrtype = "PoolByteArray";
  171. } break;
  172. case Variant::POOL_INT_ARRAY: {
  173. arrtype = "PoolIntArray";
  174. } break;
  175. case Variant::POOL_REAL_ARRAY: {
  176. arrtype = "PoolFloatArray";
  177. } break;
  178. case Variant::POOL_STRING_ARRAY: {
  179. arrtype = "PoolStringArray";
  180. } break;
  181. case Variant::POOL_VECTOR2_ARRAY: {
  182. arrtype = "PoolVector2Array";
  183. } break;
  184. case Variant::POOL_VECTOR3_ARRAY: {
  185. arrtype = "PoolVector3Array";
  186. } break;
  187. case Variant::POOL_COLOR_ARRAY: {
  188. arrtype = "PoolColorArray";
  189. } break;
  190. default: {
  191. }
  192. }
  193. if (array.get_type() == Variant::NIL) {
  194. edit->set_text(String("(Nil) ") + arrtype);
  195. edit->set_pressed(false);
  196. if (vbox) {
  197. memdelete(vbox);
  198. }
  199. return;
  200. }
  201. edit->set_text(arrtype + " (size " + itos(array.call("size")) + ")");
  202. #ifdef TOOLS_ENABLED
  203. bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
  204. if (edit->is_pressed() != unfolded) {
  205. edit->set_pressed(unfolded);
  206. }
  207. if (unfolded) {
  208. updating = true;
  209. if (!vbox) {
  210. vbox = memnew(VBoxContainer);
  211. add_child(vbox);
  212. set_bottom_editor(vbox);
  213. HBoxContainer *hbc = memnew(HBoxContainer);
  214. vbox->add_child(hbc);
  215. Label *label = memnew(Label(TTR("Size: ")));
  216. label->set_h_size_flags(SIZE_EXPAND_FILL);
  217. hbc->add_child(label);
  218. length = memnew(EditorSpinSlider);
  219. length->set_step(1);
  220. length->set_max(1000000);
  221. length->set_h_size_flags(SIZE_EXPAND_FILL);
  222. hbc->add_child(length);
  223. length->connect("value_changed", this, "_length_changed");
  224. page_hb = memnew(HBoxContainer);
  225. vbox->add_child(page_hb);
  226. label = memnew(Label(TTR("Page: ")));
  227. label->set_h_size_flags(SIZE_EXPAND_FILL);
  228. page_hb->add_child(label);
  229. page = memnew(EditorSpinSlider);
  230. page->set_step(1);
  231. page_hb->add_child(page);
  232. page->set_h_size_flags(SIZE_EXPAND_FILL);
  233. page->connect("value_changed", this, "_page_changed");
  234. } else {
  235. //bye bye children of the box
  236. while (vbox->get_child_count() > 2) {
  237. memdelete(vbox->get_child(2));
  238. }
  239. }
  240. int len = array.call("size");
  241. length->set_value(len);
  242. int pages = MAX(0, len - 1) / page_len + 1;
  243. page->set_max(pages);
  244. page_idx = MIN(page_idx, pages - 1);
  245. page->set_value(page_idx);
  246. page_hb->set_visible(pages > 1);
  247. int offset = page_idx * page_len;
  248. int amount = MIN(len - offset, page_len);
  249. if (array.get_type() == Variant::ARRAY) {
  250. array = array.call("duplicate");
  251. }
  252. object->set_array(array);
  253. for (int i = 0; i < amount; i++) {
  254. String prop_name = "indices/" + itos(i + offset);
  255. EditorProperty *prop = NULL;
  256. Variant value = array.get(i + offset);
  257. Variant::Type value_type = value.get_type();
  258. if (value_type == Variant::NIL && subtype != Variant::NIL) {
  259. value_type = subtype;
  260. }
  261. if (value_type == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(value)) {
  262. EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID);
  263. editor->setup("Object");
  264. prop = editor;
  265. } else {
  266. prop = EditorInspector::instantiate_property_editor(NULL, value_type, "", subtype_hint, subtype_hint_string, 0);
  267. }
  268. prop->set_object_and_property(object.ptr(), prop_name);
  269. prop->set_label(itos(i + offset));
  270. prop->set_selectable(false);
  271. prop->connect("property_changed", this, "_property_changed");
  272. prop->connect("object_id_selected", this, "_object_id_selected");
  273. if (array.get_type() == Variant::ARRAY) {
  274. HBoxContainer *hb = memnew(HBoxContainer);
  275. vbox->add_child(hb);
  276. hb->add_child(prop);
  277. prop->set_h_size_flags(SIZE_EXPAND_FILL);
  278. if (subtype == Variant::NIL) {
  279. Button *edit = memnew(Button);
  280. edit->set_icon(get_icon("Edit", "EditorIcons"));
  281. hb->add_child(edit);
  282. edit->connect("pressed", this, "_change_type", varray(edit, i + offset));
  283. }
  284. } else {
  285. vbox->add_child(prop);
  286. }
  287. prop->update_property();
  288. }
  289. updating = false;
  290. } else {
  291. if (vbox) {
  292. set_bottom_editor(NULL);
  293. memdelete(vbox);
  294. vbox = NULL;
  295. }
  296. }
  297. #endif
  298. }
  299. void EditorPropertyArray::_notification(int p_what) {
  300. if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
  301. }
  302. }
  303. void EditorPropertyArray::_edit_pressed() {
  304. Variant array = get_edited_object()->get(get_edited_property());
  305. if (!array.is_array()) {
  306. Variant::CallError ce;
  307. array = Variant::construct(array_type, NULL, 0, ce);
  308. get_edited_object()->set(get_edited_property(), array);
  309. }
  310. get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed());
  311. update_property();
  312. }
  313. void EditorPropertyArray::_page_changed(double p_page) {
  314. if (updating)
  315. return;
  316. page_idx = p_page;
  317. update_property();
  318. }
  319. void EditorPropertyArray::_length_changed(double p_page) {
  320. if (updating)
  321. return;
  322. Variant array = object->get_array();
  323. int previous_size = array.call("size");
  324. array.call("resize", int(p_page));
  325. if (array.get_type() == Variant::ARRAY) {
  326. if (subtype != Variant::NIL) {
  327. int size = array.call("size");
  328. for (int i = previous_size; i < size; i++) {
  329. if (array.get(i).get_type() == Variant::NIL) {
  330. Variant::CallError ce;
  331. array.set(i, Variant::construct(subtype, NULL, 0, ce));
  332. }
  333. }
  334. }
  335. array = array.call("duplicate"); //dupe, so undo/redo works better
  336. } else {
  337. int size = array.call("size");
  338. // Pool*Array don't initialize their elements, have to do it manually
  339. for (int i = previous_size; i < size; i++) {
  340. Variant::CallError ce;
  341. array.set(i, Variant::construct(array.get(i).get_type(), NULL, 0, ce));
  342. }
  343. }
  344. emit_changed(get_edited_property(), array, "", false);
  345. object->set_array(array);
  346. update_property();
  347. }
  348. void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint_string) {
  349. array_type = p_array_type;
  350. if (array_type == Variant::ARRAY && !p_hint_string.empty()) {
  351. int hint_subtype_seperator = p_hint_string.find(":");
  352. if (hint_subtype_seperator >= 0) {
  353. String subtype_string = p_hint_string.substr(0, hint_subtype_seperator);
  354. int slash_pos = subtype_string.find("/");
  355. if (slash_pos >= 0) {
  356. subtype_hint = PropertyHint(subtype_string.substr(slash_pos + 1, subtype_string.size() - slash_pos - 1).to_int());
  357. subtype_string = subtype_string.substr(0, slash_pos);
  358. }
  359. subtype_hint_string = p_hint_string.substr(hint_subtype_seperator + 1, p_hint_string.size() - hint_subtype_seperator - 1);
  360. subtype = Variant::Type(subtype_string.to_int());
  361. }
  362. }
  363. }
  364. void EditorPropertyArray::_bind_methods() {
  365. ClassDB::bind_method("_edit_pressed", &EditorPropertyArray::_edit_pressed);
  366. ClassDB::bind_method("_page_changed", &EditorPropertyArray::_page_changed);
  367. ClassDB::bind_method("_length_changed", &EditorPropertyArray::_length_changed);
  368. ClassDB::bind_method("_property_changed", &EditorPropertyArray::_property_changed, DEFVAL(String()), DEFVAL(false));
  369. ClassDB::bind_method("_change_type", &EditorPropertyArray::_change_type);
  370. ClassDB::bind_method("_change_type_menu", &EditorPropertyArray::_change_type_menu);
  371. ClassDB::bind_method("_object_id_selected", &EditorPropertyArray::_object_id_selected);
  372. }
  373. EditorPropertyArray::EditorPropertyArray() {
  374. object.instance();
  375. page_idx = 0;
  376. page_len = 10;
  377. edit = memnew(Button);
  378. edit->set_flat(true);
  379. edit->set_h_size_flags(SIZE_EXPAND_FILL);
  380. edit->set_clip_text(true);
  381. edit->connect("pressed", this, "_edit_pressed");
  382. edit->set_toggle_mode(true);
  383. add_child(edit);
  384. add_focusable(edit);
  385. vbox = NULL;
  386. page = NULL;
  387. length = NULL;
  388. updating = false;
  389. change_type = memnew(PopupMenu);
  390. add_child(change_type);
  391. change_type->connect("id_pressed", this, "_change_type_menu");
  392. changing_type_idx = -1;
  393. for (int i = 0; i < Variant::VARIANT_MAX; i++) {
  394. String type = Variant::get_type_name(Variant::Type(i));
  395. change_type->add_item(type, i);
  396. }
  397. changing_type_idx = -1;
  398. subtype = Variant::NIL;
  399. subtype_hint = PROPERTY_HINT_NONE;
  400. subtype_hint_string = "";
  401. }
  402. ///////////////////// DICTIONARY ///////////////////////////
  403. void EditorPropertyDictionary::_property_changed(const String &p_prop, Variant p_value, const String &p_name, bool changing) {
  404. if (p_prop == "new_item_key") {
  405. object->set_new_item_key(p_value);
  406. } else if (p_prop == "new_item_value") {
  407. object->set_new_item_value(p_value);
  408. } else if (p_prop.begins_with("indices")) {
  409. int idx = p_prop.get_slice("/", 1).to_int();
  410. Dictionary dict = object->get_dict();
  411. Variant key = dict.get_key_at_index(idx);
  412. dict[key] = p_value;
  413. emit_changed(get_edited_property(), dict, "", true);
  414. dict = dict.duplicate(); //dupe, so undo/redo works better
  415. object->set_dict(dict);
  416. }
  417. }
  418. void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) {
  419. Button *button = Object::cast_to<Button>(p_button);
  420. Rect2 rect = button->get_global_rect();
  421. change_type->set_as_minsize();
  422. change_type->set_global_position(rect.position + rect.size - Vector2(change_type->get_combined_minimum_size().x, 0));
  423. change_type->popup();
  424. changing_type_idx = p_index;
  425. }
  426. void EditorPropertyDictionary::_add_key_value() {
  427. // Do not allow nil as valid key. I experienced errors with this
  428. if (object->get_new_item_key().get_type() == Variant::NIL) {
  429. return;
  430. }
  431. Dictionary dict = object->get_dict();
  432. dict[object->get_new_item_key()] = object->get_new_item_value();
  433. object->set_new_item_key(Variant());
  434. object->set_new_item_value(Variant());
  435. emit_changed(get_edited_property(), dict, "", false);
  436. dict = dict.duplicate(); //dupe, so undo/redo works better
  437. object->set_dict(dict);
  438. update_property();
  439. }
  440. void EditorPropertyDictionary::_change_type_menu(int p_index) {
  441. if (changing_type_idx < 0) {
  442. Variant value;
  443. Variant::CallError ce;
  444. value = Variant::construct(Variant::Type(p_index), NULL, 0, ce);
  445. if (changing_type_idx == -1) {
  446. object->set_new_item_key(value);
  447. } else {
  448. object->set_new_item_value(value);
  449. }
  450. update_property();
  451. return;
  452. }
  453. Dictionary dict = object->get_dict();
  454. if (p_index < Variant::VARIANT_MAX) {
  455. Variant value;
  456. Variant::CallError ce;
  457. value = Variant::construct(Variant::Type(p_index), NULL, 0, ce);
  458. Variant key = dict.get_key_at_index(changing_type_idx);
  459. dict[key] = value;
  460. } else {
  461. Variant key = dict.get_key_at_index(changing_type_idx);
  462. dict.erase(key);
  463. }
  464. emit_changed(get_edited_property(), dict, "", false);
  465. dict = dict.duplicate(); //dupe, so undo/redo works better
  466. object->set_dict(dict);
  467. update_property();
  468. }
  469. void EditorPropertyDictionary::update_property() {
  470. Variant updated_val = get_edited_object()->get(get_edited_property());
  471. if (updated_val.get_type() == Variant::NIL) {
  472. edit->set_text("Dictionary (Nil)"); //This provides symmetry with the array property.
  473. edit->set_pressed(false);
  474. if (vbox) {
  475. memdelete(vbox);
  476. }
  477. return;
  478. }
  479. Dictionary dict = updated_val;
  480. edit->set_text("Dictionary (size " + itos(dict.size()) + ")");
  481. #ifdef TOOLS_ENABLED
  482. bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
  483. if (edit->is_pressed() != unfolded) {
  484. edit->set_pressed(unfolded);
  485. }
  486. if (unfolded) {
  487. updating = true;
  488. if (!vbox) {
  489. vbox = memnew(VBoxContainer);
  490. add_child(vbox);
  491. set_bottom_editor(vbox);
  492. page_hb = memnew(HBoxContainer);
  493. vbox->add_child(page_hb);
  494. Label *label = memnew(Label(TTR("Page: ")));
  495. label->set_h_size_flags(SIZE_EXPAND_FILL);
  496. page_hb->add_child(label);
  497. page = memnew(EditorSpinSlider);
  498. page->set_step(1);
  499. page_hb->add_child(page);
  500. page->set_h_size_flags(SIZE_EXPAND_FILL);
  501. page->connect("value_changed", this, "_page_changed");
  502. } else {
  503. // Queue childs for deletion, delete immediately might cause errors.
  504. for (int i = 1; i < vbox->get_child_count(); i++) {
  505. vbox->get_child(i)->queue_delete();
  506. }
  507. }
  508. int len = dict.size();
  509. int pages = MAX(0, len - 1) / page_len + 1;
  510. page->set_max(pages);
  511. page_idx = MIN(page_idx, pages - 1);
  512. page->set_value(page_idx);
  513. page_hb->set_visible(pages > 1);
  514. int offset = page_idx * page_len;
  515. int amount = MIN(len - offset, page_len);
  516. dict = dict.duplicate();
  517. object->set_dict(dict);
  518. VBoxContainer *add_vbox = NULL;
  519. for (int i = 0; i < amount + 2; i++) {
  520. String prop_name;
  521. Variant key;
  522. Variant value;
  523. if (i < amount) {
  524. prop_name = "indices/" + itos(i + offset);
  525. key = dict.get_key_at_index(i + offset);
  526. value = dict.get_value_at_index(i + offset);
  527. } else if (i == amount) {
  528. prop_name = "new_item_key";
  529. value = object->get_new_item_key();
  530. } else if (i == amount + 1) {
  531. prop_name = "new_item_value";
  532. value = object->get_new_item_value();
  533. }
  534. EditorProperty *prop = NULL;
  535. switch (value.get_type()) {
  536. case Variant::NIL: {
  537. prop = memnew(EditorPropertyNil);
  538. } break;
  539. // atomic types
  540. case Variant::BOOL: {
  541. prop = memnew(EditorPropertyCheck);
  542. } break;
  543. case Variant::INT: {
  544. EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
  545. editor->setup(-100000, 100000, 1, true, true);
  546. prop = editor;
  547. } break;
  548. case Variant::REAL: {
  549. EditorPropertyFloat *editor = memnew(EditorPropertyFloat);
  550. editor->setup(-100000, 100000, 0.001, true, false, true, true);
  551. prop = editor;
  552. } break;
  553. case Variant::STRING: {
  554. prop = memnew(EditorPropertyText);
  555. } break;
  556. // math types
  557. case Variant::VECTOR2: {
  558. EditorPropertyVector2 *editor = memnew(EditorPropertyVector2);
  559. editor->setup(-100000, 100000, 0.001, true);
  560. prop = editor;
  561. } break;
  562. case Variant::RECT2: {
  563. EditorPropertyRect2 *editor = memnew(EditorPropertyRect2);
  564. editor->setup(-100000, 100000, 0.001, true);
  565. prop = editor;
  566. } break;
  567. case Variant::VECTOR3: {
  568. EditorPropertyVector3 *editor = memnew(EditorPropertyVector3);
  569. editor->setup(-100000, 100000, 0.001, true);
  570. prop = editor;
  571. } break;
  572. case Variant::TRANSFORM2D: {
  573. EditorPropertyTransform2D *editor = memnew(EditorPropertyTransform2D);
  574. editor->setup(-100000, 100000, 0.001, true);
  575. prop = editor;
  576. } break;
  577. case Variant::PLANE: {
  578. EditorPropertyPlane *editor = memnew(EditorPropertyPlane);
  579. editor->setup(-100000, 100000, 0.001, true);
  580. prop = editor;
  581. } break;
  582. case Variant::QUAT: {
  583. EditorPropertyQuat *editor = memnew(EditorPropertyQuat);
  584. editor->setup(-100000, 100000, 0.001, true);
  585. prop = editor;
  586. } break;
  587. case Variant::AABB: {
  588. EditorPropertyAABB *editor = memnew(EditorPropertyAABB);
  589. editor->setup(-100000, 100000, 0.001, true);
  590. prop = editor;
  591. } break;
  592. case Variant::BASIS: {
  593. EditorPropertyBasis *editor = memnew(EditorPropertyBasis);
  594. editor->setup(-100000, 100000, 0.001, true);
  595. prop = editor;
  596. } break;
  597. case Variant::TRANSFORM: {
  598. EditorPropertyTransform *editor = memnew(EditorPropertyTransform);
  599. editor->setup(-100000, 100000, 0.001, true);
  600. prop = editor;
  601. } break;
  602. // misc types
  603. case Variant::COLOR: {
  604. prop = memnew(EditorPropertyColor);
  605. } break;
  606. case Variant::NODE_PATH: {
  607. prop = memnew(EditorPropertyNodePath);
  608. } break;
  609. case Variant::_RID: {
  610. prop = memnew(EditorPropertyNil);
  611. } break;
  612. case Variant::OBJECT: {
  613. if (Object::cast_to<EncodedObjectAsID>(value)) {
  614. EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID);
  615. editor->setup("Object");
  616. prop = editor;
  617. } else {
  618. EditorPropertyResource *editor = memnew(EditorPropertyResource);
  619. editor->setup("Resource");
  620. prop = editor;
  621. }
  622. } break;
  623. case Variant::DICTIONARY: {
  624. prop = memnew(EditorPropertyDictionary);
  625. } break;
  626. case Variant::ARRAY: {
  627. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  628. editor->setup(Variant::ARRAY);
  629. prop = editor;
  630. } break;
  631. // arrays
  632. case Variant::POOL_BYTE_ARRAY: {
  633. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  634. editor->setup(Variant::POOL_BYTE_ARRAY);
  635. prop = editor;
  636. } break;
  637. case Variant::POOL_INT_ARRAY: {
  638. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  639. editor->setup(Variant::POOL_INT_ARRAY);
  640. prop = editor;
  641. } break;
  642. case Variant::POOL_REAL_ARRAY: {
  643. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  644. editor->setup(Variant::POOL_REAL_ARRAY);
  645. prop = editor;
  646. } break;
  647. case Variant::POOL_STRING_ARRAY: {
  648. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  649. editor->setup(Variant::POOL_STRING_ARRAY);
  650. prop = editor;
  651. } break;
  652. case Variant::POOL_VECTOR2_ARRAY: {
  653. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  654. editor->setup(Variant::POOL_VECTOR2_ARRAY);
  655. prop = editor;
  656. } break;
  657. case Variant::POOL_VECTOR3_ARRAY: {
  658. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  659. editor->setup(Variant::POOL_VECTOR3_ARRAY);
  660. prop = editor;
  661. } break;
  662. case Variant::POOL_COLOR_ARRAY: {
  663. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  664. editor->setup(Variant::POOL_COLOR_ARRAY);
  665. prop = editor;
  666. } break;
  667. default: {
  668. }
  669. }
  670. if (i == amount) {
  671. PanelContainer *pc = memnew(PanelContainer);
  672. vbox->add_child(pc);
  673. Ref<StyleBoxFlat> flat;
  674. flat.instance();
  675. for (int j = 0; j < 4; j++) {
  676. flat->set_default_margin(Margin(j), 2 * EDSCALE);
  677. }
  678. flat->set_bg_color(get_color("prop_subsection", "Editor"));
  679. pc->add_style_override("panel", flat);
  680. add_vbox = memnew(VBoxContainer);
  681. pc->add_child(add_vbox);
  682. }
  683. prop->set_object_and_property(object.ptr(), prop_name);
  684. int change_index = 0;
  685. if (i < amount) {
  686. String cs = key.get_construct_string();
  687. prop->set_label(key.get_construct_string());
  688. prop->set_tooltip(cs);
  689. change_index = i + offset;
  690. } else if (i == amount) {
  691. prop->set_label(TTR("New Key:"));
  692. change_index = -1;
  693. } else if (i == amount + 1) {
  694. prop->set_label(TTR("New Value:"));
  695. change_index = -2;
  696. }
  697. prop->set_selectable(false);
  698. prop->connect("property_changed", this, "_property_changed");
  699. prop->connect("object_id_selected", this, "_object_id_selected");
  700. HBoxContainer *hb = memnew(HBoxContainer);
  701. if (add_vbox) {
  702. add_vbox->add_child(hb);
  703. } else {
  704. vbox->add_child(hb);
  705. }
  706. hb->add_child(prop);
  707. prop->set_h_size_flags(SIZE_EXPAND_FILL);
  708. Button *edit = memnew(Button);
  709. edit->set_icon(get_icon("Edit", "EditorIcons"));
  710. hb->add_child(edit);
  711. edit->connect("pressed", this, "_change_type", varray(edit, change_index));
  712. prop->update_property();
  713. if (i == amount + 1) {
  714. Button *butt_add_item = memnew(Button);
  715. butt_add_item->set_text(TTR("Add Key/Value Pair"));
  716. butt_add_item->connect("pressed", this, "_add_key_value");
  717. add_vbox->add_child(butt_add_item);
  718. }
  719. }
  720. updating = false;
  721. } else {
  722. if (vbox) {
  723. set_bottom_editor(NULL);
  724. memdelete(vbox);
  725. vbox = NULL;
  726. }
  727. }
  728. #endif
  729. }
  730. void EditorPropertyDictionary::_object_id_selected(const String &p_property, ObjectID p_id) {
  731. emit_signal("object_id_selected", p_property, p_id);
  732. }
  733. void EditorPropertyDictionary::_notification(int p_what) {
  734. if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
  735. }
  736. }
  737. void EditorPropertyDictionary::_edit_pressed() {
  738. Variant prop_val = get_edited_object()->get(get_edited_property());
  739. if (prop_val.get_type() == Variant::NIL) {
  740. Variant::CallError ce;
  741. prop_val = Variant::construct(Variant::DICTIONARY, NULL, 0, ce);
  742. get_edited_object()->set(get_edited_property(), prop_val);
  743. }
  744. get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed());
  745. update_property();
  746. }
  747. void EditorPropertyDictionary::_page_changed(double p_page) {
  748. if (updating)
  749. return;
  750. page_idx = p_page;
  751. update_property();
  752. }
  753. void EditorPropertyDictionary::_bind_methods() {
  754. ClassDB::bind_method("_edit_pressed", &EditorPropertyDictionary::_edit_pressed);
  755. ClassDB::bind_method("_page_changed", &EditorPropertyDictionary::_page_changed);
  756. ClassDB::bind_method("_property_changed", &EditorPropertyDictionary::_property_changed, DEFVAL(String()), DEFVAL(false));
  757. ClassDB::bind_method("_change_type", &EditorPropertyDictionary::_change_type);
  758. ClassDB::bind_method("_change_type_menu", &EditorPropertyDictionary::_change_type_menu);
  759. ClassDB::bind_method("_add_key_value", &EditorPropertyDictionary::_add_key_value);
  760. ClassDB::bind_method("_object_id_selected", &EditorPropertyDictionary::_object_id_selected);
  761. }
  762. EditorPropertyDictionary::EditorPropertyDictionary() {
  763. object.instance();
  764. page_idx = 0;
  765. page_len = 10;
  766. edit = memnew(Button);
  767. edit->set_flat(true);
  768. edit->set_h_size_flags(SIZE_EXPAND_FILL);
  769. edit->set_clip_text(true);
  770. edit->connect("pressed", this, "_edit_pressed");
  771. edit->set_toggle_mode(true);
  772. add_child(edit);
  773. add_focusable(edit);
  774. vbox = NULL;
  775. page = NULL;
  776. updating = false;
  777. change_type = memnew(PopupMenu);
  778. add_child(change_type);
  779. change_type->connect("id_pressed", this, "_change_type_menu");
  780. changing_type_idx = -1;
  781. for (int i = 0; i < Variant::VARIANT_MAX; i++) {
  782. String type = Variant::get_type_name(Variant::Type(i));
  783. change_type->add_item(type, i);
  784. }
  785. change_type->add_separator();
  786. change_type->add_item(TTR("Remove Item"), Variant::VARIANT_MAX);
  787. changing_type_idx = -1;
  788. }