editor_properties_array_dict.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989
  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, 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_signal("property_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_signal("property_changed", get_edited_property(), array);
  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. if (array.get_type() == Variant::NIL) {
  193. edit->set_text(String("(Nil) ") + arrtype);
  194. edit->set_pressed(false);
  195. if (vbox) {
  196. memdelete(vbox);
  197. }
  198. return;
  199. }
  200. edit->set_text(arrtype + " (size " + itos(array.call("size")) + ")");
  201. #ifdef TOOLS_ENABLED
  202. bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
  203. if (edit->is_pressed() != unfolded) {
  204. edit->set_pressed(unfolded);
  205. }
  206. if (unfolded) {
  207. updating = true;
  208. if (!vbox) {
  209. vbox = memnew(VBoxContainer);
  210. add_child(vbox);
  211. set_bottom_editor(vbox);
  212. HBoxContainer *hbc = memnew(HBoxContainer);
  213. vbox->add_child(hbc);
  214. Label *label = memnew(Label(TTR("Size: ")));
  215. label->set_h_size_flags(SIZE_EXPAND_FILL);
  216. hbc->add_child(label);
  217. length = memnew(EditorSpinSlider);
  218. length->set_step(1);
  219. length->set_max(1000000);
  220. length->set_h_size_flags(SIZE_EXPAND_FILL);
  221. hbc->add_child(length);
  222. length->connect("value_changed", this, "_length_changed");
  223. page_hb = memnew(HBoxContainer);
  224. vbox->add_child(page_hb);
  225. label = memnew(Label(TTR("Page: ")));
  226. label->set_h_size_flags(SIZE_EXPAND_FILL);
  227. page_hb->add_child(label);
  228. page = memnew(EditorSpinSlider);
  229. page->set_step(1);
  230. page_hb->add_child(page);
  231. page->set_h_size_flags(SIZE_EXPAND_FILL);
  232. page->connect("value_changed", this, "_page_changed");
  233. } else {
  234. //bye bye children of the box
  235. while (vbox->get_child_count() > 2) {
  236. memdelete(vbox->get_child(2));
  237. }
  238. }
  239. int len = array.call("size");
  240. length->set_value(len);
  241. int pages = MAX(0, len - 1) / page_len + 1;
  242. page->set_max(pages);
  243. page_idx = MIN(page_idx, pages - 1);
  244. page->set_value(page_idx);
  245. page_hb->set_visible(pages > 1);
  246. int offset = page_idx * page_len;
  247. int amount = MIN(len - offset, page_len);
  248. if (array.get_type() == Variant::ARRAY) {
  249. array = array.call("duplicate");
  250. }
  251. object->set_array(array);
  252. for (int i = 0; i < amount; i++) {
  253. String prop_name = "indices/" + itos(i + offset);
  254. EditorProperty *prop = NULL;
  255. Variant value = array.get(i + offset);
  256. Variant::Type value_type = value.get_type();
  257. if (value_type == Variant::NIL && subtype != Variant::NIL) {
  258. value_type = subtype;
  259. }
  260. if (value_type == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(value)) {
  261. EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID);
  262. editor->setup("Object");
  263. prop = editor;
  264. } else {
  265. prop = EditorInspector::instantiate_property_editor(NULL, value_type, "", subtype_hint, subtype_hint_string, 0);
  266. }
  267. prop->set_object_and_property(object.ptr(), prop_name);
  268. prop->set_label(itos(i + offset));
  269. prop->set_selectable(false);
  270. prop->connect("property_changed", this, "_property_changed");
  271. prop->connect("object_id_selected", this, "_object_id_selected");
  272. if (array.get_type() == Variant::ARRAY) {
  273. HBoxContainer *hb = memnew(HBoxContainer);
  274. vbox->add_child(hb);
  275. hb->add_child(prop);
  276. prop->set_h_size_flags(SIZE_EXPAND_FILL);
  277. Button *edit = memnew(Button);
  278. edit->set_icon(get_icon("Edit", "EditorIcons"));
  279. hb->add_child(edit);
  280. edit->connect("pressed", this, "_change_type", varray(edit, i + offset));
  281. } else {
  282. vbox->add_child(prop);
  283. }
  284. prop->update_property();
  285. }
  286. updating = false;
  287. } else {
  288. if (vbox) {
  289. set_bottom_editor(NULL);
  290. memdelete(vbox);
  291. vbox = NULL;
  292. }
  293. }
  294. #endif
  295. }
  296. void EditorPropertyArray::_notification(int p_what) {
  297. if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
  298. }
  299. }
  300. void EditorPropertyArray::_edit_pressed() {
  301. Variant array = get_edited_object()->get(get_edited_property());
  302. if (!array.is_array()) {
  303. Variant::CallError ce;
  304. array = Variant::construct(array_type, NULL, 0, ce);
  305. get_edited_object()->set(get_edited_property(), array);
  306. }
  307. get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed());
  308. update_property();
  309. }
  310. void EditorPropertyArray::_page_changed(double p_page) {
  311. if (updating)
  312. return;
  313. page_idx = p_page;
  314. update_property();
  315. }
  316. void EditorPropertyArray::_length_changed(double p_page) {
  317. if (updating)
  318. return;
  319. Variant array = object->get_array();
  320. array.call("resize", int(p_page));
  321. emit_signal("property_changed", get_edited_property(), array);
  322. if (array.get_type() == Variant::ARRAY) {
  323. if (subtype != Variant::NIL) {
  324. int size = array.call("size");
  325. for (int i = 0; i < size; i++) {
  326. if (array.get(i).get_type() == Variant::NIL) {
  327. Variant::CallError ce;
  328. array.set(i, Variant::construct(subtype, NULL, 0, ce));
  329. }
  330. }
  331. }
  332. array = array.call("duplicate"); //dupe, so undo/redo works better
  333. }
  334. object->set_array(array);
  335. update_property();
  336. }
  337. void EditorPropertyArray::setup(Variant::Type p_array_type, const String &p_hint_string) {
  338. array_type = p_array_type;
  339. if (array_type == Variant::ARRAY && !p_hint_string.empty()) {
  340. int hint_subtype_seperator = p_hint_string.find(":");
  341. if (hint_subtype_seperator >= 0) {
  342. String subtype_string = p_hint_string.substr(0, hint_subtype_seperator);
  343. int slash_pos = subtype_string.find("/");
  344. if (slash_pos >= 0) {
  345. subtype_hint = PropertyHint(subtype_string.substr(slash_pos + 1, subtype_string.size() - slash_pos - 1).to_int());
  346. subtype_string = subtype_string.substr(0, slash_pos);
  347. }
  348. subtype_hint_string = p_hint_string.substr(hint_subtype_seperator + 1, p_hint_string.size() - hint_subtype_seperator - 1);
  349. subtype = Variant::Type(subtype_string.to_int());
  350. }
  351. }
  352. }
  353. void EditorPropertyArray::_bind_methods() {
  354. ClassDB::bind_method("_edit_pressed", &EditorPropertyArray::_edit_pressed);
  355. ClassDB::bind_method("_page_changed", &EditorPropertyArray::_page_changed);
  356. ClassDB::bind_method("_length_changed", &EditorPropertyArray::_length_changed);
  357. ClassDB::bind_method("_property_changed", &EditorPropertyArray::_property_changed, DEFVAL(false));
  358. ClassDB::bind_method("_change_type", &EditorPropertyArray::_change_type);
  359. ClassDB::bind_method("_change_type_menu", &EditorPropertyArray::_change_type_menu);
  360. ClassDB::bind_method("_object_id_selected", &EditorPropertyArray::_object_id_selected);
  361. }
  362. EditorPropertyArray::EditorPropertyArray() {
  363. object.instance();
  364. page_idx = 0;
  365. page_len = 10;
  366. edit = memnew(Button);
  367. edit->set_flat(true);
  368. edit->set_h_size_flags(SIZE_EXPAND_FILL);
  369. edit->set_clip_text(true);
  370. edit->connect("pressed", this, "_edit_pressed");
  371. edit->set_toggle_mode(true);
  372. add_child(edit);
  373. add_focusable(edit);
  374. vbox = NULL;
  375. page = NULL;
  376. length = NULL;
  377. updating = false;
  378. change_type = memnew(PopupMenu);
  379. add_child(change_type);
  380. change_type->connect("id_pressed", this, "_change_type_menu");
  381. changing_type_idx = -1;
  382. for (int i = 0; i < Variant::VARIANT_MAX; i++) {
  383. String type = Variant::get_type_name(Variant::Type(i));
  384. change_type->add_item(type, i);
  385. }
  386. changing_type_idx = -1;
  387. subtype = Variant::NIL;
  388. subtype_hint = PROPERTY_HINT_NONE;
  389. subtype_hint_string = "";
  390. }
  391. ///////////////////// DICTIONARY ///////////////////////////
  392. void EditorPropertyDictionary::_property_changed(const String &p_prop, Variant p_value, bool changing) {
  393. if (p_prop == "new_item_key") {
  394. object->set_new_item_key(p_value);
  395. } else if (p_prop == "new_item_value") {
  396. object->set_new_item_value(p_value);
  397. } else if (p_prop.begins_with("indices")) {
  398. int idx = p_prop.get_slice("/", 1).to_int();
  399. Dictionary dict = object->get_dict();
  400. Variant key = dict.get_key_at_index(idx);
  401. dict[key] = p_value;
  402. emit_signal("property_changed", get_edited_property(), dict, true);
  403. dict = dict.duplicate(); //dupe, so undo/redo works better
  404. object->set_dict(dict);
  405. }
  406. }
  407. void EditorPropertyDictionary::_change_type(Object *p_button, int p_index) {
  408. Button *button = Object::cast_to<Button>(p_button);
  409. Rect2 rect = button->get_global_rect();
  410. change_type->set_as_minsize();
  411. change_type->set_global_position(rect.position + rect.size - Vector2(change_type->get_combined_minimum_size().x, 0));
  412. change_type->popup();
  413. changing_type_idx = p_index;
  414. }
  415. void EditorPropertyDictionary::_add_key_value() {
  416. // Do not allow nil as valid key. I experienced errors with this
  417. if (object->get_new_item_key().get_type() == Variant::NIL) {
  418. return;
  419. }
  420. Dictionary dict = object->get_dict();
  421. dict[object->get_new_item_key()] = object->get_new_item_value();
  422. object->set_new_item_key(Variant());
  423. object->set_new_item_value(Variant());
  424. emit_signal("property_changed", get_edited_property(), dict);
  425. dict = dict.duplicate(); //dupe, so undo/redo works better
  426. object->set_dict(dict);
  427. update_property();
  428. }
  429. void EditorPropertyDictionary::_change_type_menu(int p_index) {
  430. if (changing_type_idx < 0) {
  431. Variant value;
  432. Variant::CallError ce;
  433. value = Variant::construct(Variant::Type(p_index), NULL, 0, ce);
  434. if (changing_type_idx == -1) {
  435. object->set_new_item_key(value);
  436. } else {
  437. object->set_new_item_value(value);
  438. }
  439. update_property();
  440. return;
  441. }
  442. Dictionary dict = object->get_dict();
  443. if (p_index < Variant::VARIANT_MAX) {
  444. Variant value;
  445. Variant::CallError ce;
  446. value = Variant::construct(Variant::Type(p_index), NULL, 0, ce);
  447. Variant key = dict.get_key_at_index(changing_type_idx);
  448. dict[key] = value;
  449. } else {
  450. Variant key = dict.get_key_at_index(changing_type_idx);
  451. dict.erase(key);
  452. }
  453. emit_signal("property_changed", get_edited_property(), dict);
  454. dict = dict.duplicate(); //dupe, so undo/redo works better
  455. object->set_dict(dict);
  456. update_property();
  457. }
  458. void EditorPropertyDictionary::update_property() {
  459. Variant updated_val = get_edited_object()->get(get_edited_property());
  460. if (updated_val.get_type() == Variant::NIL) {
  461. edit->set_text("Dictionary (Nil)"); //This provides symmetry with the array property.
  462. edit->set_pressed(false);
  463. if (vbox) {
  464. memdelete(vbox);
  465. }
  466. return;
  467. }
  468. Dictionary dict = updated_val;
  469. edit->set_text("Dictionary (size " + itos(dict.size()) + ")");
  470. #ifdef TOOLS_ENABLED
  471. bool unfolded = get_edited_object()->editor_is_section_unfolded(get_edited_property());
  472. if (edit->is_pressed() != unfolded) {
  473. edit->set_pressed(unfolded);
  474. }
  475. if (unfolded) {
  476. updating = true;
  477. if (!vbox) {
  478. vbox = memnew(VBoxContainer);
  479. add_child(vbox);
  480. set_bottom_editor(vbox);
  481. page_hb = memnew(HBoxContainer);
  482. vbox->add_child(page_hb);
  483. Label *label = memnew(Label(TTR("Page: ")));
  484. label->set_h_size_flags(SIZE_EXPAND_FILL);
  485. page_hb->add_child(label);
  486. page = memnew(EditorSpinSlider);
  487. page->set_step(1);
  488. page_hb->add_child(page);
  489. page->set_h_size_flags(SIZE_EXPAND_FILL);
  490. page->connect("value_changed", this, "_page_changed");
  491. } else {
  492. // Queue childs for deletion, delete immediately might cause errors.
  493. for (int i = 1; i < vbox->get_child_count(); i++) {
  494. vbox->get_child(i)->queue_delete();
  495. }
  496. }
  497. int len = dict.size();
  498. int pages = MAX(0, len - 1) / page_len + 1;
  499. page->set_max(pages);
  500. page_idx = MIN(page_idx, pages - 1);
  501. page->set_value(page_idx);
  502. page_hb->set_visible(pages > 1);
  503. int offset = page_idx * page_len;
  504. int amount = MIN(len - offset, page_len);
  505. dict = dict.duplicate();
  506. object->set_dict(dict);
  507. VBoxContainer *add_vbox = NULL;
  508. for (int i = 0; i < amount + 2; i++) {
  509. String prop_name;
  510. Variant key;
  511. Variant value;
  512. if (i < amount) {
  513. prop_name = "indices/" + itos(i + offset);
  514. key = dict.get_key_at_index(i + offset);
  515. value = dict.get_value_at_index(i + offset);
  516. } else if (i == amount) {
  517. prop_name = "new_item_key";
  518. value = object->get_new_item_key();
  519. } else if (i == amount + 1) {
  520. prop_name = "new_item_value";
  521. value = object->get_new_item_value();
  522. }
  523. EditorProperty *prop = NULL;
  524. switch (value.get_type()) {
  525. case Variant::NIL: {
  526. prop = memnew(EditorPropertyNil);
  527. } break;
  528. // atomic types
  529. case Variant::BOOL: {
  530. prop = memnew(EditorPropertyCheck);
  531. } break;
  532. case Variant::INT: {
  533. EditorPropertyInteger *editor = memnew(EditorPropertyInteger);
  534. editor->setup(-100000, 100000, 1, true, true);
  535. prop = editor;
  536. } break;
  537. case Variant::REAL: {
  538. EditorPropertyFloat *editor = memnew(EditorPropertyFloat);
  539. editor->setup(-100000, 100000, 0.001, true, false, true, true);
  540. prop = editor;
  541. } break;
  542. case Variant::STRING: {
  543. prop = memnew(EditorPropertyText);
  544. } break;
  545. // math types
  546. case Variant::VECTOR2: {
  547. EditorPropertyVector2 *editor = memnew(EditorPropertyVector2);
  548. editor->setup(-100000, 100000, 0.001, true);
  549. prop = editor;
  550. } break;
  551. case Variant::RECT2: {
  552. EditorPropertyRect2 *editor = memnew(EditorPropertyRect2);
  553. editor->setup(-100000, 100000, 0.001, true);
  554. prop = editor;
  555. } break;
  556. case Variant::VECTOR3: {
  557. EditorPropertyVector3 *editor = memnew(EditorPropertyVector3);
  558. editor->setup(-100000, 100000, 0.001, true);
  559. prop = editor;
  560. } break;
  561. case Variant::TRANSFORM2D: {
  562. EditorPropertyTransform2D *editor = memnew(EditorPropertyTransform2D);
  563. editor->setup(-100000, 100000, 0.001, true);
  564. prop = editor;
  565. } break;
  566. case Variant::PLANE: {
  567. EditorPropertyPlane *editor = memnew(EditorPropertyPlane);
  568. editor->setup(-100000, 100000, 0.001, true);
  569. prop = editor;
  570. } break;
  571. case Variant::QUAT: {
  572. EditorPropertyQuat *editor = memnew(EditorPropertyQuat);
  573. editor->setup(-100000, 100000, 0.001, true);
  574. prop = editor;
  575. } break;
  576. case Variant::AABB: {
  577. EditorPropertyAABB *editor = memnew(EditorPropertyAABB);
  578. editor->setup(-100000, 100000, 0.001, true);
  579. prop = editor;
  580. } break;
  581. case Variant::BASIS: {
  582. EditorPropertyBasis *editor = memnew(EditorPropertyBasis);
  583. editor->setup(-100000, 100000, 0.001, true);
  584. prop = editor;
  585. } break;
  586. case Variant::TRANSFORM: {
  587. EditorPropertyTransform *editor = memnew(EditorPropertyTransform);
  588. editor->setup(-100000, 100000, 0.001, true);
  589. prop = editor;
  590. } break;
  591. // misc types
  592. case Variant::COLOR: {
  593. prop = memnew(EditorPropertyColor);
  594. } break;
  595. case Variant::NODE_PATH: {
  596. prop = memnew(EditorPropertyNodePath);
  597. } break;
  598. case Variant::_RID: {
  599. prop = memnew(EditorPropertyNil);
  600. } break;
  601. case Variant::OBJECT: {
  602. if (Object::cast_to<EncodedObjectAsID>(value)) {
  603. EditorPropertyObjectID *editor = memnew(EditorPropertyObjectID);
  604. editor->setup("Object");
  605. prop = editor;
  606. } else {
  607. EditorPropertyResource *editor = memnew(EditorPropertyResource);
  608. editor->setup("Resource");
  609. prop = editor;
  610. }
  611. } break;
  612. case Variant::DICTIONARY: {
  613. prop = memnew(EditorPropertyDictionary);
  614. } break;
  615. case Variant::ARRAY: {
  616. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  617. editor->setup(Variant::ARRAY);
  618. prop = editor;
  619. } break;
  620. // arrays
  621. case Variant::POOL_BYTE_ARRAY: {
  622. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  623. editor->setup(Variant::POOL_BYTE_ARRAY);
  624. prop = editor;
  625. } break;
  626. case Variant::POOL_INT_ARRAY: {
  627. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  628. editor->setup(Variant::POOL_INT_ARRAY);
  629. prop = editor;
  630. } break;
  631. case Variant::POOL_REAL_ARRAY: {
  632. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  633. editor->setup(Variant::POOL_REAL_ARRAY);
  634. prop = editor;
  635. } break;
  636. case Variant::POOL_STRING_ARRAY: {
  637. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  638. editor->setup(Variant::POOL_STRING_ARRAY);
  639. prop = editor;
  640. } break;
  641. case Variant::POOL_VECTOR2_ARRAY: {
  642. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  643. editor->setup(Variant::POOL_VECTOR2_ARRAY);
  644. prop = editor;
  645. } break;
  646. case Variant::POOL_VECTOR3_ARRAY: {
  647. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  648. editor->setup(Variant::POOL_VECTOR3_ARRAY);
  649. prop = editor;
  650. } break;
  651. case Variant::POOL_COLOR_ARRAY: {
  652. EditorPropertyArray *editor = memnew(EditorPropertyArray);
  653. editor->setup(Variant::POOL_COLOR_ARRAY);
  654. prop = editor;
  655. } break;
  656. default: {}
  657. }
  658. if (i == amount) {
  659. PanelContainer *pc = memnew(PanelContainer);
  660. vbox->add_child(pc);
  661. Ref<StyleBoxFlat> flat;
  662. flat.instance();
  663. for (int j = 0; j < 4; j++) {
  664. flat->set_default_margin(Margin(j), 2 * EDSCALE);
  665. }
  666. flat->set_bg_color(get_color("prop_subsection", "Editor"));
  667. pc->add_style_override("panel", flat);
  668. add_vbox = memnew(VBoxContainer);
  669. pc->add_child(add_vbox);
  670. }
  671. prop->set_object_and_property(object.ptr(), prop_name);
  672. int change_index = 0;
  673. if (i < amount) {
  674. String cs = key.get_construct_string();
  675. prop->set_label(key.get_construct_string());
  676. prop->set_tooltip(cs);
  677. change_index = i + offset;
  678. } else if (i == amount) {
  679. prop->set_label(TTR("New Key:"));
  680. change_index = -1;
  681. } else if (i == amount + 1) {
  682. prop->set_label(TTR("New Value:"));
  683. change_index = -2;
  684. }
  685. prop->set_selectable(false);
  686. prop->connect("property_changed", this, "_property_changed");
  687. prop->connect("object_id_selected", this, "_object_id_selected");
  688. HBoxContainer *hb = memnew(HBoxContainer);
  689. if (add_vbox) {
  690. add_vbox->add_child(hb);
  691. } else {
  692. vbox->add_child(hb);
  693. }
  694. hb->add_child(prop);
  695. prop->set_h_size_flags(SIZE_EXPAND_FILL);
  696. Button *edit = memnew(Button);
  697. edit->set_icon(get_icon("Edit", "EditorIcons"));
  698. hb->add_child(edit);
  699. edit->connect("pressed", this, "_change_type", varray(edit, change_index));
  700. prop->update_property();
  701. if (i == amount + 1) {
  702. Button *butt_add_item = memnew(Button);
  703. butt_add_item->set_text(TTR("Add Key/Value Pair"));
  704. butt_add_item->connect("pressed", this, "_add_key_value");
  705. add_vbox->add_child(butt_add_item);
  706. }
  707. }
  708. updating = false;
  709. } else {
  710. if (vbox) {
  711. set_bottom_editor(NULL);
  712. memdelete(vbox);
  713. vbox = NULL;
  714. }
  715. }
  716. #endif
  717. }
  718. void EditorPropertyDictionary::_object_id_selected(const String &p_property, ObjectID p_id) {
  719. emit_signal("object_id_selected", p_property, p_id);
  720. }
  721. void EditorPropertyDictionary::_notification(int p_what) {
  722. if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
  723. }
  724. }
  725. void EditorPropertyDictionary::_edit_pressed() {
  726. Variant prop_val = get_edited_object()->get(get_edited_property());
  727. if (prop_val.get_type() == Variant::NIL) {
  728. Variant::CallError ce;
  729. prop_val = Variant::construct(Variant::DICTIONARY, NULL, 0, ce);
  730. get_edited_object()->set(get_edited_property(), prop_val);
  731. }
  732. get_edited_object()->editor_set_section_unfold(get_edited_property(), edit->is_pressed());
  733. update_property();
  734. }
  735. void EditorPropertyDictionary::_page_changed(double p_page) {
  736. if (updating)
  737. return;
  738. page_idx = p_page;
  739. update_property();
  740. }
  741. void EditorPropertyDictionary::_bind_methods() {
  742. ClassDB::bind_method("_edit_pressed", &EditorPropertyDictionary::_edit_pressed);
  743. ClassDB::bind_method("_page_changed", &EditorPropertyDictionary::_page_changed);
  744. ClassDB::bind_method("_property_changed", &EditorPropertyDictionary::_property_changed, DEFVAL(false));
  745. ClassDB::bind_method("_change_type", &EditorPropertyDictionary::_change_type);
  746. ClassDB::bind_method("_change_type_menu", &EditorPropertyDictionary::_change_type_menu);
  747. ClassDB::bind_method("_add_key_value", &EditorPropertyDictionary::_add_key_value);
  748. ClassDB::bind_method("_object_id_selected", &EditorPropertyDictionary::_object_id_selected);
  749. }
  750. EditorPropertyDictionary::EditorPropertyDictionary() {
  751. object.instance();
  752. page_idx = 0;
  753. page_len = 10;
  754. edit = memnew(Button);
  755. edit->set_flat(true);
  756. edit->set_h_size_flags(SIZE_EXPAND_FILL);
  757. edit->set_clip_text(true);
  758. edit->connect("pressed", this, "_edit_pressed");
  759. edit->set_toggle_mode(true);
  760. add_child(edit);
  761. add_focusable(edit);
  762. vbox = NULL;
  763. page = NULL;
  764. updating = false;
  765. change_type = memnew(PopupMenu);
  766. add_child(change_type);
  767. change_type->connect("id_pressed", this, "_change_type_menu");
  768. changing_type_idx = -1;
  769. for (int i = 0; i < Variant::VARIANT_MAX; i++) {
  770. String type = Variant::get_type_name(Variant::Type(i));
  771. change_type->add_item(type, i);
  772. }
  773. change_type->add_separator();
  774. change_type->add_item(TTR("Remove Item"), Variant::VARIANT_MAX);
  775. changing_type_idx = -1;
  776. }