editor_inspector.cpp 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289
  1. /*************************************************************************/
  2. /* editor_inspector.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_inspector.h"
  31. #include "array_property_edit.h"
  32. #include "dictionary_property_edit.h"
  33. #include "editor_node.h"
  34. #include "editor_scale.h"
  35. #include "multi_node_edit.h"
  36. #include "scene/resources/packed_scene.h"
  37. Size2 EditorProperty::get_minimum_size() const {
  38. Size2 ms;
  39. Ref<Font> font = get_font("font", "Tree");
  40. ms.height = font->get_height();
  41. for (int i = 0; i < get_child_count(); i++) {
  42. Control *c = Object::cast_to<Control>(get_child(i));
  43. if (!c)
  44. continue;
  45. if (c->is_set_as_toplevel())
  46. continue;
  47. if (!c->is_visible())
  48. continue;
  49. if (c == bottom_editor)
  50. continue;
  51. Size2 minsize = c->get_combined_minimum_size();
  52. ms.width = MAX(ms.width, minsize.width);
  53. ms.height = MAX(ms.height, minsize.height);
  54. }
  55. if (keying) {
  56. Ref<Texture> key = get_icon("Key", "EditorIcons");
  57. ms.width += key->get_width() + get_constant("hseparator", "Tree");
  58. }
  59. if (checkable) {
  60. Ref<Texture> check = get_icon("checked", "CheckBox");
  61. ms.width += check->get_width() + get_constant("hseparator", "Tree");
  62. }
  63. if (bottom_editor != NULL && bottom_editor->is_visible()) {
  64. ms.height += get_constant("vseparation", "Tree");
  65. Size2 bems = bottom_editor->get_combined_minimum_size();
  66. //bems.width += get_constant("item_margin", "Tree");
  67. ms.height += bems.height;
  68. ms.width = MAX(ms.width, bems.width);
  69. }
  70. return ms;
  71. }
  72. void EditorProperty::emit_changed(const StringName &p_property, const Variant &p_value, const StringName &p_field, bool p_changing) {
  73. emit_signal("property_changed", p_property, p_value, p_field, p_changing);
  74. }
  75. void EditorProperty::_notification(int p_what) {
  76. if (p_what == NOTIFICATION_SORT_CHILDREN) {
  77. Size2 size = get_size();
  78. Rect2 rect;
  79. Rect2 bottom_rect;
  80. right_child_rect = Rect2();
  81. bottom_child_rect = Rect2();
  82. {
  83. int child_room = size.width * (1.0 - split_ratio);
  84. Ref<Font> font = get_font("font", "Tree");
  85. int height = font->get_height();
  86. bool no_children = true;
  87. //compute room needed
  88. for (int i = 0; i < get_child_count(); i++) {
  89. Control *c = Object::cast_to<Control>(get_child(i));
  90. if (!c)
  91. continue;
  92. if (c->is_set_as_toplevel())
  93. continue;
  94. if (c == bottom_editor)
  95. continue;
  96. Size2 minsize = c->get_combined_minimum_size();
  97. child_room = MAX(child_room, minsize.width);
  98. height = MAX(height, minsize.height);
  99. no_children = false;
  100. }
  101. if (no_children) {
  102. text_size = size.width;
  103. rect = Rect2(size.width - 1, 0, 1, height);
  104. } else {
  105. text_size = MAX(0, size.width - (child_room + 4 * EDSCALE));
  106. rect = Rect2(size.width - child_room, 0, child_room, height);
  107. }
  108. if (bottom_editor) {
  109. int m = 0; //get_constant("item_margin", "Tree");
  110. bottom_rect = Rect2(m, rect.size.height + get_constant("vseparation", "Tree"), size.width - m, bottom_editor->get_combined_minimum_size().height);
  111. }
  112. if (keying) {
  113. Ref<Texture> key;
  114. if (use_keying_next()) {
  115. key = get_icon("KeyNext", "EditorIcons");
  116. } else {
  117. key = get_icon("Key", "EditorIcons");
  118. }
  119. rect.size.x -= key->get_width() + get_constant("hseparator", "Tree");
  120. if (no_children) {
  121. text_size -= key->get_width() + 4 * EDSCALE;
  122. }
  123. }
  124. }
  125. //set children
  126. for (int i = 0; i < get_child_count(); i++) {
  127. Control *c = Object::cast_to<Control>(get_child(i));
  128. if (!c)
  129. continue;
  130. if (c->is_set_as_toplevel())
  131. continue;
  132. if (c == bottom_editor)
  133. continue;
  134. fit_child_in_rect(c, rect);
  135. right_child_rect = rect;
  136. }
  137. if (bottom_editor) {
  138. fit_child_in_rect(bottom_editor, bottom_rect);
  139. bottom_child_rect = bottom_rect;
  140. }
  141. update(); //need to redraw text
  142. }
  143. if (p_what == NOTIFICATION_DRAW) {
  144. Ref<Font> font = get_font("font", "Tree");
  145. Color dark_color = get_color("dark_color_2", "Editor");
  146. Size2 size = get_size();
  147. if (bottom_editor) {
  148. size.height = bottom_editor->get_margin(MARGIN_TOP);
  149. } else if (label_reference) {
  150. size.height = label_reference->get_size().height;
  151. }
  152. if (selected) {
  153. Ref<StyleBox> sb = get_stylebox("selected", "Tree");
  154. draw_style_box(sb, Rect2(Vector2(), size));
  155. }
  156. if (draw_top_bg && right_child_rect != Rect2()) {
  157. draw_rect(right_child_rect, dark_color);
  158. }
  159. if (bottom_child_rect != Rect2()) {
  160. draw_rect(bottom_child_rect, dark_color);
  161. }
  162. Color color;
  163. if (draw_red) {
  164. color = get_color("error_color", "Editor");
  165. } else {
  166. color = get_color("property_color", "Editor");
  167. }
  168. if (label.find(".") != -1) {
  169. color.a = 0.5; //this should be un-hacked honestly, as it's used for editor overrides
  170. }
  171. int ofs = 0;
  172. if (checkable) {
  173. Ref<Texture> checkbox;
  174. if (checked)
  175. checkbox = get_icon("checked", "CheckBox");
  176. else
  177. checkbox = get_icon("unchecked", "CheckBox");
  178. Color color2(1, 1, 1);
  179. if (check_hover) {
  180. color2.r *= 1.2;
  181. color2.g *= 1.2;
  182. color2.b *= 1.2;
  183. }
  184. check_rect = Rect2(ofs, ((size.height - checkbox->get_height()) / 2), checkbox->get_width(), checkbox->get_height());
  185. draw_texture(checkbox, check_rect.position, color2);
  186. ofs += get_constant("hseparator", "Tree");
  187. ofs += checkbox->get_width();
  188. } else {
  189. check_rect = Rect2();
  190. }
  191. int text_limit = text_size;
  192. if (can_revert) {
  193. Ref<Texture> reload_icon = get_icon("ReloadSmall", "EditorIcons");
  194. text_limit -= reload_icon->get_width() + get_constant("hseparator", "Tree") * 2;
  195. revert_rect = Rect2(text_limit + get_constant("hseparator", "Tree"), (size.height - reload_icon->get_height()) / 2, reload_icon->get_width(), reload_icon->get_height());
  196. Color color2(1, 1, 1);
  197. if (revert_hover) {
  198. color2.r *= 1.2;
  199. color2.g *= 1.2;
  200. color2.b *= 1.2;
  201. }
  202. draw_texture(reload_icon, revert_rect.position, color2);
  203. } else {
  204. revert_rect = Rect2();
  205. }
  206. int v_ofs = (size.height - font->get_height()) / 2;
  207. draw_string(font, Point2(ofs, v_ofs + font->get_ascent()), label, color, text_limit);
  208. if (keying) {
  209. Ref<Texture> key;
  210. if (use_keying_next()) {
  211. key = get_icon("KeyNext", "EditorIcons");
  212. } else {
  213. key = get_icon("Key", "EditorIcons");
  214. }
  215. ofs = size.width - key->get_width() - get_constant("hseparator", "Tree");
  216. Color color2(1, 1, 1);
  217. if (keying_hover) {
  218. color2.r *= 1.2;
  219. color2.g *= 1.2;
  220. color2.b *= 1.2;
  221. }
  222. keying_rect = Rect2(ofs, ((size.height - key->get_height()) / 2), key->get_width(), key->get_height());
  223. draw_texture(key, keying_rect.position, color2);
  224. } else {
  225. keying_rect = Rect2();
  226. }
  227. }
  228. }
  229. void EditorProperty::set_label(const String &p_label) {
  230. label = p_label;
  231. update();
  232. }
  233. String EditorProperty::get_label() const {
  234. return label;
  235. }
  236. Object *EditorProperty::get_edited_object() {
  237. return object;
  238. }
  239. StringName EditorProperty::get_edited_property() {
  240. return property;
  241. }
  242. void EditorProperty::update_property() {
  243. if (get_script_instance())
  244. get_script_instance()->call("update_property");
  245. }
  246. void EditorProperty::set_read_only(bool p_read_only) {
  247. read_only = p_read_only;
  248. }
  249. bool EditorProperty::is_read_only() const {
  250. return read_only;
  251. }
  252. bool EditorPropertyRevert::may_node_be_in_instance(Node *p_node) {
  253. Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
  254. bool might_be = false;
  255. Node *node = p_node;
  256. while (node) {
  257. if (node->get_scene_instance_state().is_valid()) {
  258. might_be = true;
  259. break;
  260. }
  261. if (node == edited_scene) {
  262. if (node->get_scene_inherited_state().is_valid()) {
  263. might_be = true;
  264. break;
  265. }
  266. might_be = false;
  267. break;
  268. }
  269. node = node->get_owner();
  270. }
  271. return might_be; // or might not be
  272. }
  273. bool EditorPropertyRevert::get_instanced_node_original_property(Node *p_node, const StringName &p_prop, Variant &value) {
  274. Node *node = p_node;
  275. Node *orig = node;
  276. Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
  277. bool found = false;
  278. while (node) {
  279. Ref<SceneState> ss;
  280. if (node == edited_scene) {
  281. ss = node->get_scene_inherited_state();
  282. } else {
  283. ss = node->get_scene_instance_state();
  284. }
  285. if (ss.is_valid()) {
  286. NodePath np = node->get_path_to(orig);
  287. int node_idx = ss->find_node_by_path(np);
  288. if (node_idx >= 0) {
  289. bool lfound = false;
  290. Variant lvar;
  291. lvar = ss->get_property_value(node_idx, p_prop, lfound);
  292. if (lfound) {
  293. found = true;
  294. value = lvar;
  295. }
  296. }
  297. }
  298. if (node == edited_scene) {
  299. //just in case
  300. break;
  301. }
  302. node = node->get_owner();
  303. }
  304. if (!found) {
  305. //if not found, try default class value
  306. Variant attempt = ClassDB::class_get_default_property_value(node->get_class_name(), p_prop);
  307. if (attempt.get_type() != Variant::NIL) {
  308. found = true;
  309. value = attempt;
  310. }
  311. }
  312. return found;
  313. }
  314. bool EditorPropertyRevert::is_node_property_different(Node *p_node, const Variant &p_current, const Variant &p_orig) {
  315. // this is a pretty difficult function, because a property may not be saved but may have
  316. // the flag to not save if one or if zero
  317. //make sure there is an actual state
  318. {
  319. Node *node = p_node;
  320. if (!node)
  321. return false;
  322. Node *edited_scene = EditorNode::get_singleton()->get_edited_scene();
  323. bool found_state = false;
  324. while (node) {
  325. Ref<SceneState> ss;
  326. if (node == edited_scene) {
  327. ss = node->get_scene_inherited_state();
  328. } else {
  329. ss = node->get_scene_instance_state();
  330. }
  331. if (ss.is_valid()) {
  332. found_state = true;
  333. }
  334. if (node == edited_scene) {
  335. //just in case
  336. break;
  337. }
  338. node = node->get_owner();
  339. }
  340. if (!found_state)
  341. return false; //pointless to check if we are not comparing against anything.
  342. }
  343. if (p_current.get_type() == Variant::REAL && p_orig.get_type() == Variant::REAL) {
  344. float a = p_current;
  345. float b = p_orig;
  346. return Math::abs(a - b) > CMP_EPSILON; //this must be done because, as some scenes save as text, there might be a tiny difference in floats due to numerical error
  347. }
  348. return bool(Variant::evaluate(Variant::OP_NOT_EQUAL, p_current, p_orig));
  349. }
  350. bool EditorPropertyRevert::can_property_revert(Object *p_object, const StringName &p_property) {
  351. bool has_revert = false;
  352. Node *node = Object::cast_to<Node>(p_object);
  353. if (node && EditorPropertyRevert::may_node_be_in_instance(node)) {
  354. //check for difference including instantiation
  355. Variant vorig;
  356. if (EditorPropertyRevert::get_instanced_node_original_property(node, p_property, vorig)) {
  357. Variant v = p_object->get(p_property);
  358. if (EditorPropertyRevert::is_node_property_different(node, v, vorig)) {
  359. has_revert = true;
  360. }
  361. }
  362. } else {
  363. //check for difference against default class value instead
  364. Variant default_value = ClassDB::class_get_default_property_value(p_object->get_class_name(), p_property);
  365. if (default_value != Variant() && default_value != p_object->get(p_property)) {
  366. has_revert = true;
  367. }
  368. }
  369. if (p_object->call("property_can_revert", p_property).operator bool()) {
  370. has_revert = true;
  371. }
  372. if (!has_revert && !p_object->get_script().is_null()) {
  373. Ref<Script> scr = p_object->get_script();
  374. Variant orig_value;
  375. if (scr->get_property_default_value(p_property, orig_value)) {
  376. if (orig_value != p_object->get(p_property)) {
  377. has_revert = true;
  378. }
  379. }
  380. }
  381. return has_revert;
  382. }
  383. void EditorProperty::update_reload_status() {
  384. if (property == StringName())
  385. return; //no property, so nothing to do
  386. bool has_reload = EditorPropertyRevert::can_property_revert(object, property);
  387. if (has_reload != can_revert) {
  388. can_revert = has_reload;
  389. update();
  390. }
  391. }
  392. bool EditorProperty::use_keying_next() const {
  393. List<PropertyInfo> plist;
  394. object->get_property_list(&plist, true);
  395. for (List<PropertyInfo>::Element *I = plist.front(); I; I = I->next()) {
  396. PropertyInfo &p = I->get();
  397. if (p.name == property) {
  398. return p.hint == PROPERTY_HINT_SPRITE_FRAME;
  399. }
  400. }
  401. return false;
  402. }
  403. void EditorProperty::set_checkable(bool p_checkable) {
  404. checkable = p_checkable;
  405. update();
  406. queue_sort();
  407. }
  408. bool EditorProperty::is_checkable() const {
  409. return checkable;
  410. }
  411. void EditorProperty::set_checked(bool p_checked) {
  412. checked = p_checked;
  413. update();
  414. }
  415. bool EditorProperty::is_checked() const {
  416. return checked;
  417. }
  418. void EditorProperty::set_draw_red(bool p_draw_red) {
  419. draw_red = p_draw_red;
  420. update();
  421. }
  422. void EditorProperty::set_keying(bool p_keying) {
  423. keying = p_keying;
  424. update();
  425. queue_sort();
  426. }
  427. bool EditorProperty::is_keying() const {
  428. return keying;
  429. }
  430. bool EditorProperty::is_draw_red() const {
  431. return draw_red;
  432. }
  433. void EditorProperty::_focusable_focused(int p_index) {
  434. if (!selectable)
  435. return;
  436. bool already_selected = selected;
  437. selected = true;
  438. selected_focusable = p_index;
  439. update();
  440. if (!already_selected && selected) {
  441. emit_signal("selected", property, selected_focusable);
  442. }
  443. }
  444. void EditorProperty::add_focusable(Control *p_control) {
  445. p_control->connect("focus_entered", this, "_focusable_focused", varray(focusables.size()));
  446. focusables.push_back(p_control);
  447. }
  448. void EditorProperty::select(int p_focusable) {
  449. bool already_selected = selected;
  450. if (p_focusable >= 0) {
  451. ERR_FAIL_INDEX(p_focusable, focusables.size());
  452. focusables[p_focusable]->grab_focus();
  453. } else {
  454. selected = true;
  455. update();
  456. }
  457. if (!already_selected && selected) {
  458. emit_signal("selected", property, selected_focusable);
  459. }
  460. }
  461. void EditorProperty::deselect() {
  462. selected = false;
  463. selected_focusable = -1;
  464. update();
  465. }
  466. bool EditorProperty::is_selected() const {
  467. return selected;
  468. }
  469. void EditorProperty::_gui_input(const Ref<InputEvent> &p_event) {
  470. if (property == StringName())
  471. return;
  472. Ref<InputEventMouse> me = p_event;
  473. if (me.is_valid()) {
  474. bool button_left = me->get_button_mask() & BUTTON_MASK_LEFT;
  475. bool new_keying_hover = keying_rect.has_point(me->get_position()) && !button_left;
  476. if (new_keying_hover != keying_hover) {
  477. keying_hover = new_keying_hover;
  478. update();
  479. }
  480. bool new_revert_hover = revert_rect.has_point(me->get_position()) && !button_left;
  481. if (new_revert_hover != revert_hover) {
  482. revert_hover = new_revert_hover;
  483. update();
  484. }
  485. bool new_check_hover = check_rect.has_point(me->get_position()) && !button_left;
  486. if (new_check_hover != check_hover) {
  487. check_hover = new_check_hover;
  488. update();
  489. }
  490. }
  491. Ref<InputEventMouseButton> mb = p_event;
  492. if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
  493. if (!selected && selectable) {
  494. selected = true;
  495. emit_signal("selected", property, -1);
  496. update();
  497. }
  498. if (keying_rect.has_point(mb->get_position())) {
  499. emit_signal("property_keyed", property, use_keying_next());
  500. if (use_keying_next()) {
  501. call_deferred("emit_changed", property, object->get(property).operator int64_t() + 1, "", false);
  502. call_deferred("update_property");
  503. }
  504. }
  505. if (revert_rect.has_point(mb->get_position())) {
  506. Variant vorig;
  507. Node *node = Object::cast_to<Node>(object);
  508. if (node && EditorPropertyRevert::may_node_be_in_instance(node) && EditorPropertyRevert::get_instanced_node_original_property(node, property, vorig)) {
  509. emit_changed(property, vorig.duplicate(true));
  510. update_property();
  511. return;
  512. }
  513. if (object->call("property_can_revert", property).operator bool()) {
  514. Variant rev = object->call("property_get_revert", property);
  515. emit_changed(property, rev);
  516. update_property();
  517. return;
  518. }
  519. if (!object->get_script().is_null()) {
  520. Ref<Script> scr = object->get_script();
  521. Variant orig_value;
  522. if (scr->get_property_default_value(property, orig_value)) {
  523. emit_changed(property, orig_value);
  524. update_property();
  525. return;
  526. }
  527. }
  528. Variant default_value = ClassDB::class_get_default_property_value(object->get_class_name(), property);
  529. if (default_value != Variant()) {
  530. emit_changed(property, default_value);
  531. update_property();
  532. return;
  533. }
  534. }
  535. if (check_rect.has_point(mb->get_position())) {
  536. checked = !checked;
  537. update();
  538. emit_signal("property_checked", property, checked);
  539. }
  540. }
  541. }
  542. void EditorProperty::set_label_reference(Control *p_control) {
  543. label_reference = p_control;
  544. }
  545. void EditorProperty::set_bottom_editor(Control *p_control) {
  546. bottom_editor = p_control;
  547. }
  548. Variant EditorProperty::get_drag_data(const Point2 &p_point) {
  549. if (property == StringName())
  550. return Variant();
  551. Dictionary dp;
  552. dp["type"] = "obj_property";
  553. dp["object"] = object;
  554. dp["property"] = property;
  555. dp["value"] = object->get(property);
  556. Label *label = memnew(Label);
  557. label->set_text(property);
  558. set_drag_preview(label);
  559. return dp;
  560. }
  561. void EditorProperty::set_use_folding(bool p_use_folding) {
  562. use_folding = p_use_folding;
  563. }
  564. bool EditorProperty::is_using_folding() const {
  565. return use_folding;
  566. }
  567. void EditorProperty::expand_all_folding() {
  568. }
  569. void EditorProperty::collapse_all_folding() {
  570. }
  571. void EditorProperty::set_selectable(bool p_selectable) {
  572. selectable = p_selectable;
  573. }
  574. bool EditorProperty::is_selectable() const {
  575. return selectable;
  576. }
  577. void EditorProperty::set_name_split_ratio(float p_ratio) {
  578. split_ratio = p_ratio;
  579. }
  580. float EditorProperty::get_name_split_ratio() const {
  581. return split_ratio;
  582. }
  583. void EditorProperty::set_object_and_property(Object *p_object, const StringName &p_property) {
  584. object = p_object;
  585. property = p_property;
  586. }
  587. Control *EditorProperty::make_custom_tooltip(const String &p_text) const {
  588. tooltip_text = p_text;
  589. EditorHelpBit *help_bit = memnew(EditorHelpBit);
  590. help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel"));
  591. help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE);
  592. String text = TTR("Property:") + " [u][b]" + p_text.get_slice("::", 0) + "[/b][/u]\n";
  593. text += p_text.get_slice("::", 1).strip_edges();
  594. help_bit->set_text(text);
  595. help_bit->call_deferred("set_text", text); //hack so it uses proper theme once inside scene
  596. return help_bit;
  597. }
  598. String EditorProperty::get_tooltip_text() const {
  599. return tooltip_text;
  600. }
  601. void EditorProperty::_bind_methods() {
  602. ClassDB::bind_method(D_METHOD("set_label", "text"), &EditorProperty::set_label);
  603. ClassDB::bind_method(D_METHOD("get_label"), &EditorProperty::get_label);
  604. ClassDB::bind_method(D_METHOD("set_read_only", "read_only"), &EditorProperty::set_read_only);
  605. ClassDB::bind_method(D_METHOD("is_read_only"), &EditorProperty::is_read_only);
  606. ClassDB::bind_method(D_METHOD("set_checkable", "checkable"), &EditorProperty::set_checkable);
  607. ClassDB::bind_method(D_METHOD("is_checkable"), &EditorProperty::is_checkable);
  608. ClassDB::bind_method(D_METHOD("set_checked", "checked"), &EditorProperty::set_checked);
  609. ClassDB::bind_method(D_METHOD("is_checked"), &EditorProperty::is_checked);
  610. ClassDB::bind_method(D_METHOD("set_draw_red", "draw_red"), &EditorProperty::set_draw_red);
  611. ClassDB::bind_method(D_METHOD("is_draw_red"), &EditorProperty::is_draw_red);
  612. ClassDB::bind_method(D_METHOD("set_keying", "keying"), &EditorProperty::set_keying);
  613. ClassDB::bind_method(D_METHOD("is_keying"), &EditorProperty::is_keying);
  614. ClassDB::bind_method(D_METHOD("get_edited_property"), &EditorProperty::get_edited_property);
  615. ClassDB::bind_method(D_METHOD("get_edited_object"), &EditorProperty::get_edited_object);
  616. ClassDB::bind_method(D_METHOD("_gui_input"), &EditorProperty::_gui_input);
  617. ClassDB::bind_method(D_METHOD("_focusable_focused"), &EditorProperty::_focusable_focused);
  618. ClassDB::bind_method(D_METHOD("get_tooltip_text"), &EditorProperty::get_tooltip_text);
  619. ClassDB::bind_method(D_METHOD("emit_changed", "property", "value", "field", "changing"), &EditorProperty::emit_changed, DEFVAL(StringName()), DEFVAL(false));
  620. ADD_PROPERTY(PropertyInfo(Variant::STRING, "label"), "set_label", "get_label");
  621. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only");
  622. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "checkable"), "set_checkable", "is_checkable");
  623. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "checked"), "set_checked", "is_checked");
  624. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_red"), "set_draw_red", "is_draw_red");
  625. ADD_PROPERTY(PropertyInfo(Variant::BOOL, "keying"), "set_keying", "is_keying");
  626. ADD_SIGNAL(MethodInfo("property_changed", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
  627. ADD_SIGNAL(MethodInfo("multiple_properties_changed", PropertyInfo(Variant::POOL_STRING_ARRAY, "properties"), PropertyInfo(Variant::ARRAY, "value")));
  628. ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property")));
  629. ADD_SIGNAL(MethodInfo("property_keyed_with_value", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::NIL, "value", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT)));
  630. ADD_SIGNAL(MethodInfo("property_checked", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::STRING, "bool")));
  631. ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::OBJECT, "resource", PROPERTY_HINT_RESOURCE_TYPE, "Resource")));
  632. ADD_SIGNAL(MethodInfo("object_id_selected", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::INT, "id")));
  633. ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "path"), PropertyInfo(Variant::INT, "focusable_idx")));
  634. MethodInfo vm;
  635. vm.name = "update_property";
  636. BIND_VMETHOD(vm);
  637. }
  638. EditorProperty::EditorProperty() {
  639. draw_top_bg = true;
  640. object = NULL;
  641. split_ratio = 0.5;
  642. selectable = true;
  643. text_size = 0;
  644. read_only = false;
  645. checkable = false;
  646. checked = false;
  647. draw_red = false;
  648. keying = false;
  649. keying_hover = false;
  650. revert_hover = false;
  651. check_hover = false;
  652. can_revert = false;
  653. use_folding = false;
  654. property_usage = 0;
  655. selected = false;
  656. selected_focusable = -1;
  657. label_reference = NULL;
  658. bottom_editor = NULL;
  659. }
  660. ////////////////////////////////////////////////
  661. ////////////////////////////////////////////////
  662. void EditorInspectorPlugin::add_custom_control(Control *control) {
  663. AddedEditor ae;
  664. ae.property_editor = control;
  665. added_editors.push_back(ae);
  666. }
  667. void EditorInspectorPlugin::add_property_editor(const String &p_for_property, Control *p_prop) {
  668. ERR_FAIL_COND(Object::cast_to<EditorProperty>(p_prop) == NULL);
  669. AddedEditor ae;
  670. ae.properties.push_back(p_for_property);
  671. ae.property_editor = p_prop;
  672. added_editors.push_back(ae);
  673. }
  674. void EditorInspectorPlugin::add_property_editor_for_multiple_properties(const String &p_label, const Vector<String> &p_properties, Control *p_prop) {
  675. AddedEditor ae;
  676. ae.properties = p_properties;
  677. ae.property_editor = p_prop;
  678. ae.label = p_label;
  679. added_editors.push_back(ae);
  680. }
  681. bool EditorInspectorPlugin::can_handle(Object *p_object) {
  682. if (get_script_instance()) {
  683. return get_script_instance()->call("can_handle", p_object);
  684. }
  685. return false;
  686. }
  687. void EditorInspectorPlugin::parse_begin(Object *p_object) {
  688. if (get_script_instance()) {
  689. get_script_instance()->call("parse_begin", p_object);
  690. }
  691. }
  692. void EditorInspectorPlugin::parse_category(Object *p_object, const String &p_parse_category) {
  693. if (get_script_instance()) {
  694. get_script_instance()->call("parse_category", p_object, p_parse_category);
  695. }
  696. }
  697. bool EditorInspectorPlugin::parse_property(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) {
  698. if (get_script_instance()) {
  699. Variant arg[6] = {
  700. p_object, p_type, p_path, p_hint, p_hint_text, p_usage
  701. };
  702. const Variant *argptr[6] = {
  703. &arg[0], &arg[1], &arg[2], &arg[3], &arg[4], &arg[5]
  704. };
  705. Variant::CallError err;
  706. return get_script_instance()->call("parse_property", (const Variant **)&argptr, 6, err);
  707. }
  708. return false;
  709. }
  710. void EditorInspectorPlugin::parse_end() {
  711. if (get_script_instance()) {
  712. get_script_instance()->call("parse_end");
  713. }
  714. }
  715. void EditorInspectorPlugin::_bind_methods() {
  716. ClassDB::bind_method(D_METHOD("add_custom_control", "control"), &EditorInspectorPlugin::add_custom_control);
  717. ClassDB::bind_method(D_METHOD("add_property_editor", "property", "editor"), &EditorInspectorPlugin::add_property_editor);
  718. ClassDB::bind_method(D_METHOD("add_property_editor_for_multiple_properties", "label", "properties", "editor"), &EditorInspectorPlugin::add_property_editor_for_multiple_properties);
  719. MethodInfo vm;
  720. vm.name = "can_handle";
  721. vm.return_val.type = Variant::BOOL;
  722. vm.arguments.push_back(PropertyInfo(Variant::OBJECT, "object"));
  723. BIND_VMETHOD(vm);
  724. vm.name = "parse_begin";
  725. vm.return_val.type = Variant::NIL;
  726. BIND_VMETHOD(vm);
  727. vm.name = "parse_category";
  728. vm.arguments.push_back(PropertyInfo(Variant::STRING, "category"));
  729. BIND_VMETHOD(vm);
  730. vm.arguments.pop_back();
  731. vm.name = "parse_property";
  732. vm.return_val.type = Variant::BOOL;
  733. vm.arguments.push_back(PropertyInfo(Variant::INT, "type"));
  734. vm.arguments.push_back(PropertyInfo(Variant::STRING, "path"));
  735. vm.arguments.push_back(PropertyInfo(Variant::INT, "hint"));
  736. vm.arguments.push_back(PropertyInfo(Variant::STRING, "hint_text"));
  737. vm.arguments.push_back(PropertyInfo(Variant::INT, "usage"));
  738. BIND_VMETHOD(vm);
  739. vm.arguments.clear();
  740. vm.name = "parse_end";
  741. vm.return_val.type = Variant::NIL;
  742. BIND_VMETHOD(vm);
  743. }
  744. ////////////////////////////////////////////////
  745. ////////////////////////////////////////////////
  746. void EditorInspectorCategory::_notification(int p_what) {
  747. if (p_what == NOTIFICATION_DRAW) {
  748. draw_rect(Rect2(Vector2(), get_size()), bg_color);
  749. Ref<Font> font = get_font("font", "Tree");
  750. int hs = get_constant("hseparation", "Tree");
  751. int w = font->get_string_size(label).width;
  752. if (icon.is_valid()) {
  753. w += hs + icon->get_width();
  754. }
  755. int ofs = (get_size().width - w) / 2;
  756. if (icon.is_valid()) {
  757. draw_texture(icon, Point2(ofs, (get_size().height - icon->get_height()) / 2).floor());
  758. ofs += hs + icon->get_width();
  759. }
  760. Color color = get_color("font_color", "Tree");
  761. draw_string(font, Point2(ofs, font->get_ascent() + (get_size().height - font->get_height()) / 2).floor(), label, color, get_size().width);
  762. }
  763. }
  764. Control *EditorInspectorCategory::make_custom_tooltip(const String &p_text) const {
  765. tooltip_text = p_text;
  766. EditorHelpBit *help_bit = memnew(EditorHelpBit);
  767. help_bit->add_style_override("panel", get_stylebox("panel", "TooltipPanel"));
  768. help_bit->get_rich_text()->set_fixed_size_to_width(360 * EDSCALE);
  769. String text = "[u][b]" + p_text.get_slice("::", 0) + "[/b][/u]\n";
  770. text += p_text.get_slice("::", 1).strip_edges();
  771. help_bit->set_text(text);
  772. help_bit->call_deferred("set_text", text); //hack so it uses proper theme once inside scene
  773. return help_bit;
  774. }
  775. Size2 EditorInspectorCategory::get_minimum_size() const {
  776. Ref<Font> font = get_font("font", "Tree");
  777. Size2 ms;
  778. ms.width = 1;
  779. ms.height = font->get_height();
  780. if (icon.is_valid()) {
  781. ms.height = MAX(icon->get_height(), ms.height);
  782. }
  783. ms.height += get_constant("vseparation", "Tree");
  784. return ms;
  785. }
  786. void EditorInspectorCategory::_bind_methods() {
  787. ClassDB::bind_method(D_METHOD("get_tooltip_text"), &EditorInspectorCategory::get_tooltip_text);
  788. }
  789. String EditorInspectorCategory::get_tooltip_text() const {
  790. return tooltip_text;
  791. }
  792. EditorInspectorCategory::EditorInspectorCategory() {
  793. }
  794. ////////////////////////////////////////////////
  795. ////////////////////////////////////////////////
  796. void EditorInspectorSection::_test_unfold() {
  797. if (!vbox_added) {
  798. add_child(vbox);
  799. vbox_added = true;
  800. }
  801. }
  802. void EditorInspectorSection::_notification(int p_what) {
  803. if (p_what == NOTIFICATION_SORT_CHILDREN) {
  804. Ref<Font> font = get_font("font", "Tree");
  805. Ref<Texture> arrow;
  806. #ifdef TOOLS_ENABLED
  807. if (foldable) {
  808. if (object->editor_is_section_unfolded(section)) {
  809. arrow = get_icon("arrow_up", "Tree");
  810. } else {
  811. arrow = get_icon("arrow", "Tree");
  812. }
  813. }
  814. #endif
  815. Size2 size = get_size();
  816. Point2 offset;
  817. offset.y = font->get_height();
  818. if (arrow.is_valid()) {
  819. offset.y = MAX(offset.y, arrow->get_height());
  820. }
  821. offset.y += get_constant("vseparation", "Tree");
  822. offset.x += get_constant("inspector_margin", "Editor");
  823. Rect2 rect(offset, size - offset);
  824. //set children
  825. for (int i = 0; i < get_child_count(); i++) {
  826. Control *c = Object::cast_to<Control>(get_child(i));
  827. if (!c)
  828. continue;
  829. if (c->is_set_as_toplevel())
  830. continue;
  831. if (!c->is_visible_in_tree())
  832. continue;
  833. fit_child_in_rect(c, rect);
  834. }
  835. update(); //need to redraw text
  836. }
  837. if (p_what == NOTIFICATION_DRAW) {
  838. Ref<Texture> arrow;
  839. #ifdef TOOLS_ENABLED
  840. if (foldable) {
  841. if (object->editor_is_section_unfolded(section)) {
  842. arrow = get_icon("arrow_up", "Tree");
  843. } else {
  844. arrow = get_icon("arrow", "Tree");
  845. }
  846. }
  847. #endif
  848. Ref<Font> font = get_font("font", "Tree");
  849. int h = font->get_height();
  850. if (arrow.is_valid()) {
  851. h = MAX(h, arrow->get_height());
  852. }
  853. h += get_constant("vseparation", "Tree");
  854. draw_rect(Rect2(Vector2(), Vector2(get_size().width, h)), bg_color);
  855. int hs = get_constant("hseparation", "Tree");
  856. Color color = get_color("font_color", "Tree");
  857. draw_string(font, Point2(hs, font->get_ascent() + (h - font->get_height()) / 2).floor(), label, color, get_size().width);
  858. if (arrow.is_valid()) {
  859. draw_texture(arrow, Point2(get_size().width - arrow->get_width(), (h - arrow->get_height()) / 2).floor());
  860. }
  861. }
  862. }
  863. Size2 EditorInspectorSection::get_minimum_size() const {
  864. Size2 ms;
  865. for (int i = 0; i < get_child_count(); i++) {
  866. Control *c = Object::cast_to<Control>(get_child(i));
  867. if (!c)
  868. continue;
  869. if (c->is_set_as_toplevel())
  870. continue;
  871. if (!c->is_visible())
  872. continue;
  873. Size2 minsize = c->get_combined_minimum_size();
  874. ms.width = MAX(ms.width, minsize.width);
  875. ms.height = MAX(ms.height, minsize.height);
  876. }
  877. Ref<Font> font = get_font("font", "Tree");
  878. ms.height += font->get_height() + get_constant("vseparation", "Tree");
  879. ms.width += get_constant("inspector_margin", "Editor");
  880. return ms;
  881. }
  882. void EditorInspectorSection::setup(const String &p_section, const String &p_label, Object *p_object, const Color &p_bg_color, bool p_foldable) {
  883. section = p_section;
  884. label = p_label;
  885. object = p_object;
  886. bg_color = p_bg_color;
  887. foldable = p_foldable;
  888. if (!foldable && !vbox_added) {
  889. add_child(vbox);
  890. vbox_added = true;
  891. }
  892. #ifdef TOOLS_ENABLED
  893. if (foldable) {
  894. _test_unfold();
  895. if (object->editor_is_section_unfolded(section)) {
  896. vbox->show();
  897. } else {
  898. vbox->hide();
  899. }
  900. }
  901. #endif
  902. }
  903. void EditorInspectorSection::_gui_input(const Ref<InputEvent> &p_event) {
  904. if (!foldable)
  905. return;
  906. #ifdef TOOLS_ENABLED
  907. Ref<InputEventMouseButton> mb = p_event;
  908. if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
  909. Ref<Font> font = get_font("font", "Tree");
  910. if (mb->get_position().y > font->get_height()) { //clicked outside
  911. return;
  912. }
  913. _test_unfold();
  914. bool unfold = !object->editor_is_section_unfolded(section);
  915. object->editor_set_section_unfold(section, unfold);
  916. if (unfold) {
  917. vbox->show();
  918. } else {
  919. vbox->hide();
  920. }
  921. }
  922. #endif
  923. }
  924. VBoxContainer *EditorInspectorSection::get_vbox() {
  925. return vbox;
  926. }
  927. void EditorInspectorSection::unfold() {
  928. if (!foldable)
  929. return;
  930. _test_unfold();
  931. #ifdef TOOLS_ENABLED
  932. object->editor_set_section_unfold(section, true);
  933. vbox->show();
  934. update();
  935. #endif
  936. }
  937. void EditorInspectorSection::fold() {
  938. if (!foldable)
  939. return;
  940. if (!vbox_added)
  941. return; //kinda pointless
  942. #ifdef TOOLS_ENABLED
  943. object->editor_set_section_unfold(section, false);
  944. vbox->hide();
  945. update();
  946. #endif
  947. }
  948. void EditorInspectorSection::_bind_methods() {
  949. ClassDB::bind_method(D_METHOD("setup", "section", "label", "object", "bg_color", "foldable"), &EditorInspectorSection::setup);
  950. ClassDB::bind_method(D_METHOD("get_vbox"), &EditorInspectorSection::get_vbox);
  951. ClassDB::bind_method(D_METHOD("unfold"), &EditorInspectorSection::unfold);
  952. ClassDB::bind_method(D_METHOD("fold"), &EditorInspectorSection::fold);
  953. ClassDB::bind_method(D_METHOD("_gui_input"), &EditorInspectorSection::_gui_input);
  954. }
  955. EditorInspectorSection::EditorInspectorSection() {
  956. object = NULL;
  957. foldable = false;
  958. vbox = memnew(VBoxContainer);
  959. vbox_added = false;
  960. }
  961. EditorInspectorSection::~EditorInspectorSection() {
  962. if (!vbox_added) {
  963. memdelete(vbox);
  964. }
  965. }
  966. ////////////////////////////////////////////////
  967. ////////////////////////////////////////////////
  968. Ref<EditorInspectorPlugin> EditorInspector::inspector_plugins[MAX_PLUGINS];
  969. int EditorInspector::inspector_plugin_count = 0;
  970. EditorProperty *EditorInspector::instantiate_property_editor(Object *p_object, Variant::Type p_type, const String &p_path, PropertyHint p_hint, const String &p_hint_text, int p_usage) {
  971. for (int i = inspector_plugin_count - 1; i >= 0; i--) {
  972. inspector_plugins[i]->parse_property(p_object, p_type, p_path, p_hint, p_hint_text, p_usage);
  973. if (inspector_plugins[i]->added_editors.size()) {
  974. for (int j = 1; j < inspector_plugins[i]->added_editors.size(); j++) { //only keep first one
  975. memdelete(inspector_plugins[i]->added_editors[j].property_editor);
  976. }
  977. EditorProperty *prop = Object::cast_to<EditorProperty>(inspector_plugins[i]->added_editors[0].property_editor);
  978. if (prop) {
  979. inspector_plugins[i]->added_editors.clear();
  980. return prop;
  981. } else {
  982. memdelete(inspector_plugins[i]->added_editors[0].property_editor);
  983. inspector_plugins[i]->added_editors.clear();
  984. }
  985. }
  986. }
  987. return NULL;
  988. }
  989. void EditorInspector::add_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) {
  990. ERR_FAIL_COND(inspector_plugin_count == MAX_PLUGINS);
  991. for (int i = 0; i < inspector_plugin_count; i++) {
  992. if (inspector_plugins[i] == p_plugin)
  993. return; //already exists
  994. }
  995. inspector_plugins[inspector_plugin_count++] = p_plugin;
  996. }
  997. void EditorInspector::remove_inspector_plugin(const Ref<EditorInspectorPlugin> &p_plugin) {
  998. ERR_FAIL_COND(inspector_plugin_count == MAX_PLUGINS);
  999. int idx = -1;
  1000. for (int i = 0; i < inspector_plugin_count; i++) {
  1001. if (inspector_plugins[i] == p_plugin) {
  1002. idx = i;
  1003. break;
  1004. }
  1005. }
  1006. for (int i = idx; i < inspector_plugin_count - 1; i++) {
  1007. inspector_plugins[i] = inspector_plugins[i + 1];
  1008. }
  1009. inspector_plugin_count--;
  1010. }
  1011. void EditorInspector::cleanup_plugins() {
  1012. for (int i = 0; i < inspector_plugin_count; i++) {
  1013. inspector_plugins[i].unref();
  1014. }
  1015. inspector_plugin_count = 0;
  1016. }
  1017. void EditorInspector::set_undo_redo(UndoRedo *p_undo_redo) {
  1018. undo_redo = p_undo_redo;
  1019. }
  1020. String EditorInspector::get_selected_path() const {
  1021. return property_selected;
  1022. }
  1023. void EditorInspector::_parse_added_editors(VBoxContainer *current_vbox, Ref<EditorInspectorPlugin> ped) {
  1024. for (List<EditorInspectorPlugin::AddedEditor>::Element *F = ped->added_editors.front(); F; F = F->next()) {
  1025. EditorProperty *ep = Object::cast_to<EditorProperty>(F->get().property_editor);
  1026. current_vbox->add_child(F->get().property_editor);
  1027. if (ep) {
  1028. ep->object = object;
  1029. ep->connect("property_changed", this, "_property_changed");
  1030. ep->connect("property_keyed", this, "_property_keyed");
  1031. ep->connect("property_keyed_with_value", this, "_property_keyed_with_value");
  1032. ep->connect("property_checked", this, "_property_checked");
  1033. ep->connect("selected", this, "_property_selected");
  1034. ep->connect("multiple_properties_changed", this, "_multiple_properties_changed");
  1035. ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED);
  1036. ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED);
  1037. if (F->get().properties.size()) {
  1038. if (F->get().properties.size() == 1) {
  1039. //since it's one, associate:
  1040. ep->property = F->get().properties[0];
  1041. ep->property_usage = 0;
  1042. }
  1043. if (F->get().label != String()) {
  1044. ep->set_label(F->get().label);
  1045. }
  1046. for (int i = 0; i < F->get().properties.size(); i++) {
  1047. String prop = F->get().properties[i];
  1048. if (!editor_property_map.has(prop)) {
  1049. editor_property_map[prop] = List<EditorProperty *>();
  1050. }
  1051. editor_property_map[prop].push_back(ep);
  1052. }
  1053. }
  1054. ep->set_read_only(read_only);
  1055. ep->update_property();
  1056. ep->update_reload_status();
  1057. }
  1058. }
  1059. ped->added_editors.clear();
  1060. }
  1061. void EditorInspector::update_tree() {
  1062. //to update properly if all is refreshed
  1063. StringName current_selected = property_selected;
  1064. int current_focusable = -1;
  1065. if (property_focusable != -1) {
  1066. //check focusable is really focusable
  1067. bool restore_focus = false;
  1068. Control *focused = get_focus_owner();
  1069. if (focused) {
  1070. Node *parent = focused->get_parent();
  1071. while (parent) {
  1072. EditorInspector *inspector = Object::cast_to<EditorInspector>(parent);
  1073. if (inspector) {
  1074. restore_focus = inspector == this; //may be owned by another inspector
  1075. break; //exit after the first inspector is found, since there may be nested ones
  1076. }
  1077. parent = parent->get_parent();
  1078. }
  1079. }
  1080. if (restore_focus) {
  1081. current_focusable = property_focusable;
  1082. }
  1083. }
  1084. _clear();
  1085. if (!object)
  1086. return;
  1087. List<Ref<EditorInspectorPlugin> > valid_plugins;
  1088. for (int i = inspector_plugin_count - 1; i >= 0; i--) { //start by last, so lastly added can override newly added
  1089. if (!inspector_plugins[i]->can_handle(object))
  1090. continue;
  1091. valid_plugins.push_back(inspector_plugins[i]);
  1092. }
  1093. bool draw_red = false;
  1094. {
  1095. Node *nod = Object::cast_to<Node>(object);
  1096. Node *es = EditorNode::get_singleton()->get_edited_scene();
  1097. if (nod && es != nod && nod->get_owner() != es) {
  1098. draw_red = true;
  1099. }
  1100. }
  1101. // TreeItem *current_category = NULL;
  1102. String filter = search_box ? search_box->get_text() : "";
  1103. String group;
  1104. String group_base;
  1105. VBoxContainer *category_vbox = NULL;
  1106. List<PropertyInfo>
  1107. plist;
  1108. object->get_property_list(&plist, true);
  1109. HashMap<String, VBoxContainer *> item_path;
  1110. Map<VBoxContainer *, EditorInspectorSection *> section_map;
  1111. item_path[""] = main_vbox;
  1112. Color sscolor = get_color("prop_subsection", "Editor");
  1113. for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) {
  1114. Ref<EditorInspectorPlugin> ped = E->get();
  1115. ped->parse_begin(object);
  1116. _parse_added_editors(main_vbox, ped);
  1117. }
  1118. for (List<PropertyInfo>::Element *I = plist.front(); I; I = I->next()) {
  1119. PropertyInfo &p = I->get();
  1120. //make sure the property can be edited
  1121. if (p.usage & PROPERTY_USAGE_GROUP) {
  1122. group = p.name;
  1123. group_base = p.hint_string;
  1124. continue;
  1125. } else if (p.usage & PROPERTY_USAGE_CATEGORY) {
  1126. group = "";
  1127. group_base = "";
  1128. if (!show_categories)
  1129. continue;
  1130. List<PropertyInfo>::Element *N = I->next();
  1131. bool valid = true;
  1132. //if no properties in category, skip
  1133. while (N) {
  1134. if (N->get().usage & PROPERTY_USAGE_EDITOR)
  1135. break;
  1136. if (N->get().usage & PROPERTY_USAGE_CATEGORY) {
  1137. valid = false;
  1138. break;
  1139. }
  1140. N = N->next();
  1141. }
  1142. if (!valid)
  1143. continue; //empty, ignore
  1144. EditorInspectorCategory *category = memnew(EditorInspectorCategory);
  1145. main_vbox->add_child(category);
  1146. category_vbox = NULL; //reset
  1147. String type = p.name;
  1148. category->icon = EditorNode::get_singleton()->get_class_icon(type, "Object");
  1149. category->label = type;
  1150. category->bg_color = get_color("prop_category", "Editor");
  1151. if (use_doc_hints) {
  1152. StringName type2 = p.name;
  1153. if (!class_descr_cache.has(type2)) {
  1154. String descr;
  1155. DocData *dd = EditorHelp::get_doc_data();
  1156. Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(type2);
  1157. if (E) {
  1158. descr = E->get().brief_description;
  1159. }
  1160. class_descr_cache[type2] = descr.word_wrap(80);
  1161. }
  1162. category->set_tooltip(p.name + "::" + (class_descr_cache[type2] == "" ? "" : class_descr_cache[type2]));
  1163. }
  1164. for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) {
  1165. Ref<EditorInspectorPlugin> ped = E->get();
  1166. ped->parse_category(object, p.name);
  1167. _parse_added_editors(main_vbox, ped);
  1168. }
  1169. continue;
  1170. } else if (!(p.usage & PROPERTY_USAGE_EDITOR))
  1171. continue;
  1172. if (p.usage & PROPERTY_USAGE_HIGH_END_GFX && VS::get_singleton()->is_low_end())
  1173. continue; //do not show this property in low end gfx
  1174. if (p.name == "script" && (hide_script || bool(object->call("_hide_script_from_inspector")))) {
  1175. continue;
  1176. }
  1177. String basename = p.name;
  1178. if (group != "") {
  1179. if (group_base != "") {
  1180. if (basename.begins_with(group_base)) {
  1181. basename = basename.replace_first(group_base, "");
  1182. } else if (group_base.begins_with(basename)) {
  1183. //keep it, this is used pretty often
  1184. } else {
  1185. group = ""; //no longer using group base, clear
  1186. }
  1187. }
  1188. }
  1189. if (group != "") {
  1190. basename = group + "/" + basename;
  1191. }
  1192. String name = (basename.find("/") != -1) ? basename.right(basename.find_last("/") + 1) : basename;
  1193. if (capitalize_paths) {
  1194. int dot = name.find(".");
  1195. if (dot != -1) {
  1196. String ov = name.right(dot);
  1197. name = name.substr(0, dot);
  1198. name = name.camelcase_to_underscore().capitalize();
  1199. name += ov;
  1200. } else {
  1201. name = name.camelcase_to_underscore().capitalize();
  1202. }
  1203. }
  1204. String path = basename.left(basename.find_last("/"));
  1205. if (use_filter && filter != "") {
  1206. String cat = path;
  1207. if (capitalize_paths)
  1208. cat = cat.capitalize();
  1209. if (!filter.is_subsequence_ofi(cat) && !filter.is_subsequence_ofi(name))
  1210. continue;
  1211. }
  1212. if (category_vbox == NULL) {
  1213. category_vbox = memnew(VBoxContainer);
  1214. main_vbox->add_child(category_vbox);
  1215. }
  1216. VBoxContainer *current_vbox = main_vbox;
  1217. {
  1218. String acc_path = "";
  1219. int level = 1;
  1220. for (int i = 0; i < path.get_slice_count("/"); i++) {
  1221. String path_name = path.get_slice("/", i);
  1222. if (i > 0)
  1223. acc_path += "/";
  1224. acc_path += path_name;
  1225. if (!item_path.has(acc_path)) {
  1226. EditorInspectorSection *section = memnew(EditorInspectorSection);
  1227. current_vbox->add_child(section);
  1228. sections.push_back(section);
  1229. if (capitalize_paths)
  1230. path_name = path_name.capitalize();
  1231. Color c = sscolor;
  1232. c.a /= level;
  1233. section->setup(acc_path, path_name, object, c, use_folding);
  1234. VBoxContainer *vb = section->get_vbox();
  1235. item_path[acc_path] = vb;
  1236. section_map[vb] = section;
  1237. }
  1238. current_vbox = item_path[acc_path];
  1239. level = (MIN(level + 1, 4));
  1240. }
  1241. if (current_vbox == main_vbox) {
  1242. //do not add directly to the main vbox, given it has no spacing
  1243. if (category_vbox == NULL) {
  1244. category_vbox = memnew(VBoxContainer);
  1245. }
  1246. current_vbox = category_vbox;
  1247. }
  1248. }
  1249. bool checkable = false;
  1250. bool checked = false;
  1251. if (p.usage & PROPERTY_USAGE_CHECKABLE) {
  1252. checkable = true;
  1253. checked = p.usage & PROPERTY_USAGE_CHECKED;
  1254. }
  1255. if (p.usage & PROPERTY_USAGE_RESTART_IF_CHANGED) {
  1256. restart_request_props.insert(p.name);
  1257. }
  1258. String doc_hint;
  1259. if (use_doc_hints) {
  1260. StringName classname = object->get_class_name();
  1261. if (object_class != String()) {
  1262. classname = object_class;
  1263. }
  1264. StringName propname = property_prefix + p.name;
  1265. String descr;
  1266. bool found = false;
  1267. Map<StringName, Map<StringName, String> >::Element *E = descr_cache.find(classname);
  1268. if (E) {
  1269. Map<StringName, String>::Element *F = E->get().find(propname);
  1270. if (F) {
  1271. found = true;
  1272. descr = F->get();
  1273. }
  1274. }
  1275. if (!found) {
  1276. DocData *dd = EditorHelp::get_doc_data();
  1277. Map<String, DocData::ClassDoc>::Element *F = dd->class_list.find(classname);
  1278. while (F && descr == String()) {
  1279. for (int i = 0; i < F->get().properties.size(); i++) {
  1280. if (F->get().properties[i].name == propname.operator String()) {
  1281. descr = F->get().properties[i].description.strip_edges().word_wrap(80);
  1282. break;
  1283. }
  1284. }
  1285. if (!F->get().inherits.empty()) {
  1286. F = dd->class_list.find(F->get().inherits);
  1287. } else {
  1288. break;
  1289. }
  1290. }
  1291. descr_cache[classname][propname] = descr;
  1292. }
  1293. doc_hint = descr;
  1294. }
  1295. for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) {
  1296. Ref<EditorInspectorPlugin> ped = E->get();
  1297. bool exclusive = ped->parse_property(object, p.type, p.name, p.hint, p.hint_string, p.usage);
  1298. List<EditorInspectorPlugin::AddedEditor> editors = ped->added_editors; //make a copy, since plugins may be used again in a sub-inspector
  1299. ped->added_editors.clear();
  1300. for (List<EditorInspectorPlugin::AddedEditor>::Element *F = editors.front(); F; F = F->next()) {
  1301. EditorProperty *ep = Object::cast_to<EditorProperty>(F->get().property_editor);
  1302. if (ep) {
  1303. //set all this before the control gets the ENTER_TREE notification
  1304. ep->object = object;
  1305. if (F->get().properties.size()) {
  1306. if (F->get().properties.size() == 1) {
  1307. //since it's one, associate:
  1308. ep->property = F->get().properties[0];
  1309. ep->property_usage = p.usage;
  1310. //and set label?
  1311. }
  1312. if (F->get().label != String()) {
  1313. ep->set_label(F->get().label);
  1314. } else {
  1315. //use existin one
  1316. ep->set_label(name);
  1317. }
  1318. for (int i = 0; i < F->get().properties.size(); i++) {
  1319. String prop = F->get().properties[i];
  1320. if (!editor_property_map.has(prop)) {
  1321. editor_property_map[prop] = List<EditorProperty *>();
  1322. }
  1323. editor_property_map[prop].push_back(ep);
  1324. }
  1325. }
  1326. ep->set_draw_red(draw_red);
  1327. ep->set_use_folding(use_folding);
  1328. ep->set_checkable(checkable);
  1329. ep->set_checked(checked);
  1330. ep->set_keying(keying);
  1331. ep->set_read_only(read_only);
  1332. }
  1333. current_vbox->add_child(F->get().property_editor);
  1334. if (ep) {
  1335. ep->connect("property_changed", this, "_property_changed");
  1336. if (p.usage & PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED) {
  1337. ep->connect("property_changed", this, "_property_changed_update_all", varray(), CONNECT_DEFERRED);
  1338. }
  1339. ep->connect("property_keyed", this, "_property_keyed");
  1340. ep->connect("property_keyed_with_value", this, "_property_keyed_with_value");
  1341. ep->connect("property_checked", this, "_property_checked");
  1342. ep->connect("selected", this, "_property_selected");
  1343. ep->connect("multiple_properties_changed", this, "_multiple_properties_changed");
  1344. ep->connect("resource_selected", this, "_resource_selected", varray(), CONNECT_DEFERRED);
  1345. ep->connect("object_id_selected", this, "_object_id_selected", varray(), CONNECT_DEFERRED);
  1346. if (doc_hint != String()) {
  1347. ep->set_tooltip(property_prefix + p.name + "::" + doc_hint);
  1348. } else {
  1349. ep->set_tooltip(property_prefix + p.name);
  1350. }
  1351. ep->update_property();
  1352. ep->update_reload_status();
  1353. if (current_selected && ep->property == current_selected) {
  1354. ep->select(current_focusable);
  1355. }
  1356. }
  1357. }
  1358. if (exclusive) {
  1359. break;
  1360. }
  1361. }
  1362. }
  1363. for (List<Ref<EditorInspectorPlugin> >::Element *E = valid_plugins.front(); E; E = E->next()) {
  1364. Ref<EditorInspectorPlugin> ped = E->get();
  1365. ped->parse_end();
  1366. _parse_added_editors(main_vbox, ped);
  1367. }
  1368. //see if this property exists and should be kept
  1369. }
  1370. void EditorInspector::update_property(const String &p_prop) {
  1371. if (!editor_property_map.has(p_prop))
  1372. return;
  1373. for (List<EditorProperty *>::Element *E = editor_property_map[p_prop].front(); E; E = E->next()) {
  1374. E->get()->update_property();
  1375. E->get()->update_reload_status();
  1376. }
  1377. }
  1378. void EditorInspector::_clear() {
  1379. while (main_vbox->get_child_count()) {
  1380. memdelete(main_vbox->get_child(0));
  1381. }
  1382. property_selected = StringName();
  1383. property_focusable = -1;
  1384. editor_property_map.clear();
  1385. sections.clear();
  1386. pending.clear();
  1387. restart_request_props.clear();
  1388. }
  1389. void EditorInspector::refresh() {
  1390. if (refresh_countdown > 0 || changing)
  1391. return;
  1392. refresh_countdown = EditorSettings::get_singleton()->get("docks/property_editor/auto_refresh_interval");
  1393. }
  1394. Object *EditorInspector::get_edited_object() {
  1395. return object;
  1396. }
  1397. void EditorInspector::edit(Object *p_object) {
  1398. if (object == p_object)
  1399. return;
  1400. if (object) {
  1401. _clear();
  1402. object->remove_change_receptor(this);
  1403. }
  1404. object = p_object;
  1405. if (object) {
  1406. update_scroll_request = 0; //reset
  1407. if (scroll_cache.has(object->get_instance_id())) { //if exists, set something else
  1408. update_scroll_request = scroll_cache[object->get_instance_id()]; //done this way because wait until full size is accommodated
  1409. }
  1410. object->add_change_receptor(this);
  1411. update_tree();
  1412. }
  1413. }
  1414. void EditorInspector::set_keying(bool p_active) {
  1415. if (keying == p_active)
  1416. return;
  1417. keying = p_active;
  1418. update_tree();
  1419. }
  1420. void EditorInspector::set_read_only(bool p_read_only) {
  1421. read_only = p_read_only;
  1422. update_tree();
  1423. }
  1424. bool EditorInspector::is_capitalize_paths_enabled() const {
  1425. return capitalize_paths;
  1426. }
  1427. void EditorInspector::set_enable_capitalize_paths(bool p_capitalize) {
  1428. capitalize_paths = p_capitalize;
  1429. update_tree();
  1430. }
  1431. void EditorInspector::set_autoclear(bool p_enable) {
  1432. autoclear = p_enable;
  1433. }
  1434. void EditorInspector::set_show_categories(bool p_show) {
  1435. show_categories = p_show;
  1436. update_tree();
  1437. }
  1438. void EditorInspector::set_use_doc_hints(bool p_enable) {
  1439. use_doc_hints = p_enable;
  1440. update_tree();
  1441. }
  1442. void EditorInspector::set_hide_script(bool p_hide) {
  1443. hide_script = p_hide;
  1444. update_tree();
  1445. }
  1446. void EditorInspector::set_use_filter(bool p_use) {
  1447. use_filter = p_use;
  1448. update_tree();
  1449. }
  1450. void EditorInspector::register_text_enter(Node *p_line_edit) {
  1451. search_box = Object::cast_to<LineEdit>(p_line_edit);
  1452. if (search_box)
  1453. search_box->connect("text_changed", this, "_filter_changed");
  1454. }
  1455. void EditorInspector::_filter_changed(const String &p_text) {
  1456. _clear();
  1457. update_tree();
  1458. }
  1459. void EditorInspector::set_use_folding(bool p_enable) {
  1460. use_folding = p_enable;
  1461. update_tree();
  1462. }
  1463. bool EditorInspector::is_using_folding() {
  1464. return use_folding;
  1465. }
  1466. void EditorInspector::collapse_all_folding() {
  1467. for (List<EditorInspectorSection *>::Element *E = sections.front(); E; E = E->next()) {
  1468. E->get()->fold();
  1469. }
  1470. for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) {
  1471. for (List<EditorProperty *>::Element *E = F->get().front(); E; E = E->next()) {
  1472. E->get()->collapse_all_folding();
  1473. }
  1474. }
  1475. }
  1476. void EditorInspector::expand_all_folding() {
  1477. for (List<EditorInspectorSection *>::Element *E = sections.front(); E; E = E->next()) {
  1478. E->get()->unfold();
  1479. }
  1480. for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) {
  1481. for (List<EditorProperty *>::Element *E = F->get().front(); E; E = E->next()) {
  1482. E->get()->expand_all_folding();
  1483. }
  1484. }
  1485. }
  1486. void EditorInspector::set_scroll_offset(int p_offset) {
  1487. set_v_scroll(p_offset);
  1488. }
  1489. int EditorInspector::get_scroll_offset() const {
  1490. return get_v_scroll();
  1491. }
  1492. void EditorInspector::set_sub_inspector(bool p_enable) {
  1493. sub_inspector = p_enable;
  1494. if (!is_inside_tree())
  1495. return;
  1496. if (sub_inspector) {
  1497. add_style_override("bg", get_stylebox("sub_inspector_bg", "Editor"));
  1498. } else {
  1499. add_style_override("bg", get_stylebox("bg", "Tree"));
  1500. }
  1501. }
  1502. void EditorInspector::_edit_request_change(Object *p_object, const String &p_property) {
  1503. if (object != p_object) //may be undoing/redoing for a non edited object, so ignore
  1504. return;
  1505. if (changing)
  1506. return;
  1507. if (p_property == String())
  1508. update_tree_pending = true;
  1509. else {
  1510. pending.insert(p_property);
  1511. }
  1512. }
  1513. void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bool p_refresh_all, const String &p_changed_field) {
  1514. if (autoclear && editor_property_map.has(p_name)) {
  1515. for (List<EditorProperty *>::Element *E = editor_property_map[p_name].front(); E; E = E->next()) {
  1516. if (E->get()->is_checkable()) {
  1517. E->get()->set_checked(true);
  1518. }
  1519. }
  1520. }
  1521. if (!undo_redo || bool(object->call("_dont_undo_redo"))) {
  1522. object->set(p_name, p_value);
  1523. if (p_refresh_all)
  1524. _edit_request_change(object, "");
  1525. else
  1526. _edit_request_change(object, p_name);
  1527. emit_signal(_prop_edited, p_name);
  1528. } else if (Object::cast_to<MultiNodeEdit>(object)) {
  1529. Object::cast_to<MultiNodeEdit>(object)->set_property_field(p_name, p_value, p_changed_field);
  1530. _edit_request_change(object, p_name);
  1531. emit_signal(_prop_edited, p_name);
  1532. } else {
  1533. undo_redo->create_action(TTR("Set") + " " + p_name, UndoRedo::MERGE_ENDS);
  1534. undo_redo->add_do_property(object, p_name, p_value);
  1535. undo_redo->add_undo_property(object, p_name, object->get(p_name));
  1536. if (p_refresh_all) {
  1537. undo_redo->add_do_method(this, "_edit_request_change", object, "");
  1538. undo_redo->add_undo_method(this, "_edit_request_change", object, "");
  1539. } else {
  1540. undo_redo->add_do_method(this, "_edit_request_change", object, p_name);
  1541. undo_redo->add_undo_method(this, "_edit_request_change", object, p_name);
  1542. }
  1543. Resource *r = Object::cast_to<Resource>(object);
  1544. if (r) {
  1545. if (String(p_name) == "resource_local_to_scene") {
  1546. bool prev = object->get(p_name);
  1547. bool next = p_value;
  1548. if (next) {
  1549. undo_redo->add_do_method(r, "setup_local_to_scene");
  1550. }
  1551. if (prev) {
  1552. undo_redo->add_undo_method(r, "setup_local_to_scene");
  1553. }
  1554. }
  1555. }
  1556. undo_redo->add_do_method(this, "emit_signal", _prop_edited, p_name);
  1557. undo_redo->add_undo_method(this, "emit_signal", _prop_edited, p_name);
  1558. undo_redo->commit_action();
  1559. }
  1560. if (editor_property_map.has(p_name)) {
  1561. for (List<EditorProperty *>::Element *E = editor_property_map[p_name].front(); E; E = E->next()) {
  1562. E->get()->update_reload_status();
  1563. }
  1564. }
  1565. }
  1566. void EditorInspector::_property_changed(const String &p_path, const Variant &p_value, const String &p_name, bool changing) {
  1567. // The "changing" variable must be true for properties that trigger events as typing occurs,
  1568. // like "text_changed" signal. eg: Text property of Label, Button, RichTextLabel, etc.
  1569. if (changing)
  1570. this->changing++;
  1571. _edit_set(p_path, p_value, false, p_name);
  1572. if (changing)
  1573. this->changing--;
  1574. if (restart_request_props.has(p_path)) {
  1575. emit_signal("restart_requested");
  1576. }
  1577. }
  1578. void EditorInspector::_property_changed_update_all(const String &p_path, const Variant &p_value, const String &p_name, bool p_changing) {
  1579. update_tree();
  1580. }
  1581. void EditorInspector::_multiple_properties_changed(Vector<String> p_paths, Array p_values) {
  1582. ERR_FAIL_COND(p_paths.size() == 0 || p_values.size() == 0);
  1583. ERR_FAIL_COND(p_paths.size() != p_values.size());
  1584. String names;
  1585. for (int i = 0; i < p_paths.size(); i++) {
  1586. if (i > 0)
  1587. names += ",";
  1588. names += p_paths[i];
  1589. }
  1590. undo_redo->create_action(TTR("Set Multiple:") + " " + names, UndoRedo::MERGE_ENDS);
  1591. for (int i = 0; i < p_paths.size(); i++) {
  1592. _edit_set(p_paths[i], p_values[i], false, "");
  1593. if (restart_request_props.has(p_paths[i])) {
  1594. emit_signal("restart_requested");
  1595. }
  1596. }
  1597. changing++;
  1598. undo_redo->commit_action();
  1599. changing--;
  1600. }
  1601. void EditorInspector::_property_keyed(const String &p_path, bool p_advance) {
  1602. if (!object)
  1603. return;
  1604. emit_signal("property_keyed", p_path, object->get(p_path), p_advance); //second param is deprecated
  1605. }
  1606. void EditorInspector::_property_keyed_with_value(const String &p_path, const Variant &p_value, bool p_advance) {
  1607. if (!object)
  1608. return;
  1609. emit_signal("property_keyed", p_path, p_value, p_advance); //second param is deprecated
  1610. }
  1611. void EditorInspector::_property_checked(const String &p_path, bool p_checked) {
  1612. if (!object)
  1613. return;
  1614. //property checked
  1615. if (autoclear) {
  1616. if (!p_checked) {
  1617. object->set(p_path, Variant());
  1618. } else {
  1619. Variant to_create;
  1620. List<PropertyInfo> pinfo;
  1621. object->get_property_list(&pinfo);
  1622. for (List<PropertyInfo>::Element *E = pinfo.front(); E; E = E->next()) {
  1623. if (E->get().name == p_path) {
  1624. Variant::CallError ce;
  1625. to_create = Variant::construct(E->get().type, NULL, 0, ce);
  1626. break;
  1627. }
  1628. }
  1629. object->set(p_path, to_create);
  1630. }
  1631. if (editor_property_map.has(p_path)) {
  1632. for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
  1633. E->get()->update_property();
  1634. E->get()->update_reload_status();
  1635. }
  1636. }
  1637. } else {
  1638. emit_signal("property_toggled", p_path, p_checked);
  1639. }
  1640. }
  1641. void EditorInspector::_property_selected(const String &p_path, int p_focusable) {
  1642. property_selected = p_path;
  1643. property_focusable = p_focusable;
  1644. //deselect the others
  1645. for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) {
  1646. if (F->key() == property_selected)
  1647. continue;
  1648. for (List<EditorProperty *>::Element *E = F->get().front(); E; E = E->next()) {
  1649. if (E->get()->is_selected())
  1650. E->get()->deselect();
  1651. }
  1652. }
  1653. emit_signal("property_selected", p_path);
  1654. }
  1655. void EditorInspector::_object_id_selected(const String &p_path, ObjectID p_id) {
  1656. emit_signal("object_id_selected", p_id);
  1657. }
  1658. void EditorInspector::_resource_selected(const String &p_path, RES p_resource) {
  1659. emit_signal("resource_selected", p_resource, p_path);
  1660. }
  1661. void EditorInspector::_node_removed(Node *p_node) {
  1662. if (p_node == object) {
  1663. edit(NULL);
  1664. }
  1665. }
  1666. void EditorInspector::_notification(int p_what) {
  1667. if (p_what == NOTIFICATION_ENTER_TREE) {
  1668. if (sub_inspector) {
  1669. add_style_override("bg", get_stylebox("sub_inspector_bg", "Editor"));
  1670. } else {
  1671. add_style_override("bg", get_stylebox("bg", "Tree"));
  1672. get_tree()->connect("node_removed", this, "_node_removed");
  1673. }
  1674. }
  1675. if (p_what == NOTIFICATION_EXIT_TREE) {
  1676. if (!sub_inspector) {
  1677. get_tree()->disconnect("node_removed", this, "_node_removed");
  1678. }
  1679. edit(NULL);
  1680. }
  1681. if (p_what == NOTIFICATION_PROCESS) {
  1682. if (update_scroll_request >= 0) {
  1683. get_v_scrollbar()->call_deferred("set_value", update_scroll_request);
  1684. update_scroll_request = -1;
  1685. }
  1686. if (refresh_countdown > 0) {
  1687. refresh_countdown -= get_process_delta_time();
  1688. if (refresh_countdown <= 0) {
  1689. for (Map<StringName, List<EditorProperty *> >::Element *F = editor_property_map.front(); F; F = F->next()) {
  1690. for (List<EditorProperty *>::Element *E = F->get().front(); E; E = E->next()) {
  1691. E->get()->update_property();
  1692. E->get()->update_reload_status();
  1693. }
  1694. }
  1695. }
  1696. }
  1697. changing++;
  1698. if (update_tree_pending) {
  1699. update_tree();
  1700. update_tree_pending = false;
  1701. pending.clear();
  1702. } else {
  1703. while (pending.size()) {
  1704. StringName prop = pending.front()->get();
  1705. if (editor_property_map.has(prop)) {
  1706. for (List<EditorProperty *>::Element *E = editor_property_map[prop].front(); E; E = E->next()) {
  1707. E->get()->update_property();
  1708. E->get()->update_reload_status();
  1709. }
  1710. }
  1711. pending.erase(pending.front());
  1712. }
  1713. }
  1714. changing--;
  1715. }
  1716. if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) {
  1717. if (sub_inspector) {
  1718. add_style_override("bg", get_stylebox("sub_inspector_bg", "Editor"));
  1719. } else if (is_inside_tree()) {
  1720. add_style_override("bg", get_stylebox("bg", "Tree"));
  1721. }
  1722. update_tree();
  1723. }
  1724. }
  1725. void EditorInspector::_changed_callback(Object *p_changed, const char *p_prop) {
  1726. //this is called when property change is notified via _change_notify()
  1727. _edit_request_change(p_changed, p_prop);
  1728. }
  1729. void EditorInspector::_vscroll_changed(double p_offset) {
  1730. if (update_scroll_request >= 0) //waiting, do nothing
  1731. return;
  1732. if (object) {
  1733. scroll_cache[object->get_instance_id()] = p_offset;
  1734. }
  1735. }
  1736. void EditorInspector::set_property_prefix(const String &p_prefix) {
  1737. property_prefix = p_prefix;
  1738. }
  1739. String EditorInspector::get_property_prefix() const {
  1740. return property_prefix;
  1741. }
  1742. void EditorInspector::set_object_class(const String &p_class) {
  1743. object_class = p_class;
  1744. }
  1745. String EditorInspector::get_object_class() const {
  1746. return object_class;
  1747. }
  1748. void EditorInspector::_bind_methods() {
  1749. ClassDB::bind_method("_property_changed", &EditorInspector::_property_changed, DEFVAL(""), DEFVAL(false));
  1750. ClassDB::bind_method("_multiple_properties_changed", &EditorInspector::_multiple_properties_changed);
  1751. ClassDB::bind_method("_property_changed_update_all", &EditorInspector::_property_changed_update_all);
  1752. ClassDB::bind_method("_edit_request_change", &EditorInspector::_edit_request_change);
  1753. ClassDB::bind_method("_node_removed", &EditorInspector::_node_removed);
  1754. ClassDB::bind_method("_filter_changed", &EditorInspector::_filter_changed);
  1755. ClassDB::bind_method("_property_keyed", &EditorInspector::_property_keyed);
  1756. ClassDB::bind_method("_property_keyed_with_value", &EditorInspector::_property_keyed_with_value);
  1757. ClassDB::bind_method("_property_checked", &EditorInspector::_property_checked);
  1758. ClassDB::bind_method("_property_selected", &EditorInspector::_property_selected);
  1759. ClassDB::bind_method("_resource_selected", &EditorInspector::_resource_selected);
  1760. ClassDB::bind_method("_object_id_selected", &EditorInspector::_object_id_selected);
  1761. ClassDB::bind_method("_vscroll_changed", &EditorInspector::_vscroll_changed);
  1762. ClassDB::bind_method("refresh", &EditorInspector::refresh);
  1763. ADD_SIGNAL(MethodInfo("property_selected", PropertyInfo(Variant::STRING, "property")));
  1764. ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property")));
  1765. ADD_SIGNAL(MethodInfo("resource_selected", PropertyInfo(Variant::OBJECT, "res"), PropertyInfo(Variant::STRING, "prop")));
  1766. ADD_SIGNAL(MethodInfo("object_id_selected", PropertyInfo(Variant::INT, "id")));
  1767. ADD_SIGNAL(MethodInfo("property_edited", PropertyInfo(Variant::STRING, "property")));
  1768. ADD_SIGNAL(MethodInfo("property_toggled", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::BOOL, "checked")));
  1769. ADD_SIGNAL(MethodInfo("restart_requested"));
  1770. }
  1771. EditorInspector::EditorInspector() {
  1772. object = NULL;
  1773. undo_redo = NULL;
  1774. main_vbox = memnew(VBoxContainer);
  1775. main_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
  1776. main_vbox->add_constant_override("separation", 0);
  1777. add_child(main_vbox);
  1778. set_enable_h_scroll(false);
  1779. set_enable_v_scroll(true);
  1780. show_categories = false;
  1781. hide_script = true;
  1782. use_doc_hints = false;
  1783. capitalize_paths = true;
  1784. use_filter = false;
  1785. autoclear = false;
  1786. changing = 0;
  1787. use_folding = false;
  1788. update_all_pending = false;
  1789. update_tree_pending = false;
  1790. refresh_countdown = 0;
  1791. read_only = false;
  1792. search_box = NULL;
  1793. keying = false;
  1794. _prop_edited = "property_edited";
  1795. set_process(true);
  1796. property_focusable = -1;
  1797. sub_inspector = false;
  1798. get_v_scrollbar()->connect("value_changed", this, "_vscroll_changed");
  1799. update_scroll_request = -1;
  1800. }