theme_editor_plugin.cpp 124 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441
  1. /**************************************************************************/
  2. /* theme_editor_plugin.cpp */
  3. /**************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /**************************************************************************/
  8. /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
  9. /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /**************************************************************************/
  30. #include "theme_editor_plugin.h"
  31. #include "core/os/keyboard.h"
  32. #include "editor/editor_resource_picker.h"
  33. #include "editor/editor_scale.h"
  34. #include "editor/progress_dialog.h"
  35. void ThemeItemImportTree::_update_items_tree() {
  36. import_items_tree->clear();
  37. TreeItem *root = import_items_tree->create_item();
  38. if (base_theme.is_null()) {
  39. return;
  40. }
  41. String filter_text = import_items_filter->get_text();
  42. List<StringName> types;
  43. List<StringName> names;
  44. List<StringName> filtered_names;
  45. base_theme->get_type_list(&types);
  46. types.sort_custom<StringName::AlphCompare>();
  47. int color_amount = 0;
  48. int constant_amount = 0;
  49. int font_amount = 0;
  50. int icon_amount = 0;
  51. int stylebox_amount = 0;
  52. tree_color_items.clear();
  53. tree_constant_items.clear();
  54. tree_font_items.clear();
  55. tree_icon_items.clear();
  56. tree_stylebox_items.clear();
  57. for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
  58. String type_name = (String)E->get();
  59. TreeItem *type_node = import_items_tree->create_item(root);
  60. type_node->set_meta("_can_be_imported", false);
  61. type_node->set_collapsed(true);
  62. type_node->set_text(0, type_name);
  63. type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);
  64. type_node->set_checked(IMPORT_ITEM, false);
  65. type_node->set_editable(IMPORT_ITEM, true);
  66. type_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);
  67. type_node->set_checked(IMPORT_ITEM_DATA, false);
  68. type_node->set_editable(IMPORT_ITEM_DATA, true);
  69. bool is_matching_filter = (filter_text.empty() || type_name.findn(filter_text) > -1);
  70. bool has_filtered_items = false;
  71. bool any_checked = false;
  72. bool any_checked_with_data = false;
  73. for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {
  74. Theme::DataType dt = (Theme::DataType)i;
  75. names.clear();
  76. filtered_names.clear();
  77. base_theme->get_theme_item_list(dt, E->get(), &names);
  78. bool data_type_has_filtered_items = false;
  79. for (List<StringName>::Element *F = names.front(); F; F = F->next()) {
  80. String item_name = (String)F->get();
  81. bool is_item_matching_filter = (item_name.findn(filter_text) > -1);
  82. if (!filter_text.empty() && !is_matching_filter && !is_item_matching_filter) {
  83. continue;
  84. }
  85. // Only mark this if actual items match the filter and not just the type group.
  86. if (!filter_text.empty() && is_item_matching_filter) {
  87. has_filtered_items = true;
  88. data_type_has_filtered_items = true;
  89. }
  90. filtered_names.push_back(F->get());
  91. }
  92. if (filtered_names.size() == 0) {
  93. continue;
  94. }
  95. TreeItem *data_type_node = import_items_tree->create_item(type_node);
  96. data_type_node->set_meta("_can_be_imported", false);
  97. data_type_node->set_metadata(0, i);
  98. data_type_node->set_collapsed(!data_type_has_filtered_items);
  99. data_type_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);
  100. data_type_node->set_checked(IMPORT_ITEM, false);
  101. data_type_node->set_editable(IMPORT_ITEM, true);
  102. data_type_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);
  103. data_type_node->set_checked(IMPORT_ITEM_DATA, false);
  104. data_type_node->set_editable(IMPORT_ITEM_DATA, true);
  105. List<TreeItem *> *item_list;
  106. switch (dt) {
  107. case Theme::DATA_TYPE_COLOR:
  108. data_type_node->set_icon(0, get_icon("Color", "EditorIcons"));
  109. data_type_node->set_text(0, TTR("Colors"));
  110. item_list = &tree_color_items;
  111. color_amount += filtered_names.size();
  112. break;
  113. case Theme::DATA_TYPE_CONSTANT:
  114. data_type_node->set_icon(0, get_icon("MemberConstant", "EditorIcons"));
  115. data_type_node->set_text(0, TTR("Constants"));
  116. item_list = &tree_constant_items;
  117. constant_amount += filtered_names.size();
  118. break;
  119. case Theme::DATA_TYPE_FONT:
  120. data_type_node->set_icon(0, get_icon("Font", "EditorIcons"));
  121. data_type_node->set_text(0, TTR("Fonts"));
  122. item_list = &tree_font_items;
  123. font_amount += filtered_names.size();
  124. break;
  125. case Theme::DATA_TYPE_ICON:
  126. data_type_node->set_icon(0, get_icon("ImageTexture", "EditorIcons"));
  127. data_type_node->set_text(0, TTR("Icons"));
  128. item_list = &tree_icon_items;
  129. icon_amount += filtered_names.size();
  130. break;
  131. case Theme::DATA_TYPE_STYLEBOX:
  132. data_type_node->set_icon(0, get_icon("StyleBoxFlat", "EditorIcons"));
  133. data_type_node->set_text(0, TTR("Styleboxes"));
  134. item_list = &tree_stylebox_items;
  135. stylebox_amount += filtered_names.size();
  136. break;
  137. case Theme::DATA_TYPE_MAX:
  138. break; // Can't happen, but silences warning.
  139. }
  140. bool data_type_any_checked = false;
  141. bool data_type_any_checked_with_data = false;
  142. filtered_names.sort_custom<StringName::AlphCompare>();
  143. for (List<StringName>::Element *F = filtered_names.front(); F; F = F->next()) {
  144. TreeItem *item_node = import_items_tree->create_item(data_type_node);
  145. item_node->set_meta("_can_be_imported", true);
  146. item_node->set_text(0, F->get());
  147. item_node->set_cell_mode(IMPORT_ITEM, TreeItem::CELL_MODE_CHECK);
  148. item_node->set_checked(IMPORT_ITEM, false);
  149. item_node->set_editable(IMPORT_ITEM, true);
  150. item_node->set_cell_mode(IMPORT_ITEM_DATA, TreeItem::CELL_MODE_CHECK);
  151. item_node->set_checked(IMPORT_ITEM_DATA, false);
  152. item_node->set_editable(IMPORT_ITEM_DATA, true);
  153. _restore_selected_item(item_node);
  154. if (item_node->is_checked(IMPORT_ITEM)) {
  155. data_type_any_checked = true;
  156. any_checked = true;
  157. }
  158. if (item_node->is_checked(IMPORT_ITEM_DATA)) {
  159. data_type_any_checked_with_data = true;
  160. any_checked_with_data = true;
  161. }
  162. item_list->push_back(item_node);
  163. }
  164. data_type_node->set_checked(IMPORT_ITEM, data_type_any_checked);
  165. data_type_node->set_checked(IMPORT_ITEM_DATA, data_type_any_checked && data_type_any_checked_with_data);
  166. }
  167. // Remove the item if it doesn't match the filter in any way.
  168. if (!is_matching_filter && !has_filtered_items) {
  169. root->remove_child(type_node);
  170. memdelete(type_node);
  171. continue;
  172. }
  173. // Show one level inside of a type group if there are matches in items.
  174. if (!filter_text.empty() && has_filtered_items) {
  175. type_node->set_collapsed(false);
  176. }
  177. type_node->set_checked(IMPORT_ITEM, any_checked);
  178. type_node->set_checked(IMPORT_ITEM_DATA, any_checked && any_checked_with_data);
  179. }
  180. if (color_amount > 0) {
  181. Array arr;
  182. arr.push_back(color_amount);
  183. select_colors_label->set_text(TTR("{num} color(s)").format(arr, "{num}"));
  184. select_all_colors_button->set_visible(true);
  185. select_full_colors_button->set_visible(true);
  186. deselect_all_colors_button->set_visible(true);
  187. } else {
  188. select_colors_label->set_text(TTR("No colors found."));
  189. select_all_colors_button->set_visible(false);
  190. select_full_colors_button->set_visible(false);
  191. deselect_all_colors_button->set_visible(false);
  192. }
  193. if (constant_amount > 0) {
  194. Array arr;
  195. arr.push_back(constant_amount);
  196. select_constants_label->set_text(TTR("{num} constant(s)").format(arr, "{num}"));
  197. select_all_constants_button->set_visible(true);
  198. select_full_constants_button->set_visible(true);
  199. deselect_all_constants_button->set_visible(true);
  200. } else {
  201. select_constants_label->set_text(TTR("No constants found."));
  202. select_all_constants_button->set_visible(false);
  203. select_full_constants_button->set_visible(false);
  204. deselect_all_constants_button->set_visible(false);
  205. }
  206. if (font_amount > 0) {
  207. Array arr;
  208. arr.push_back(font_amount);
  209. select_fonts_label->set_text(TTR("{num} font(s)").format(arr, "{num}"));
  210. select_all_fonts_button->set_visible(true);
  211. select_full_fonts_button->set_visible(true);
  212. deselect_all_fonts_button->set_visible(true);
  213. } else {
  214. select_fonts_label->set_text(TTR("No fonts found."));
  215. select_all_fonts_button->set_visible(false);
  216. select_full_fonts_button->set_visible(false);
  217. deselect_all_fonts_button->set_visible(false);
  218. }
  219. if (icon_amount > 0) {
  220. Array arr;
  221. arr.push_back(icon_amount);
  222. select_icons_label->set_text(TTR("{num} icon(s)").format(arr, "{num}"));
  223. select_all_icons_button->set_visible(true);
  224. select_full_icons_button->set_visible(true);
  225. deselect_all_icons_button->set_visible(true);
  226. select_icons_warning_hb->set_visible(true);
  227. } else {
  228. select_icons_label->set_text(TTR("No icons found."));
  229. select_all_icons_button->set_visible(false);
  230. select_full_icons_button->set_visible(false);
  231. deselect_all_icons_button->set_visible(false);
  232. select_icons_warning_hb->set_visible(false);
  233. }
  234. if (stylebox_amount > 0) {
  235. Array arr;
  236. arr.push_back(stylebox_amount);
  237. select_styleboxes_label->set_text(TTR("{num} stylebox(es)").format(arr, "{num}"));
  238. select_all_styleboxes_button->set_visible(true);
  239. select_full_styleboxes_button->set_visible(true);
  240. deselect_all_styleboxes_button->set_visible(true);
  241. } else {
  242. select_styleboxes_label->set_text(TTR("No styleboxes found."));
  243. select_all_styleboxes_button->set_visible(false);
  244. select_full_styleboxes_button->set_visible(false);
  245. deselect_all_styleboxes_button->set_visible(false);
  246. }
  247. }
  248. void ThemeItemImportTree::_toggle_type_items(bool p_collapse) {
  249. TreeItem *root = import_items_tree->get_root();
  250. if (!root) {
  251. return;
  252. }
  253. TreeItem *type_node = root->get_children();
  254. while (type_node) {
  255. type_node->set_collapsed(p_collapse);
  256. type_node = type_node->get_next();
  257. }
  258. }
  259. void ThemeItemImportTree::_filter_text_changed(const String &p_value) {
  260. _update_items_tree();
  261. }
  262. void ThemeItemImportTree::_store_selected_item(TreeItem *p_tree_item) {
  263. if (!p_tree_item->get_meta("_can_be_imported")) {
  264. return;
  265. }
  266. TreeItem *data_type_node = p_tree_item->get_parent();
  267. if (!data_type_node || data_type_node == import_items_tree->get_root()) {
  268. return;
  269. }
  270. TreeItem *type_node = data_type_node->get_parent();
  271. if (!type_node || type_node == import_items_tree->get_root()) {
  272. return;
  273. }
  274. ThemeItem ti;
  275. ti.item_name = p_tree_item->get_text(0);
  276. ti.data_type = (Theme::DataType)(int)data_type_node->get_metadata(0);
  277. ti.type_name = type_node->get_text(0);
  278. bool import = p_tree_item->is_checked(IMPORT_ITEM);
  279. bool with_data = p_tree_item->is_checked(IMPORT_ITEM_DATA);
  280. if (import && with_data) {
  281. selected_items[ti] = SELECT_IMPORT_FULL;
  282. } else if (import) {
  283. selected_items[ti] = SELECT_IMPORT_DEFINITION;
  284. } else {
  285. selected_items.erase(ti);
  286. }
  287. _update_total_selected(ti.data_type);
  288. }
  289. void ThemeItemImportTree::_restore_selected_item(TreeItem *p_tree_item) {
  290. if (!p_tree_item->get_meta("_can_be_imported")) {
  291. return;
  292. }
  293. TreeItem *data_type_node = p_tree_item->get_parent();
  294. if (!data_type_node || data_type_node == import_items_tree->get_root()) {
  295. return;
  296. }
  297. TreeItem *type_node = data_type_node->get_parent();
  298. if (!type_node || type_node == import_items_tree->get_root()) {
  299. return;
  300. }
  301. ThemeItem ti;
  302. ti.item_name = p_tree_item->get_text(0);
  303. ti.data_type = (Theme::DataType)(int)data_type_node->get_metadata(0);
  304. ti.type_name = type_node->get_text(0);
  305. if (!selected_items.has(ti)) {
  306. p_tree_item->set_checked(IMPORT_ITEM, false);
  307. p_tree_item->set_checked(IMPORT_ITEM_DATA, false);
  308. return;
  309. }
  310. if (selected_items[ti] == SELECT_IMPORT_FULL) {
  311. p_tree_item->set_checked(IMPORT_ITEM, true);
  312. p_tree_item->set_checked(IMPORT_ITEM_DATA, true);
  313. } else if (selected_items[ti] == SELECT_IMPORT_DEFINITION) {
  314. p_tree_item->set_checked(IMPORT_ITEM, true);
  315. p_tree_item->set_checked(IMPORT_ITEM_DATA, false);
  316. }
  317. }
  318. void ThemeItemImportTree::_update_total_selected(Theme::DataType p_data_type) {
  319. ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
  320. Label *total_selected_items_label;
  321. switch (p_data_type) {
  322. case Theme::DATA_TYPE_COLOR:
  323. total_selected_items_label = total_selected_colors_label;
  324. break;
  325. case Theme::DATA_TYPE_CONSTANT:
  326. total_selected_items_label = total_selected_constants_label;
  327. break;
  328. case Theme::DATA_TYPE_FONT:
  329. total_selected_items_label = total_selected_fonts_label;
  330. break;
  331. case Theme::DATA_TYPE_ICON:
  332. total_selected_items_label = total_selected_icons_label;
  333. break;
  334. case Theme::DATA_TYPE_STYLEBOX:
  335. total_selected_items_label = total_selected_styleboxes_label;
  336. break;
  337. case Theme::DATA_TYPE_MAX:
  338. return; // Can't happen, but silences warning.
  339. }
  340. if (!total_selected_items_label) {
  341. return;
  342. }
  343. int count = 0;
  344. for (Map<ThemeItem, ItemCheckedState>::Element *E = selected_items.front(); E; E = E->next()) {
  345. ThemeItem ti = E->key();
  346. if (ti.data_type == p_data_type) {
  347. count++;
  348. }
  349. }
  350. if (count == 0) {
  351. total_selected_items_label->hide();
  352. } else {
  353. Array arr;
  354. arr.push_back(count);
  355. total_selected_items_label->set_text(TTR("{num} currently selected").format(arr, "{num}"));
  356. total_selected_items_label->show();
  357. }
  358. }
  359. void ThemeItemImportTree::_tree_item_edited() {
  360. if (updating_tree) {
  361. return;
  362. }
  363. TreeItem *edited_item = import_items_tree->get_edited();
  364. if (!edited_item) {
  365. return;
  366. }
  367. updating_tree = true;
  368. int edited_column = import_items_tree->get_edited_column();
  369. bool is_checked = edited_item->is_checked(edited_column);
  370. if (is_checked) {
  371. if (edited_column == IMPORT_ITEM_DATA) {
  372. edited_item->set_checked(IMPORT_ITEM, true);
  373. }
  374. _select_all_subitems(edited_item, (edited_column == IMPORT_ITEM_DATA));
  375. } else {
  376. if (edited_column == IMPORT_ITEM) {
  377. edited_item->set_checked(IMPORT_ITEM_DATA, false);
  378. }
  379. _deselect_all_subitems(edited_item, (edited_column == IMPORT_ITEM));
  380. }
  381. _update_parent_items(edited_item);
  382. _store_selected_item(edited_item);
  383. updating_tree = false;
  384. }
  385. void ThemeItemImportTree::_select_all_subitems(TreeItem *p_root_item, bool p_select_with_data) {
  386. TreeItem *child_item = p_root_item->get_children();
  387. while (child_item) {
  388. child_item->set_checked(IMPORT_ITEM, true);
  389. if (p_select_with_data) {
  390. child_item->set_checked(IMPORT_ITEM_DATA, true);
  391. }
  392. _store_selected_item(child_item);
  393. _select_all_subitems(child_item, p_select_with_data);
  394. child_item = child_item->get_next();
  395. }
  396. }
  397. void ThemeItemImportTree::_deselect_all_subitems(TreeItem *p_root_item, bool p_deselect_completely) {
  398. TreeItem *child_item = p_root_item->get_children();
  399. while (child_item) {
  400. child_item->set_checked(IMPORT_ITEM_DATA, false);
  401. if (p_deselect_completely) {
  402. child_item->set_checked(IMPORT_ITEM, false);
  403. }
  404. _store_selected_item(child_item);
  405. _deselect_all_subitems(child_item, p_deselect_completely);
  406. child_item = child_item->get_next();
  407. }
  408. }
  409. void ThemeItemImportTree::_update_parent_items(TreeItem *p_root_item) {
  410. TreeItem *parent_item = p_root_item->get_parent();
  411. if (!parent_item) {
  412. return;
  413. }
  414. bool any_checked = false;
  415. bool any_checked_with_data = false;
  416. TreeItem *child_item = parent_item->get_children();
  417. while (child_item) {
  418. if (child_item->is_checked(IMPORT_ITEM)) {
  419. any_checked = true;
  420. }
  421. if (child_item->is_checked(IMPORT_ITEM_DATA)) {
  422. any_checked_with_data = true;
  423. }
  424. child_item = child_item->get_next();
  425. }
  426. parent_item->set_checked(IMPORT_ITEM, any_checked);
  427. parent_item->set_checked(IMPORT_ITEM_DATA, any_checked && any_checked_with_data);
  428. _update_parent_items(parent_item);
  429. }
  430. void ThemeItemImportTree::_select_all_items_pressed() {
  431. if (updating_tree) {
  432. return;
  433. }
  434. updating_tree = true;
  435. TreeItem *root = import_items_tree->get_root();
  436. _select_all_subitems(root, false);
  437. updating_tree = false;
  438. }
  439. void ThemeItemImportTree::_select_full_items_pressed() {
  440. if (updating_tree) {
  441. return;
  442. }
  443. updating_tree = true;
  444. TreeItem *root = import_items_tree->get_root();
  445. _select_all_subitems(root, true);
  446. updating_tree = false;
  447. }
  448. void ThemeItemImportTree::_deselect_all_items_pressed() {
  449. if (updating_tree) {
  450. return;
  451. }
  452. updating_tree = true;
  453. TreeItem *root = import_items_tree->get_root();
  454. _deselect_all_subitems(root, true);
  455. updating_tree = false;
  456. }
  457. void ThemeItemImportTree::_select_all_data_type_pressed(int p_data_type) {
  458. ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
  459. if (updating_tree) {
  460. return;
  461. }
  462. Theme::DataType data_type = (Theme::DataType)p_data_type;
  463. List<TreeItem *> *item_list;
  464. switch (data_type) {
  465. case Theme::DATA_TYPE_COLOR:
  466. item_list = &tree_color_items;
  467. break;
  468. case Theme::DATA_TYPE_CONSTANT:
  469. item_list = &tree_constant_items;
  470. break;
  471. case Theme::DATA_TYPE_FONT:
  472. item_list = &tree_font_items;
  473. break;
  474. case Theme::DATA_TYPE_ICON:
  475. item_list = &tree_icon_items;
  476. break;
  477. case Theme::DATA_TYPE_STYLEBOX:
  478. item_list = &tree_stylebox_items;
  479. break;
  480. case Theme::DATA_TYPE_MAX:
  481. return; // Can't happen, but silences warning.
  482. }
  483. updating_tree = true;
  484. for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {
  485. TreeItem *child_item = E->get();
  486. if (!child_item) {
  487. continue;
  488. }
  489. child_item->set_checked(IMPORT_ITEM, true);
  490. _update_parent_items(child_item);
  491. _store_selected_item(child_item);
  492. }
  493. updating_tree = false;
  494. }
  495. void ThemeItemImportTree::_select_full_data_type_pressed(int p_data_type) {
  496. ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
  497. if (updating_tree) {
  498. return;
  499. }
  500. Theme::DataType data_type = (Theme::DataType)p_data_type;
  501. List<TreeItem *> *item_list;
  502. switch (data_type) {
  503. case Theme::DATA_TYPE_COLOR:
  504. item_list = &tree_color_items;
  505. break;
  506. case Theme::DATA_TYPE_CONSTANT:
  507. item_list = &tree_constant_items;
  508. break;
  509. case Theme::DATA_TYPE_FONT:
  510. item_list = &tree_font_items;
  511. break;
  512. case Theme::DATA_TYPE_ICON:
  513. item_list = &tree_icon_items;
  514. break;
  515. case Theme::DATA_TYPE_STYLEBOX:
  516. item_list = &tree_stylebox_items;
  517. break;
  518. case Theme::DATA_TYPE_MAX:
  519. return; // Can't happen, but silences warning.
  520. }
  521. updating_tree = true;
  522. for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {
  523. TreeItem *child_item = E->get();
  524. if (!child_item) {
  525. continue;
  526. }
  527. child_item->set_checked(IMPORT_ITEM, true);
  528. child_item->set_checked(IMPORT_ITEM_DATA, true);
  529. _update_parent_items(child_item);
  530. _store_selected_item(child_item);
  531. }
  532. updating_tree = false;
  533. }
  534. void ThemeItemImportTree::_deselect_all_data_type_pressed(int p_data_type) {
  535. ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
  536. if (updating_tree) {
  537. return;
  538. }
  539. Theme::DataType data_type = (Theme::DataType)p_data_type;
  540. List<TreeItem *> *item_list;
  541. switch (data_type) {
  542. case Theme::DATA_TYPE_COLOR:
  543. item_list = &tree_color_items;
  544. break;
  545. case Theme::DATA_TYPE_CONSTANT:
  546. item_list = &tree_constant_items;
  547. break;
  548. case Theme::DATA_TYPE_FONT:
  549. item_list = &tree_font_items;
  550. break;
  551. case Theme::DATA_TYPE_ICON:
  552. item_list = &tree_icon_items;
  553. break;
  554. case Theme::DATA_TYPE_STYLEBOX:
  555. item_list = &tree_stylebox_items;
  556. break;
  557. case Theme::DATA_TYPE_MAX:
  558. return; // Can't happen, but silences warning.
  559. }
  560. updating_tree = true;
  561. for (List<TreeItem *>::Element *E = item_list->front(); E; E = E->next()) {
  562. TreeItem *child_item = E->get();
  563. if (!child_item) {
  564. continue;
  565. }
  566. child_item->set_checked(IMPORT_ITEM, false);
  567. child_item->set_checked(IMPORT_ITEM_DATA, false);
  568. _update_parent_items(child_item);
  569. _store_selected_item(child_item);
  570. }
  571. updating_tree = false;
  572. }
  573. void ThemeItemImportTree::_import_selected() {
  574. if (selected_items.size() == 0) {
  575. EditorNode::get_singleton()->show_accept(TTR("Nothing was selected for the import."), TTR("OK"));
  576. return;
  577. }
  578. // Prevent changes from immediately being reported while the operation is still ongoing.
  579. edited_theme->_freeze_change_propagation();
  580. ProgressDialog::get_singleton()->add_task("import_theme_items", TTR("Importing Theme Items"), selected_items.size() + 2);
  581. int idx = 0;
  582. for (Map<ThemeItem, ItemCheckedState>::Element *E = selected_items.front(); E; E = E->next()) {
  583. // Arbitrary number of items to skip from reporting.
  584. // Reduces the number of UI updates that this causes when copying large themes.
  585. if (idx % 10 == 0) {
  586. Array arr;
  587. arr.push_back(idx + 1);
  588. arr.push_back(selected_items.size());
  589. ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Importing items {n}/{n}").format(arr, "{n}"), idx);
  590. }
  591. ItemCheckedState cs = E->get();
  592. ThemeItem ti = E->key();
  593. if (cs == SELECT_IMPORT_DEFINITION || cs == SELECT_IMPORT_FULL) {
  594. Variant item_value = Variant();
  595. if (cs == SELECT_IMPORT_FULL) {
  596. item_value = base_theme->get_theme_item(ti.data_type, ti.item_name, ti.type_name);
  597. } else {
  598. switch (ti.data_type) {
  599. case Theme::DATA_TYPE_COLOR:
  600. item_value = Color();
  601. break;
  602. case Theme::DATA_TYPE_CONSTANT:
  603. item_value = 0;
  604. break;
  605. case Theme::DATA_TYPE_FONT:
  606. item_value = Ref<Font>();
  607. break;
  608. case Theme::DATA_TYPE_ICON:
  609. item_value = Ref<Texture>();
  610. break;
  611. case Theme::DATA_TYPE_STYLEBOX:
  612. item_value = Ref<StyleBox>();
  613. break;
  614. case Theme::DATA_TYPE_MAX:
  615. break; // Can't happen, but silences warning.
  616. }
  617. }
  618. edited_theme->set_theme_item(ti.data_type, ti.item_name, ti.type_name, item_value);
  619. }
  620. idx++;
  621. }
  622. // Allow changes to be reported now that the operation is finished.
  623. ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Updating the editor"), idx++);
  624. edited_theme->_unfreeze_and_propagate_changes();
  625. // Make sure the task is not ended before the editor freezes to update the Inspector.
  626. ProgressDialog::get_singleton()->task_step("import_theme_items", TTR("Finalizing"), idx++);
  627. ProgressDialog::get_singleton()->end_task("import_theme_items");
  628. emit_signal("items_imported");
  629. }
  630. void ThemeItemImportTree::set_edited_theme(const Ref<Theme> &p_theme) {
  631. edited_theme = p_theme;
  632. }
  633. void ThemeItemImportTree::set_base_theme(const Ref<Theme> &p_theme) {
  634. base_theme = p_theme;
  635. }
  636. void ThemeItemImportTree::reset_item_tree() {
  637. import_items_filter->clear();
  638. selected_items.clear();
  639. total_selected_colors_label->hide();
  640. total_selected_constants_label->hide();
  641. total_selected_fonts_label->hide();
  642. total_selected_icons_label->hide();
  643. total_selected_styleboxes_label->hide();
  644. _update_items_tree();
  645. }
  646. bool ThemeItemImportTree::has_selected_items() const {
  647. return (selected_items.size() > 0);
  648. }
  649. void ThemeItemImportTree::_notification(int p_what) {
  650. switch (p_what) {
  651. case NOTIFICATION_ENTER_TREE:
  652. case NOTIFICATION_THEME_CHANGED: {
  653. select_icons_warning_icon->set_texture(get_icon("StatusWarning", "EditorIcons"));
  654. select_icons_warning->add_color_override("font_color", get_color("disabled_font_color", "Editor"));
  655. // Bottom panel buttons.
  656. import_collapse_types_button->set_icon(get_icon("CollapseTree", "EditorIcons"));
  657. import_expand_types_button->set_icon(get_icon("ExpandTree", "EditorIcons"));
  658. import_select_all_button->set_icon(get_icon("ThemeSelectAll", "EditorIcons"));
  659. import_select_full_button->set_icon(get_icon("ThemeSelectFull", "EditorIcons"));
  660. import_deselect_all_button->set_icon(get_icon("ThemeDeselectAll", "EditorIcons"));
  661. // Side panel buttons.
  662. select_colors_icon->set_texture(get_icon("Color", "EditorIcons"));
  663. deselect_all_colors_button->set_icon(get_icon("ThemeDeselectAll", "EditorIcons"));
  664. select_all_colors_button->set_icon(get_icon("ThemeSelectAll", "EditorIcons"));
  665. select_full_colors_button->set_icon(get_icon("ThemeSelectFull", "EditorIcons"));
  666. select_constants_icon->set_texture(get_icon("MemberConstant", "EditorIcons"));
  667. deselect_all_constants_button->set_icon(get_icon("ThemeDeselectAll", "EditorIcons"));
  668. select_all_constants_button->set_icon(get_icon("ThemeSelectAll", "EditorIcons"));
  669. select_full_constants_button->set_icon(get_icon("ThemeSelectFull", "EditorIcons"));
  670. select_fonts_icon->set_texture(get_icon("Font", "EditorIcons"));
  671. deselect_all_fonts_button->set_icon(get_icon("ThemeDeselectAll", "EditorIcons"));
  672. select_all_fonts_button->set_icon(get_icon("ThemeSelectAll", "EditorIcons"));
  673. select_full_fonts_button->set_icon(get_icon("ThemeSelectFull", "EditorIcons"));
  674. select_icons_icon->set_texture(get_icon("ImageTexture", "EditorIcons"));
  675. deselect_all_icons_button->set_icon(get_icon("ThemeDeselectAll", "EditorIcons"));
  676. select_all_icons_button->set_icon(get_icon("ThemeSelectAll", "EditorIcons"));
  677. select_full_icons_button->set_icon(get_icon("ThemeSelectFull", "EditorIcons"));
  678. select_styleboxes_icon->set_texture(get_icon("StyleBoxFlat", "EditorIcons"));
  679. deselect_all_styleboxes_button->set_icon(get_icon("ThemeDeselectAll", "EditorIcons"));
  680. select_all_styleboxes_button->set_icon(get_icon("ThemeSelectAll", "EditorIcons"));
  681. select_full_styleboxes_button->set_icon(get_icon("ThemeSelectFull", "EditorIcons"));
  682. } break;
  683. }
  684. }
  685. void ThemeItemImportTree::_bind_methods() {
  686. // Internal binds.
  687. ClassDB::bind_method("_filter_text_changed", &ThemeItemImportTree::_filter_text_changed);
  688. ClassDB::bind_method("_tree_item_edited", &ThemeItemImportTree::_tree_item_edited);
  689. ClassDB::bind_method("_select_all_data_type_pressed", &ThemeItemImportTree::_select_all_data_type_pressed);
  690. ClassDB::bind_method("_select_full_data_type_pressed", &ThemeItemImportTree::_select_full_data_type_pressed);
  691. ClassDB::bind_method("_deselect_all_data_type_pressed", &ThemeItemImportTree::_deselect_all_data_type_pressed);
  692. ClassDB::bind_method("_toggle_type_items", &ThemeItemImportTree::_toggle_type_items);
  693. ClassDB::bind_method("_select_all_items_pressed", &ThemeItemImportTree::_select_all_items_pressed);
  694. ClassDB::bind_method("_select_full_items_pressed", &ThemeItemImportTree::_select_full_items_pressed);
  695. ClassDB::bind_method("_deselect_all_items_pressed", &ThemeItemImportTree::_deselect_all_items_pressed);
  696. ClassDB::bind_method("_import_selected", &ThemeItemImportTree::_import_selected);
  697. // Public binds.
  698. ADD_SIGNAL(MethodInfo("items_imported"));
  699. }
  700. ThemeItemImportTree::ThemeItemImportTree() {
  701. HBoxContainer *import_items_filter_hb = memnew(HBoxContainer);
  702. add_child(import_items_filter_hb);
  703. Label *import_items_filter_label = memnew(Label);
  704. import_items_filter_label->set_text(TTR("Filter:"));
  705. import_items_filter_hb->add_child(import_items_filter_label);
  706. import_items_filter = memnew(LineEdit);
  707. import_items_filter->set_clear_button_enabled(true);
  708. import_items_filter->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  709. import_items_filter_hb->add_child(import_items_filter);
  710. import_items_filter->connect("text_changed", this, "_filter_text_changed");
  711. HBoxContainer *import_main_hb = memnew(HBoxContainer);
  712. import_main_hb->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  713. add_child(import_main_hb);
  714. import_items_tree = memnew(Tree);
  715. import_items_tree->set_hide_root(true);
  716. import_items_tree->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  717. import_main_hb->add_child(import_items_tree);
  718. import_items_tree->connect("item_edited", this, "_tree_item_edited");
  719. import_items_tree->set_columns(3);
  720. import_items_tree->set_column_titles_visible(true);
  721. import_items_tree->set_column_title(IMPORT_ITEM, TTR("Import"));
  722. import_items_tree->set_column_title(IMPORT_ITEM_DATA, TTR("With Data"));
  723. import_items_tree->set_column_expand(0, true);
  724. import_items_tree->set_column_expand(IMPORT_ITEM, false);
  725. import_items_tree->set_column_expand(IMPORT_ITEM_DATA, false);
  726. import_items_tree->set_column_min_width(0, 160 * EDSCALE);
  727. import_items_tree->set_column_min_width(IMPORT_ITEM, 80 * EDSCALE);
  728. import_items_tree->set_column_min_width(IMPORT_ITEM_DATA, 80 * EDSCALE);
  729. ScrollContainer *import_bulk_sc = memnew(ScrollContainer);
  730. import_bulk_sc->set_custom_minimum_size(Size2(260.0, 0.0) * EDSCALE);
  731. import_bulk_sc->set_enable_h_scroll(false);
  732. import_main_hb->add_child(import_bulk_sc);
  733. VBoxContainer *import_bulk_vb = memnew(VBoxContainer);
  734. import_bulk_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  735. import_bulk_sc->add_child(import_bulk_vb);
  736. Label *import_bulk_label = memnew(Label);
  737. import_bulk_label->set_text(TTR("Select by data type:"));
  738. import_bulk_vb->add_child(import_bulk_label);
  739. select_colors_icon = memnew(TextureRect);
  740. select_colors_label = memnew(Label);
  741. deselect_all_colors_button = memnew(Button);
  742. select_all_colors_button = memnew(Button);
  743. select_full_colors_button = memnew(Button);
  744. total_selected_colors_label = memnew(Label);
  745. select_constants_icon = memnew(TextureRect);
  746. select_constants_label = memnew(Label);
  747. deselect_all_constants_button = memnew(Button);
  748. select_all_constants_button = memnew(Button);
  749. select_full_constants_button = memnew(Button);
  750. total_selected_constants_label = memnew(Label);
  751. select_fonts_icon = memnew(TextureRect);
  752. select_fonts_label = memnew(Label);
  753. deselect_all_fonts_button = memnew(Button);
  754. select_all_fonts_button = memnew(Button);
  755. select_full_fonts_button = memnew(Button);
  756. total_selected_fonts_label = memnew(Label);
  757. select_icons_icon = memnew(TextureRect);
  758. select_icons_label = memnew(Label);
  759. deselect_all_icons_button = memnew(Button);
  760. select_all_icons_button = memnew(Button);
  761. select_full_icons_button = memnew(Button);
  762. total_selected_icons_label = memnew(Label);
  763. select_styleboxes_icon = memnew(TextureRect);
  764. select_styleboxes_label = memnew(Label);
  765. deselect_all_styleboxes_button = memnew(Button);
  766. select_all_styleboxes_button = memnew(Button);
  767. select_full_styleboxes_button = memnew(Button);
  768. total_selected_styleboxes_label = memnew(Label);
  769. for (int i = 0; i < Theme::DATA_TYPE_MAX; i++) {
  770. Theme::DataType dt = (Theme::DataType)i;
  771. TextureRect *select_items_icon;
  772. Label *select_items_label;
  773. Button *deselect_all_items_button;
  774. Button *select_all_items_button;
  775. Button *select_full_items_button;
  776. Label *total_selected_items_label;
  777. String items_title = "";
  778. String select_all_items_tooltip = "";
  779. String select_full_items_tooltip = "";
  780. String deselect_all_items_tooltip = "";
  781. switch (dt) {
  782. case Theme::DATA_TYPE_COLOR:
  783. select_items_icon = select_colors_icon;
  784. select_items_label = select_colors_label;
  785. deselect_all_items_button = deselect_all_colors_button;
  786. select_all_items_button = select_all_colors_button;
  787. select_full_items_button = select_full_colors_button;
  788. total_selected_items_label = total_selected_colors_label;
  789. items_title = TTR("Colors");
  790. select_all_items_tooltip = TTR("Select all visible color items.");
  791. select_full_items_tooltip = TTR("Select all visible color items and their data.");
  792. deselect_all_items_tooltip = TTR("Deselect all visible color items.");
  793. break;
  794. case Theme::DATA_TYPE_CONSTANT:
  795. select_items_icon = select_constants_icon;
  796. select_items_label = select_constants_label;
  797. deselect_all_items_button = deselect_all_constants_button;
  798. select_all_items_button = select_all_constants_button;
  799. select_full_items_button = select_full_constants_button;
  800. total_selected_items_label = total_selected_constants_label;
  801. items_title = TTR("Constants");
  802. select_all_items_tooltip = TTR("Select all visible constant items.");
  803. select_full_items_tooltip = TTR("Select all visible constant items and their data.");
  804. deselect_all_items_tooltip = TTR("Deselect all visible constant items.");
  805. break;
  806. case Theme::DATA_TYPE_FONT:
  807. select_items_icon = select_fonts_icon;
  808. select_items_label = select_fonts_label;
  809. deselect_all_items_button = deselect_all_fonts_button;
  810. select_all_items_button = select_all_fonts_button;
  811. select_full_items_button = select_full_fonts_button;
  812. total_selected_items_label = total_selected_fonts_label;
  813. items_title = TTR("Fonts");
  814. select_all_items_tooltip = TTR("Select all visible font items.");
  815. select_full_items_tooltip = TTR("Select all visible font items and their data.");
  816. deselect_all_items_tooltip = TTR("Deselect all visible font items.");
  817. break;
  818. case Theme::DATA_TYPE_ICON:
  819. select_items_icon = select_icons_icon;
  820. select_items_label = select_icons_label;
  821. deselect_all_items_button = deselect_all_icons_button;
  822. select_all_items_button = select_all_icons_button;
  823. select_full_items_button = select_full_icons_button;
  824. total_selected_items_label = total_selected_icons_label;
  825. items_title = TTR("Icons");
  826. select_all_items_tooltip = TTR("Select all visible icon items.");
  827. select_full_items_tooltip = TTR("Select all visible icon items and their data.");
  828. deselect_all_items_tooltip = TTR("Deselect all visible icon items.");
  829. break;
  830. case Theme::DATA_TYPE_STYLEBOX:
  831. select_items_icon = select_styleboxes_icon;
  832. select_items_label = select_styleboxes_label;
  833. deselect_all_items_button = deselect_all_styleboxes_button;
  834. select_all_items_button = select_all_styleboxes_button;
  835. select_full_items_button = select_full_styleboxes_button;
  836. total_selected_items_label = total_selected_styleboxes_label;
  837. items_title = TTR("Styleboxes");
  838. select_all_items_tooltip = TTR("Select all visible stylebox items.");
  839. select_full_items_tooltip = TTR("Select all visible stylebox items and their data.");
  840. deselect_all_items_tooltip = TTR("Deselect all visible stylebox items.");
  841. break;
  842. case Theme::DATA_TYPE_MAX:
  843. continue; // Can't happen, but silences warning.
  844. }
  845. if (i > 0) {
  846. import_bulk_vb->add_child(memnew(HSeparator));
  847. }
  848. HBoxContainer *all_set = memnew(HBoxContainer);
  849. import_bulk_vb->add_child(all_set);
  850. HBoxContainer *label_set = memnew(HBoxContainer);
  851. label_set->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  852. all_set->add_child(label_set);
  853. select_items_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
  854. label_set->add_child(select_items_icon);
  855. select_items_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  856. select_items_label->set_clip_text(true);
  857. select_items_label->set_text(items_title);
  858. label_set->add_child(select_items_label);
  859. HBoxContainer *button_set = memnew(HBoxContainer);
  860. button_set->set_alignment(BoxContainer::ALIGN_END);
  861. all_set->add_child(button_set);
  862. select_all_items_button->set_flat(true);
  863. select_all_items_button->set_tooltip(select_all_items_tooltip);
  864. button_set->add_child(select_all_items_button);
  865. select_all_items_button->connect("pressed", this, "_select_all_data_type_pressed", varray(i));
  866. select_full_items_button->set_flat(true);
  867. select_full_items_button->set_tooltip(select_full_items_tooltip);
  868. button_set->add_child(select_full_items_button);
  869. select_full_items_button->connect("pressed", this, "_select_full_data_type_pressed", varray(i));
  870. deselect_all_items_button->set_flat(true);
  871. deselect_all_items_button->set_tooltip(deselect_all_items_tooltip);
  872. button_set->add_child(deselect_all_items_button);
  873. deselect_all_items_button->connect("pressed", this, "_deselect_all_data_type_pressed", varray(i));
  874. total_selected_items_label->set_align(Label::ALIGN_RIGHT);
  875. total_selected_items_label->hide();
  876. import_bulk_vb->add_child(total_selected_items_label);
  877. if (dt == Theme::DATA_TYPE_ICON) {
  878. select_icons_warning_hb = memnew(HBoxContainer);
  879. import_bulk_vb->add_child(select_icons_warning_hb);
  880. select_icons_warning_icon = memnew(TextureRect);
  881. select_icons_warning_icon->set_v_size_flags(Control::SIZE_SHRINK_CENTER);
  882. select_icons_warning_hb->add_child(select_icons_warning_icon);
  883. select_icons_warning = memnew(Label);
  884. select_icons_warning->set_text(TTR("Caution: Adding icon data may considerably increase the size of your Theme resource."));
  885. select_icons_warning->set_autowrap(true);
  886. select_icons_warning->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  887. select_icons_warning_hb->add_child(select_icons_warning);
  888. }
  889. }
  890. add_child(memnew(HSeparator));
  891. HBoxContainer *import_buttons = memnew(HBoxContainer);
  892. add_child(import_buttons);
  893. import_collapse_types_button = memnew(Button);
  894. import_collapse_types_button->set_flat(true);
  895. import_collapse_types_button->set_tooltip(TTR("Collapse types."));
  896. import_buttons->add_child(import_collapse_types_button);
  897. import_collapse_types_button->connect("pressed", this, "_toggle_type_items", varray(true));
  898. import_expand_types_button = memnew(Button);
  899. import_expand_types_button->set_flat(true);
  900. import_expand_types_button->set_tooltip(TTR("Expand types."));
  901. import_buttons->add_child(import_expand_types_button);
  902. import_expand_types_button->connect("pressed", this, "_toggle_type_items", varray(false));
  903. import_buttons->add_child(memnew(VSeparator));
  904. import_select_all_button = memnew(Button);
  905. import_select_all_button->set_flat(true);
  906. import_select_all_button->set_text(TTR("Select All"));
  907. import_select_all_button->set_tooltip(TTR("Select all Theme items."));
  908. import_buttons->add_child(import_select_all_button);
  909. import_select_all_button->connect("pressed", this, "_select_all_items_pressed");
  910. import_select_full_button = memnew(Button);
  911. import_select_full_button->set_flat(true);
  912. import_select_full_button->set_text(TTR("Select With Data"));
  913. import_select_full_button->set_tooltip(TTR("Select all Theme items with item data."));
  914. import_buttons->add_child(import_select_full_button);
  915. import_select_full_button->connect("pressed", this, "_select_full_items_pressed");
  916. import_deselect_all_button = memnew(Button);
  917. import_deselect_all_button->set_flat(true);
  918. import_deselect_all_button->set_text(TTR("Deselect All"));
  919. import_deselect_all_button->set_tooltip(TTR("Deselect all Theme items."));
  920. import_buttons->add_child(import_deselect_all_button);
  921. import_deselect_all_button->connect("pressed", this, "_deselect_all_items_pressed");
  922. import_buttons->add_spacer();
  923. Button *import_add_selected_button = memnew(Button);
  924. import_add_selected_button->set_text(TTR("Import Selected"));
  925. import_buttons->add_child(import_add_selected_button);
  926. import_add_selected_button->connect("pressed", this, "_import_selected");
  927. }
  928. void ThemeItemEditorDialog::ok_pressed() {
  929. if (import_default_theme_items->has_selected_items() || import_editor_theme_items->has_selected_items() || import_other_theme_items->has_selected_items()) {
  930. confirm_closing_dialog->set_text(TTR("Import Items tab has some items selected. Selection will be lost upon closing this window.\nClose anyway?"));
  931. confirm_closing_dialog->popup_centered(Size2i(380, 120) * EDSCALE);
  932. return;
  933. }
  934. hide();
  935. }
  936. void ThemeItemEditorDialog::_close_dialog() {
  937. hide();
  938. }
  939. void ThemeItemEditorDialog::_dialog_about_to_show() {
  940. ERR_FAIL_COND_MSG(edited_theme.is_null(), "Invalid state of the Theme Editor; the Theme resource is missing.");
  941. _update_edit_types();
  942. import_default_theme_items->set_edited_theme(edited_theme);
  943. import_default_theme_items->set_base_theme(Theme::get_default());
  944. import_default_theme_items->reset_item_tree();
  945. import_editor_theme_items->set_edited_theme(edited_theme);
  946. import_editor_theme_items->set_base_theme(EditorNode::get_singleton()->get_theme_base()->get_theme());
  947. import_editor_theme_items->reset_item_tree();
  948. import_other_theme_items->set_edited_theme(edited_theme);
  949. import_other_theme_items->reset_item_tree();
  950. }
  951. void ThemeItemEditorDialog::_update_edit_types() {
  952. Ref<Theme> base_theme = Theme::get_default();
  953. List<StringName> theme_types;
  954. edited_theme->get_type_list(&theme_types);
  955. theme_types.sort_custom<StringName::AlphCompare>();
  956. bool item_reselected = false;
  957. edit_type_list->clear();
  958. TreeItem *list_root = edit_type_list->create_item();
  959. for (List<StringName>::Element *E = theme_types.front(); E; E = E->next()) {
  960. Ref<Texture> item_icon;
  961. if (E->get() == "") {
  962. item_icon = get_icon("NodeDisabled", "EditorIcons");
  963. } else {
  964. item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled");
  965. }
  966. TreeItem *list_item = edit_type_list->create_item(list_root);
  967. list_item->set_text(0, E->get());
  968. list_item->set_icon(0, item_icon);
  969. list_item->add_button(0, get_icon("Remove", "EditorIcons"), TYPES_TREE_REMOVE_ITEM, false, TTR("Remove Type"));
  970. if (E->get() == edited_item_type) {
  971. list_item->select(0);
  972. item_reselected = true;
  973. }
  974. }
  975. if (!item_reselected) {
  976. edited_item_type = "";
  977. TreeItem *ci = list_root->get_children();
  978. if (ci) {
  979. ci->select(0);
  980. }
  981. }
  982. List<StringName> default_types;
  983. base_theme->get_type_list(&default_types);
  984. default_types.sort_custom<StringName::AlphCompare>();
  985. String selected_type = "";
  986. TreeItem *selected_item = edit_type_list->get_selected();
  987. if (selected_item) {
  988. selected_type = selected_item->get_text(0);
  989. edit_items_add_color->set_disabled(false);
  990. edit_items_add_constant->set_disabled(false);
  991. edit_items_add_font->set_disabled(false);
  992. edit_items_add_icon->set_disabled(false);
  993. edit_items_add_stylebox->set_disabled(false);
  994. edit_items_remove_class->set_disabled(false);
  995. edit_items_remove_custom->set_disabled(false);
  996. edit_items_remove_all->set_disabled(false);
  997. edit_items_message->set_text("");
  998. edit_items_message->hide();
  999. } else {
  1000. edit_items_add_color->set_disabled(true);
  1001. edit_items_add_constant->set_disabled(true);
  1002. edit_items_add_font->set_disabled(true);
  1003. edit_items_add_icon->set_disabled(true);
  1004. edit_items_add_stylebox->set_disabled(true);
  1005. edit_items_remove_class->set_disabled(true);
  1006. edit_items_remove_custom->set_disabled(true);
  1007. edit_items_remove_all->set_disabled(true);
  1008. edit_items_message->set_text(TTR("Select a theme type from the list to edit its items.\nYou can add a custom type or import a type with its items from another theme."));
  1009. edit_items_message->show();
  1010. }
  1011. _update_edit_item_tree(selected_type);
  1012. }
  1013. void ThemeItemEditorDialog::_edited_type_selected() {
  1014. TreeItem *selected_item = edit_type_list->get_selected();
  1015. String selected_type = selected_item->get_text(0);
  1016. _update_edit_item_tree(selected_type);
  1017. }
  1018. void ThemeItemEditorDialog::_edited_type_button_pressed(Object *p_item, int p_column, int p_id) {
  1019. TreeItem *item = Object::cast_to<TreeItem>(p_item);
  1020. if (!item) {
  1021. return;
  1022. }
  1023. switch (p_id) {
  1024. case TYPES_TREE_REMOVE_ITEM: {
  1025. String type_name = item->get_text(0);
  1026. _remove_theme_type(type_name);
  1027. } break;
  1028. }
  1029. }
  1030. void ThemeItemEditorDialog::_update_edit_item_tree(String p_item_type) {
  1031. edited_item_type = p_item_type;
  1032. edit_items_tree->clear();
  1033. TreeItem *root = edit_items_tree->create_item();
  1034. List<StringName> names;
  1035. bool has_any_items = false;
  1036. { // Colors.
  1037. names.clear();
  1038. edited_theme->get_color_list(p_item_type, &names);
  1039. if (names.size() > 0) {
  1040. TreeItem *color_root = edit_items_tree->create_item(root);
  1041. color_root->set_metadata(0, Theme::DATA_TYPE_COLOR);
  1042. color_root->set_icon(0, get_icon("Color", "EditorIcons"));
  1043. color_root->set_text(0, TTR("Colors"));
  1044. color_root->add_button(0, get_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Color Items"));
  1045. names.sort_custom<StringName::AlphCompare>();
  1046. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1047. TreeItem *item = edit_items_tree->create_item(color_root);
  1048. item->set_text(0, E->get());
  1049. item->add_button(0, get_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
  1050. item->add_button(0, get_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
  1051. }
  1052. has_any_items = true;
  1053. }
  1054. }
  1055. { // Constants.
  1056. names.clear();
  1057. edited_theme->get_constant_list(p_item_type, &names);
  1058. if (names.size() > 0) {
  1059. TreeItem *constant_root = edit_items_tree->create_item(root);
  1060. constant_root->set_metadata(0, Theme::DATA_TYPE_CONSTANT);
  1061. constant_root->set_icon(0, get_icon("MemberConstant", "EditorIcons"));
  1062. constant_root->set_text(0, TTR("Constants"));
  1063. constant_root->add_button(0, get_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Constant Items"));
  1064. names.sort_custom<StringName::AlphCompare>();
  1065. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1066. TreeItem *item = edit_items_tree->create_item(constant_root);
  1067. item->set_text(0, E->get());
  1068. item->add_button(0, get_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
  1069. item->add_button(0, get_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
  1070. }
  1071. has_any_items = true;
  1072. }
  1073. }
  1074. { // Fonts.
  1075. names.clear();
  1076. edited_theme->get_font_list(p_item_type, &names);
  1077. if (names.size() > 0) {
  1078. TreeItem *font_root = edit_items_tree->create_item(root);
  1079. font_root->set_metadata(0, Theme::DATA_TYPE_FONT);
  1080. font_root->set_icon(0, get_icon("Font", "EditorIcons"));
  1081. font_root->set_text(0, TTR("Fonts"));
  1082. font_root->add_button(0, get_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Font Items"));
  1083. names.sort_custom<StringName::AlphCompare>();
  1084. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1085. TreeItem *item = edit_items_tree->create_item(font_root);
  1086. item->set_text(0, E->get());
  1087. item->add_button(0, get_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
  1088. item->add_button(0, get_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
  1089. }
  1090. has_any_items = true;
  1091. }
  1092. }
  1093. { // Icons.
  1094. names.clear();
  1095. edited_theme->get_icon_list(p_item_type, &names);
  1096. if (names.size() > 0) {
  1097. TreeItem *icon_root = edit_items_tree->create_item(root);
  1098. icon_root->set_metadata(0, Theme::DATA_TYPE_ICON);
  1099. icon_root->set_icon(0, get_icon("ImageTexture", "EditorIcons"));
  1100. icon_root->set_text(0, TTR("Icons"));
  1101. icon_root->add_button(0, get_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All Icon Items"));
  1102. names.sort_custom<StringName::AlphCompare>();
  1103. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1104. TreeItem *item = edit_items_tree->create_item(icon_root);
  1105. item->set_text(0, E->get());
  1106. item->add_button(0, get_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
  1107. item->add_button(0, get_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
  1108. }
  1109. has_any_items = true;
  1110. }
  1111. }
  1112. { // Styleboxes.
  1113. names.clear();
  1114. edited_theme->get_stylebox_list(p_item_type, &names);
  1115. if (names.size() > 0) {
  1116. TreeItem *stylebox_root = edit_items_tree->create_item(root);
  1117. stylebox_root->set_metadata(0, Theme::DATA_TYPE_STYLEBOX);
  1118. stylebox_root->set_icon(0, get_icon("StyleBoxFlat", "EditorIcons"));
  1119. stylebox_root->set_text(0, TTR("Styleboxes"));
  1120. stylebox_root->add_button(0, get_icon("Clear", "EditorIcons"), ITEMS_TREE_REMOVE_DATA_TYPE, false, TTR("Remove All StyleBox Items"));
  1121. names.sort_custom<StringName::AlphCompare>();
  1122. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1123. TreeItem *item = edit_items_tree->create_item(stylebox_root);
  1124. item->set_text(0, E->get());
  1125. item->add_button(0, get_icon("Edit", "EditorIcons"), ITEMS_TREE_RENAME_ITEM, false, TTR("Rename Item"));
  1126. item->add_button(0, get_icon("Remove", "EditorIcons"), ITEMS_TREE_REMOVE_ITEM, false, TTR("Remove Item"));
  1127. }
  1128. has_any_items = true;
  1129. }
  1130. }
  1131. // If some type is selected, but it doesn't seem to have any items, show a guiding message.
  1132. TreeItem *selected_item = edit_type_list->get_selected();
  1133. if (selected_item) {
  1134. if (!has_any_items) {
  1135. edit_items_message->set_text(TTR("This theme type is empty.\nAdd more items to it manually or by importing from another theme."));
  1136. edit_items_message->show();
  1137. } else {
  1138. edit_items_message->set_text("");
  1139. edit_items_message->hide();
  1140. }
  1141. }
  1142. }
  1143. void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_column, int p_id) {
  1144. TreeItem *item = Object::cast_to<TreeItem>(p_item);
  1145. if (!item) {
  1146. return;
  1147. }
  1148. switch (p_id) {
  1149. case ITEMS_TREE_RENAME_ITEM: {
  1150. String item_name = item->get_text(0);
  1151. int data_type = item->get_parent()->get_metadata(0);
  1152. _open_rename_theme_item_dialog((Theme::DataType)data_type, item_name);
  1153. } break;
  1154. case ITEMS_TREE_REMOVE_ITEM: {
  1155. String item_name = item->get_text(0);
  1156. int data_type = item->get_parent()->get_metadata(0);
  1157. edited_theme->clear_theme_item((Theme::DataType)data_type, item_name, edited_item_type);
  1158. } break;
  1159. case ITEMS_TREE_REMOVE_DATA_TYPE: {
  1160. int data_type = item->get_metadata(0);
  1161. _remove_data_type_items((Theme::DataType)data_type, edited_item_type);
  1162. } break;
  1163. }
  1164. _update_edit_item_tree(edited_item_type);
  1165. }
  1166. void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) {
  1167. const String new_type = edit_add_type_value->get_text().strip_edges();
  1168. edit_add_type_value->clear();
  1169. UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
  1170. ur->create_action(TTR("Add Theme Type"));
  1171. ur->add_do_method(*edited_theme, "add_type", new_type);
  1172. ur->add_undo_method(*edited_theme, "remove_type", new_type);
  1173. ur->add_do_method(this, "_update_edit_types");
  1174. ur->add_undo_method(this, "_update_edit_types");
  1175. ur->commit_action();
  1176. }
  1177. void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) {
  1178. Ref<Theme> old_snapshot = edited_theme->duplicate();
  1179. Ref<Theme> new_snapshot = edited_theme->duplicate();
  1180. UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
  1181. ur->create_action(TTR("Remove Theme Type"));
  1182. new_snapshot->remove_type(p_theme_type);
  1183. ur->add_do_method(*edited_theme, "clear");
  1184. ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
  1185. // If the type was empty, it cannot be restored with merge, but thankfully we can fake it.
  1186. ur->add_undo_method(*edited_theme, "add_type", p_theme_type);
  1187. ur->add_undo_method(*edited_theme, "merge_with", old_snapshot);
  1188. ur->add_do_method(this, "_update_edit_types");
  1189. ur->add_undo_method(this, "_update_edit_types");
  1190. ur->commit_action();
  1191. }
  1192. void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) {
  1193. switch (p_data_type) {
  1194. case Theme::DATA_TYPE_ICON:
  1195. edited_theme->set_icon(p_item_name, p_item_type, Ref<Texture>());
  1196. break;
  1197. case Theme::DATA_TYPE_STYLEBOX:
  1198. edited_theme->set_stylebox(p_item_name, p_item_type, Ref<StyleBox>());
  1199. break;
  1200. case Theme::DATA_TYPE_FONT:
  1201. edited_theme->set_font(p_item_name, p_item_type, Ref<Font>());
  1202. break;
  1203. case Theme::DATA_TYPE_COLOR:
  1204. edited_theme->set_color(p_item_name, p_item_type, Color());
  1205. break;
  1206. case Theme::DATA_TYPE_CONSTANT:
  1207. edited_theme->set_constant(p_item_name, p_item_type, 0);
  1208. break;
  1209. case Theme::DATA_TYPE_MAX:
  1210. break; // Can't happen, but silences warning.
  1211. }
  1212. }
  1213. void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type, String p_item_type) {
  1214. List<StringName> names;
  1215. // Prevent changes from immediately being reported while the operation is still ongoing.
  1216. edited_theme->_freeze_change_propagation();
  1217. edited_theme->get_theme_item_list(p_data_type, p_item_type, &names);
  1218. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1219. edited_theme->clear_theme_item(p_data_type, E->get(), p_item_type);
  1220. }
  1221. // Allow changes to be reported now that the operation is finished.
  1222. edited_theme->_unfreeze_and_propagate_changes();
  1223. }
  1224. void ThemeItemEditorDialog::_remove_class_items() {
  1225. List<StringName> names;
  1226. // Prevent changes from immediately being reported while the operation is still ongoing.
  1227. edited_theme->_freeze_change_propagation();
  1228. for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
  1229. Theme::DataType data_type = (Theme::DataType)dt;
  1230. names.clear();
  1231. Theme::get_default()->get_theme_item_list(data_type, edited_item_type, &names);
  1232. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1233. if (edited_theme->has_theme_item_nocheck(data_type, E->get(), edited_item_type)) {
  1234. edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
  1235. }
  1236. }
  1237. }
  1238. // Allow changes to be reported now that the operation is finished.
  1239. edited_theme->_unfreeze_and_propagate_changes();
  1240. _update_edit_item_tree(edited_item_type);
  1241. }
  1242. void ThemeItemEditorDialog::_remove_custom_items() {
  1243. List<StringName> names;
  1244. // Prevent changes from immediately being reported while the operation is still ongoing.
  1245. edited_theme->_freeze_change_propagation();
  1246. for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
  1247. Theme::DataType data_type = (Theme::DataType)dt;
  1248. names.clear();
  1249. edited_theme->get_theme_item_list(data_type, edited_item_type, &names);
  1250. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1251. if (!Theme::get_default()->has_theme_item_nocheck(data_type, E->get(), edited_item_type)) {
  1252. edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
  1253. }
  1254. }
  1255. }
  1256. // Allow changes to be reported now that the operation is finished.
  1257. edited_theme->_unfreeze_and_propagate_changes();
  1258. _update_edit_item_tree(edited_item_type);
  1259. }
  1260. void ThemeItemEditorDialog::_remove_all_items() {
  1261. List<StringName> names;
  1262. // Prevent changes from immediately being reported while the operation is still ongoing.
  1263. edited_theme->_freeze_change_propagation();
  1264. for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
  1265. Theme::DataType data_type = (Theme::DataType)dt;
  1266. names.clear();
  1267. edited_theme->get_theme_item_list(data_type, edited_item_type, &names);
  1268. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1269. edited_theme->clear_theme_item(data_type, E->get(), edited_item_type);
  1270. }
  1271. }
  1272. // Allow changes to be reported now that the operation is finished.
  1273. edited_theme->_unfreeze_and_propagate_changes();
  1274. _update_edit_item_tree(edited_item_type);
  1275. }
  1276. void ThemeItemEditorDialog::_open_add_theme_item_dialog(int p_data_type) {
  1277. ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
  1278. item_popup_mode = CREATE_THEME_ITEM;
  1279. edit_item_data_type = (Theme::DataType)p_data_type;
  1280. switch (edit_item_data_type) {
  1281. case Theme::DATA_TYPE_COLOR:
  1282. edit_theme_item_dialog->set_title(TTR("Add Color Item"));
  1283. break;
  1284. case Theme::DATA_TYPE_CONSTANT:
  1285. edit_theme_item_dialog->set_title(TTR("Add Constant Item"));
  1286. break;
  1287. case Theme::DATA_TYPE_FONT:
  1288. edit_theme_item_dialog->set_title(TTR("Add Font Item"));
  1289. break;
  1290. case Theme::DATA_TYPE_ICON:
  1291. edit_theme_item_dialog->set_title(TTR("Add Icon Item"));
  1292. break;
  1293. case Theme::DATA_TYPE_STYLEBOX:
  1294. edit_theme_item_dialog->set_title(TTR("Add Stylebox Item"));
  1295. break;
  1296. case Theme::DATA_TYPE_MAX:
  1297. break; // Can't happen, but silences warning.
  1298. }
  1299. edit_theme_item_old_vb->hide();
  1300. theme_item_name->clear();
  1301. edit_theme_item_dialog->popup_centered(Size2(380, 110) * EDSCALE);
  1302. theme_item_name->grab_focus();
  1303. }
  1304. void ThemeItemEditorDialog::_open_rename_theme_item_dialog(Theme::DataType p_data_type, String p_item_name) {
  1305. ERR_FAIL_INDEX_MSG(p_data_type, Theme::DATA_TYPE_MAX, "Theme item data type is out of bounds.");
  1306. item_popup_mode = RENAME_THEME_ITEM;
  1307. edit_item_data_type = p_data_type;
  1308. edit_item_old_name = p_item_name;
  1309. switch (edit_item_data_type) {
  1310. case Theme::DATA_TYPE_COLOR:
  1311. edit_theme_item_dialog->set_title(TTR("Rename Color Item"));
  1312. break;
  1313. case Theme::DATA_TYPE_CONSTANT:
  1314. edit_theme_item_dialog->set_title(TTR("Rename Constant Item"));
  1315. break;
  1316. case Theme::DATA_TYPE_FONT:
  1317. edit_theme_item_dialog->set_title(TTR("Rename Font Item"));
  1318. break;
  1319. case Theme::DATA_TYPE_ICON:
  1320. edit_theme_item_dialog->set_title(TTR("Rename Icon Item"));
  1321. break;
  1322. case Theme::DATA_TYPE_STYLEBOX:
  1323. edit_theme_item_dialog->set_title(TTR("Rename Stylebox Item"));
  1324. break;
  1325. case Theme::DATA_TYPE_MAX:
  1326. break; // Can't happen, but silences warning.
  1327. }
  1328. edit_theme_item_old_vb->show();
  1329. theme_item_old_name->set_text(p_item_name);
  1330. theme_item_name->set_text(p_item_name);
  1331. edit_theme_item_dialog->popup_centered(Size2(380, 140) * EDSCALE);
  1332. theme_item_name->grab_focus();
  1333. }
  1334. void ThemeItemEditorDialog::_confirm_edit_theme_item() {
  1335. if (item_popup_mode == CREATE_THEME_ITEM) {
  1336. _add_theme_item(edit_item_data_type, theme_item_name->get_text(), edited_item_type);
  1337. } else if (item_popup_mode == RENAME_THEME_ITEM) {
  1338. edited_theme->rename_theme_item(edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type);
  1339. }
  1340. item_popup_mode = ITEM_POPUP_MODE_MAX;
  1341. edit_item_data_type = Theme::DATA_TYPE_MAX;
  1342. edit_item_old_name = "";
  1343. _update_edit_item_tree(edited_item_type);
  1344. }
  1345. void ThemeItemEditorDialog::_edit_theme_item_gui_input(const Ref<InputEvent> &p_event) {
  1346. Ref<InputEventKey> k = p_event;
  1347. if (k.is_valid()) {
  1348. if (!k->is_pressed()) {
  1349. return;
  1350. }
  1351. switch (k->get_scancode()) {
  1352. case KEY_KP_ENTER:
  1353. case KEY_ENTER: {
  1354. _confirm_edit_theme_item();
  1355. edit_theme_item_dialog->hide();
  1356. get_tree()->set_input_as_handled();
  1357. } break;
  1358. case KEY_ESCAPE: {
  1359. edit_theme_item_dialog->hide();
  1360. get_tree()->set_input_as_handled();
  1361. } break;
  1362. }
  1363. }
  1364. }
  1365. void ThemeItemEditorDialog::_open_select_another_theme() {
  1366. import_another_theme_dialog->popup_centered_ratio();
  1367. }
  1368. void ThemeItemEditorDialog::_select_another_theme_cbk(const String &p_path) {
  1369. Ref<Theme> loaded_theme = ResourceLoader::load(p_path);
  1370. if (loaded_theme.is_null()) {
  1371. EditorNode::get_singleton()->show_warning(TTR("Invalid file, not a Theme resource."));
  1372. return;
  1373. }
  1374. if (loaded_theme == edited_theme) {
  1375. EditorNode::get_singleton()->show_warning(TTR("Invalid file, same as the edited Theme resource."));
  1376. return;
  1377. }
  1378. import_another_theme_value->set_text(p_path);
  1379. import_other_theme_items->set_base_theme(loaded_theme);
  1380. import_other_theme_items->reset_item_tree();
  1381. }
  1382. void ThemeItemEditorDialog::_notification(int p_what) {
  1383. switch (p_what) {
  1384. case NOTIFICATION_ENTER_TREE: {
  1385. connect("about_to_show", this, "_dialog_about_to_show");
  1386. FALLTHROUGH;
  1387. }
  1388. case NOTIFICATION_THEME_CHANGED: {
  1389. edit_items_add_color->set_icon(get_icon("Color", "EditorIcons"));
  1390. edit_items_add_constant->set_icon(get_icon("MemberConstant", "EditorIcons"));
  1391. edit_items_add_font->set_icon(get_icon("Font", "EditorIcons"));
  1392. edit_items_add_icon->set_icon(get_icon("ImageTexture", "EditorIcons"));
  1393. edit_items_add_stylebox->set_icon(get_icon("StyleBoxFlat", "EditorIcons"));
  1394. edit_items_remove_class->set_icon(get_icon("Control", "EditorIcons"));
  1395. edit_items_remove_custom->set_icon(get_icon("ThemeRemoveCustomItems", "EditorIcons"));
  1396. edit_items_remove_all->set_icon(get_icon("ThemeRemoveAllItems", "EditorIcons"));
  1397. import_another_theme_button->set_icon(get_icon("Folder", "EditorIcons"));
  1398. tc->add_style_override("tab_selected", get_stylebox("tab_selected_odd", "TabContainer"));
  1399. tc->add_style_override("panel", get_stylebox("panel_odd", "TabContainer"));
  1400. } break;
  1401. }
  1402. }
  1403. void ThemeItemEditorDialog::_bind_methods() {
  1404. // Internal binds.
  1405. ClassDB::bind_method("_edited_type_selected", &ThemeItemEditorDialog::_edited_type_selected);
  1406. ClassDB::bind_method("_edited_type_button_pressed", &ThemeItemEditorDialog::_edited_type_button_pressed);
  1407. ClassDB::bind_method("_add_theme_type", &ThemeItemEditorDialog::_add_theme_type);
  1408. ClassDB::bind_method("_open_add_theme_item_dialog", &ThemeItemEditorDialog::_open_add_theme_item_dialog);
  1409. ClassDB::bind_method("_remove_class_items", &ThemeItemEditorDialog::_remove_class_items);
  1410. ClassDB::bind_method("_remove_custom_items", &ThemeItemEditorDialog::_remove_custom_items);
  1411. ClassDB::bind_method("_remove_all_items", &ThemeItemEditorDialog::_remove_all_items);
  1412. ClassDB::bind_method("_item_tree_button_pressed", &ThemeItemEditorDialog::_item_tree_button_pressed);
  1413. ClassDB::bind_method("_edit_theme_item_gui_input", &ThemeItemEditorDialog::_edit_theme_item_gui_input);
  1414. ClassDB::bind_method("_confirm_edit_theme_item", &ThemeItemEditorDialog::_confirm_edit_theme_item);
  1415. ClassDB::bind_method("_update_edit_types", &ThemeItemEditorDialog::_update_edit_types);
  1416. ClassDB::bind_method("_open_select_another_theme", &ThemeItemEditorDialog::_open_select_another_theme);
  1417. ClassDB::bind_method("_select_another_theme_cbk", &ThemeItemEditorDialog::_select_another_theme_cbk);
  1418. ClassDB::bind_method("_close_dialog", &ThemeItemEditorDialog::_close_dialog);
  1419. ClassDB::bind_method("_dialog_about_to_show", &ThemeItemEditorDialog::_dialog_about_to_show);
  1420. }
  1421. void ThemeItemEditorDialog::set_edited_theme(const Ref<Theme> &p_theme) {
  1422. edited_theme = p_theme;
  1423. }
  1424. ThemeItemEditorDialog::ThemeItemEditorDialog() {
  1425. set_title(TTR("Manage Theme Items"));
  1426. get_ok()->set_text(TTR("Close"));
  1427. set_hide_on_ok(false); // Closing may require a confirmation in some cases.
  1428. tc = memnew(TabContainer);
  1429. tc->set_tab_align(TabContainer::TabAlign::ALIGN_LEFT);
  1430. add_child(tc);
  1431. // Edit Items tab.
  1432. HSplitContainer *edit_dialog_hs = memnew(HSplitContainer);
  1433. tc->add_child(edit_dialog_hs);
  1434. tc->set_tab_title(0, TTR("Edit Items"));
  1435. VBoxContainer *edit_dialog_side_vb = memnew(VBoxContainer);
  1436. edit_dialog_side_vb->set_custom_minimum_size(Size2(200.0, 0.0) * EDSCALE);
  1437. edit_dialog_hs->add_child(edit_dialog_side_vb);
  1438. Label *edit_type_label = memnew(Label);
  1439. edit_type_label->set_text(TTR("Types:"));
  1440. edit_dialog_side_vb->add_child(edit_type_label);
  1441. edit_type_list = memnew(Tree);
  1442. edit_type_list->set_hide_root(true);
  1443. edit_type_list->set_hide_folding(true);
  1444. edit_type_list->set_columns(1);
  1445. edit_type_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1446. edit_dialog_side_vb->add_child(edit_type_list);
  1447. edit_type_list->connect("item_selected", this, "_edited_type_selected");
  1448. edit_type_list->connect("button_pressed", this, "_edited_type_button_pressed");
  1449. Label *edit_add_type_label = memnew(Label);
  1450. edit_add_type_label->set_text(TTR("Add Type:"));
  1451. edit_dialog_side_vb->add_child(edit_add_type_label);
  1452. HBoxContainer *edit_add_type_hb = memnew(HBoxContainer);
  1453. edit_dialog_side_vb->add_child(edit_add_type_hb);
  1454. edit_add_type_value = memnew(LineEdit);
  1455. edit_add_type_value->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  1456. edit_add_type_value->connect("text_entered", this, "_add_theme_type");
  1457. edit_add_type_hb->add_child(edit_add_type_value);
  1458. Button *edit_add_type_button = memnew(Button);
  1459. edit_add_type_button->set_text(TTR("Add"));
  1460. edit_add_type_hb->add_child(edit_add_type_button);
  1461. edit_add_type_button->connect("pressed", this, "_add_theme_type", varray(""));
  1462. VBoxContainer *edit_items_vb = memnew(VBoxContainer);
  1463. edit_items_vb->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  1464. edit_dialog_hs->add_child(edit_items_vb);
  1465. HBoxContainer *edit_items_toolbar = memnew(HBoxContainer);
  1466. edit_items_vb->add_child(edit_items_toolbar);
  1467. Label *edit_items_toolbar_add_label = memnew(Label);
  1468. edit_items_toolbar_add_label->set_text(TTR("Add Item:"));
  1469. edit_items_toolbar->add_child(edit_items_toolbar_add_label);
  1470. edit_items_add_color = memnew(Button);
  1471. edit_items_add_color->set_tooltip(TTR("Add Color Item"));
  1472. edit_items_add_color->set_flat(true);
  1473. edit_items_add_color->set_disabled(true);
  1474. edit_items_toolbar->add_child(edit_items_add_color);
  1475. edit_items_add_color->connect("pressed", this, "_open_add_theme_item_dialog", varray(Theme::DATA_TYPE_COLOR));
  1476. edit_items_add_constant = memnew(Button);
  1477. edit_items_add_constant->set_tooltip(TTR("Add Constant Item"));
  1478. edit_items_add_constant->set_flat(true);
  1479. edit_items_add_constant->set_disabled(true);
  1480. edit_items_toolbar->add_child(edit_items_add_constant);
  1481. edit_items_add_constant->connect("pressed", this, "_open_add_theme_item_dialog", varray(Theme::DATA_TYPE_CONSTANT));
  1482. edit_items_add_font = memnew(Button);
  1483. edit_items_add_font->set_tooltip(TTR("Add Font Item"));
  1484. edit_items_add_font->set_flat(true);
  1485. edit_items_add_font->set_disabled(true);
  1486. edit_items_toolbar->add_child(edit_items_add_font);
  1487. edit_items_add_font->connect("pressed", this, "_open_add_theme_item_dialog", varray(Theme::DATA_TYPE_FONT));
  1488. edit_items_add_icon = memnew(Button);
  1489. edit_items_add_icon->set_tooltip(TTR("Add Icon Item"));
  1490. edit_items_add_icon->set_flat(true);
  1491. edit_items_add_icon->set_disabled(true);
  1492. edit_items_toolbar->add_child(edit_items_add_icon);
  1493. edit_items_add_icon->connect("pressed", this, "_open_add_theme_item_dialog", varray(Theme::DATA_TYPE_ICON));
  1494. edit_items_add_stylebox = memnew(Button);
  1495. edit_items_add_stylebox->set_tooltip(TTR("Add StyleBox Item"));
  1496. edit_items_add_stylebox->set_flat(true);
  1497. edit_items_add_stylebox->set_disabled(true);
  1498. edit_items_toolbar->add_child(edit_items_add_stylebox);
  1499. edit_items_add_stylebox->connect("pressed", this, "_open_add_theme_item_dialog", varray(Theme::DATA_TYPE_STYLEBOX));
  1500. edit_items_toolbar->add_child(memnew(VSeparator));
  1501. Label *edit_items_toolbar_remove_label = memnew(Label);
  1502. edit_items_toolbar_remove_label->set_text(TTR("Remove Items:"));
  1503. edit_items_toolbar->add_child(edit_items_toolbar_remove_label);
  1504. edit_items_remove_class = memnew(Button);
  1505. edit_items_remove_class->set_tooltip(TTR("Remove Class Items"));
  1506. edit_items_remove_class->set_flat(true);
  1507. edit_items_remove_class->set_disabled(true);
  1508. edit_items_toolbar->add_child(edit_items_remove_class);
  1509. edit_items_remove_class->connect("pressed", this, "_remove_class_items");
  1510. edit_items_remove_custom = memnew(Button);
  1511. edit_items_remove_custom->set_tooltip(TTR("Remove Custom Items"));
  1512. edit_items_remove_custom->set_flat(true);
  1513. edit_items_remove_custom->set_disabled(true);
  1514. edit_items_toolbar->add_child(edit_items_remove_custom);
  1515. edit_items_remove_custom->connect("pressed", this, "_remove_custom_items");
  1516. edit_items_remove_all = memnew(Button);
  1517. edit_items_remove_all->set_tooltip(TTR("Remove All Items"));
  1518. edit_items_remove_all->set_flat(true);
  1519. edit_items_remove_all->set_disabled(true);
  1520. edit_items_toolbar->add_child(edit_items_remove_all);
  1521. edit_items_remove_all->connect("pressed", this, "_remove_all_items");
  1522. edit_items_tree = memnew(Tree);
  1523. edit_items_tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1524. edit_items_tree->set_hide_root(true);
  1525. edit_items_tree->set_columns(1);
  1526. edit_items_vb->add_child(edit_items_tree);
  1527. edit_items_tree->connect("button_pressed", this, "_item_tree_button_pressed");
  1528. edit_items_message = memnew(Label);
  1529. edit_items_message->set_anchors_and_margins_preset(Control::PRESET_WIDE);
  1530. edit_items_message->set_mouse_filter(Control::MOUSE_FILTER_STOP);
  1531. edit_items_message->set_align(Label::ALIGN_CENTER);
  1532. edit_items_message->set_valign(Label::VALIGN_CENTER);
  1533. edit_items_message->set_autowrap(true);
  1534. edit_items_tree->add_child(edit_items_message);
  1535. edit_theme_item_dialog = memnew(ConfirmationDialog);
  1536. edit_theme_item_dialog->set_title(TTR("Add Theme Item"));
  1537. add_child(edit_theme_item_dialog);
  1538. VBoxContainer *edit_theme_item_vb = memnew(VBoxContainer);
  1539. edit_theme_item_dialog->add_child(edit_theme_item_vb);
  1540. edit_theme_item_old_vb = memnew(VBoxContainer);
  1541. edit_theme_item_vb->add_child(edit_theme_item_old_vb);
  1542. Label *edit_theme_item_old = memnew(Label);
  1543. edit_theme_item_old->set_text(TTR("Old Name:"));
  1544. edit_theme_item_old_vb->add_child(edit_theme_item_old);
  1545. theme_item_old_name = memnew(Label);
  1546. edit_theme_item_old_vb->add_child(theme_item_old_name);
  1547. Label *edit_theme_item_label = memnew(Label);
  1548. edit_theme_item_label->set_text(TTR("Name:"));
  1549. edit_theme_item_vb->add_child(edit_theme_item_label);
  1550. theme_item_name = memnew(LineEdit);
  1551. edit_theme_item_vb->add_child(theme_item_name);
  1552. theme_item_name->connect("gui_input", this, "_edit_theme_item_gui_input");
  1553. edit_theme_item_dialog->connect("confirmed", this, "_confirm_edit_theme_item");
  1554. // Import Items tab.
  1555. TabContainer *import_tc = memnew(TabContainer);
  1556. tc->add_child(import_tc);
  1557. tc->set_tab_title(1, TTR("Import Items"));
  1558. import_default_theme_items = memnew(ThemeItemImportTree);
  1559. import_tc->add_child(import_default_theme_items);
  1560. import_tc->set_tab_title(0, TTR("Default Theme"));
  1561. import_default_theme_items->connect("items_imported", this, "_update_edit_types");
  1562. import_editor_theme_items = memnew(ThemeItemImportTree);
  1563. import_tc->add_child(import_editor_theme_items);
  1564. import_tc->set_tab_title(1, TTR("Editor Theme"));
  1565. import_editor_theme_items->connect("items_imported", this, "_update_edit_types");
  1566. VBoxContainer *import_another_theme_vb = memnew(VBoxContainer);
  1567. HBoxContainer *import_another_file_hb = memnew(HBoxContainer);
  1568. import_another_theme_vb->add_child(import_another_file_hb);
  1569. import_another_theme_value = memnew(LineEdit);
  1570. import_another_theme_value->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  1571. import_another_theme_value->set_editable(false);
  1572. import_another_file_hb->add_child(import_another_theme_value);
  1573. import_another_theme_button = memnew(Button);
  1574. import_another_file_hb->add_child(import_another_theme_button);
  1575. import_another_theme_button->connect("pressed", this, "_open_select_another_theme");
  1576. import_another_theme_dialog = memnew(EditorFileDialog);
  1577. import_another_theme_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
  1578. import_another_theme_dialog->set_title(TTR("Select Another Theme Resource:"));
  1579. List<String> ext;
  1580. ResourceLoader::get_recognized_extensions_for_type("Theme", &ext);
  1581. for (List<String>::Element *E = ext.front(); E; E = E->next()) {
  1582. import_another_theme_dialog->add_filter(vformat("*.%s; %s", E->get(), TTR("Theme Resource")));
  1583. }
  1584. import_another_file_hb->add_child(import_another_theme_dialog);
  1585. import_another_theme_dialog->connect("file_selected", this, "_select_another_theme_cbk");
  1586. import_other_theme_items = memnew(ThemeItemImportTree);
  1587. import_other_theme_items->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1588. import_another_theme_vb->add_child(import_other_theme_items);
  1589. import_tc->add_child(import_another_theme_vb);
  1590. import_tc->set_tab_title(2, TTR("Another Theme"));
  1591. import_other_theme_items->connect("items_imported", this, "_update_edit_types");
  1592. confirm_closing_dialog = memnew(ConfirmationDialog);
  1593. confirm_closing_dialog->set_autowrap(true);
  1594. add_child(confirm_closing_dialog);
  1595. confirm_closing_dialog->connect("confirmed", this, "_close_dialog");
  1596. }
  1597. void ThemeTypeDialog::_dialog_about_to_show() {
  1598. add_type_filter->set_text("");
  1599. _update_add_type_options();
  1600. }
  1601. void ThemeTypeDialog::ok_pressed() {
  1602. _add_type_selected(add_type_filter->get_text().strip_edges());
  1603. }
  1604. void ThemeTypeDialog::_update_add_type_options(const String &p_filter) {
  1605. add_type_options->clear();
  1606. List<StringName> names;
  1607. Theme::get_default()->get_type_list(&names);
  1608. if (include_own_types) {
  1609. edited_theme->get_type_list(&names);
  1610. }
  1611. names.sort_custom<StringName::AlphCompare>();
  1612. Vector<StringName> unique_names;
  1613. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1614. // Filter out undesired values.
  1615. if (!p_filter.is_subsequence_ofi(String(E->get()))) {
  1616. continue;
  1617. }
  1618. // Skip duplicate values.
  1619. if (unique_names.find(E->get()) >= 0) {
  1620. continue;
  1621. }
  1622. unique_names.push_back(E->get());
  1623. Ref<Texture> item_icon;
  1624. if (E->get() == "") {
  1625. item_icon = get_icon("NodeDisabled", "EditorIcons");
  1626. } else {
  1627. item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled");
  1628. }
  1629. add_type_options->add_item(E->get(), item_icon);
  1630. }
  1631. }
  1632. void ThemeTypeDialog::_add_type_filter_cbk(const String &p_value) {
  1633. _update_add_type_options(p_value);
  1634. }
  1635. void ThemeTypeDialog::_add_type_options_cbk(int p_index) {
  1636. add_type_filter->set_text(add_type_options->get_item_text(p_index));
  1637. }
  1638. void ThemeTypeDialog::_add_type_dialog_entered(const String &p_value) {
  1639. _add_type_selected(p_value.strip_edges());
  1640. }
  1641. void ThemeTypeDialog::_add_type_dialog_activated(int p_index) {
  1642. _add_type_selected(add_type_options->get_item_text(p_index));
  1643. }
  1644. void ThemeTypeDialog::_add_type_selected(const String &p_type_name) {
  1645. pre_submitted_value = p_type_name;
  1646. if (p_type_name.empty()) {
  1647. add_type_confirmation->popup_centered();
  1648. return;
  1649. }
  1650. _add_type_confirmed();
  1651. }
  1652. void ThemeTypeDialog::_add_type_confirmed() {
  1653. emit_signal("type_selected", pre_submitted_value);
  1654. hide();
  1655. }
  1656. void ThemeTypeDialog::_notification(int p_what) {
  1657. switch (p_what) {
  1658. case NOTIFICATION_ENTER_TREE: {
  1659. connect("about_to_show", this, "_dialog_about_to_show");
  1660. FALLTHROUGH;
  1661. }
  1662. case NOTIFICATION_THEME_CHANGED: {
  1663. _update_add_type_options();
  1664. } break;
  1665. case NOTIFICATION_POST_POPUP: {
  1666. add_type_filter->grab_focus();
  1667. } break;
  1668. }
  1669. }
  1670. void ThemeTypeDialog::_bind_methods() {
  1671. ClassDB::bind_method("_dialog_about_to_show", &ThemeTypeDialog::_dialog_about_to_show);
  1672. ClassDB::bind_method("_add_type_filter_cbk", &ThemeTypeDialog::_add_type_filter_cbk);
  1673. ClassDB::bind_method("_add_type_dialog_entered", &ThemeTypeDialog::_add_type_dialog_entered);
  1674. ClassDB::bind_method("_add_type_options_cbk", &ThemeTypeDialog::_add_type_options_cbk);
  1675. ClassDB::bind_method("_add_type_dialog_activated", &ThemeTypeDialog::_add_type_dialog_activated);
  1676. ClassDB::bind_method("_add_type_confirmed", &ThemeTypeDialog::_add_type_confirmed);
  1677. ADD_SIGNAL(MethodInfo("type_selected", PropertyInfo(Variant::STRING, "type_name")));
  1678. }
  1679. void ThemeTypeDialog::set_edited_theme(const Ref<Theme> &p_theme) {
  1680. edited_theme = p_theme;
  1681. }
  1682. void ThemeTypeDialog::set_include_own_types(bool p_enable) {
  1683. include_own_types = p_enable;
  1684. }
  1685. ThemeTypeDialog::ThemeTypeDialog() {
  1686. get_ok()->set_text(TTR("Add Type"));
  1687. set_hide_on_ok(false);
  1688. VBoxContainer *add_type_vb = memnew(VBoxContainer);
  1689. add_child(add_type_vb);
  1690. Label *add_type_filter_label = memnew(Label);
  1691. add_type_filter_label->set_text(TTR("Filter the list of types or create a new custom type:"));
  1692. add_type_vb->add_child(add_type_filter_label);
  1693. add_type_filter = memnew(LineEdit);
  1694. add_type_vb->add_child(add_type_filter);
  1695. add_type_filter->connect("text_changed", this, "_add_type_filter_cbk");
  1696. add_type_filter->connect("text_entered", this, "_add_type_dialog_entered");
  1697. Label *add_type_options_label = memnew(Label);
  1698. add_type_options_label->set_text(TTR("Available Node-based types:"));
  1699. add_type_vb->add_child(add_type_options_label);
  1700. add_type_options = memnew(ItemList);
  1701. add_type_options->set_v_size_flags(Control::SIZE_EXPAND_FILL);
  1702. add_type_vb->add_child(add_type_options);
  1703. add_type_options->connect("item_selected", this, "_add_type_options_cbk");
  1704. add_type_options->connect("item_activated", this, "_add_type_dialog_activated");
  1705. add_type_confirmation = memnew(ConfirmationDialog);
  1706. add_type_confirmation->set_title(TTR("Type name is empty!"));
  1707. add_type_confirmation->set_text(TTR("Are you sure you want to create an empty type?"));
  1708. add_type_confirmation->connect("confirmed", this, "_add_type_confirmed");
  1709. add_child(add_type_confirmation);
  1710. }
  1711. VBoxContainer *ThemeTypeEditor::_create_item_list(Theme::DataType p_data_type) {
  1712. VBoxContainer *items_tab = memnew(VBoxContainer);
  1713. items_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE);
  1714. data_type_tabs->add_child(items_tab);
  1715. data_type_tabs->set_tab_title(data_type_tabs->get_tab_count() - 1, "");
  1716. ScrollContainer *items_sc = memnew(ScrollContainer);
  1717. items_sc->set_v_size_flags(SIZE_EXPAND_FILL);
  1718. items_sc->set_enable_h_scroll(false);
  1719. items_tab->add_child(items_sc);
  1720. VBoxContainer *items_list = memnew(VBoxContainer);
  1721. items_list->set_h_size_flags(SIZE_EXPAND_FILL);
  1722. items_sc->add_child(items_list);
  1723. HBoxContainer *item_add_hb = memnew(HBoxContainer);
  1724. items_tab->add_child(item_add_hb);
  1725. LineEdit *item_add_edit = memnew(LineEdit);
  1726. item_add_edit->set_h_size_flags(SIZE_EXPAND_FILL);
  1727. item_add_hb->add_child(item_add_edit);
  1728. item_add_edit->connect("text_entered", this, "_item_add_lineedit_cbk", varray(p_data_type, item_add_edit));
  1729. Button *item_add_button = memnew(Button);
  1730. item_add_button->set_text(TTR("Add"));
  1731. item_add_hb->add_child(item_add_button);
  1732. item_add_button->connect("pressed", this, "_item_add_cbk", varray(p_data_type, item_add_edit));
  1733. return items_list;
  1734. }
  1735. void ThemeTypeEditor::_update_type_list() {
  1736. ERR_FAIL_COND(edited_theme.is_null());
  1737. if (updating) {
  1738. return;
  1739. }
  1740. updating = true;
  1741. Control *focused = get_focus_owner();
  1742. if (focused) {
  1743. if (focusables.find(focused, 0) != -1) {
  1744. // If focus is currently on one of the internal property editors, don't update.
  1745. updating = false;
  1746. return;
  1747. }
  1748. Node *focus_parent = focused->get_parent();
  1749. while (focus_parent) {
  1750. Control *c = Object::cast_to<Control>(focus_parent);
  1751. if (c && focusables.find(c, 0) != -1) {
  1752. // If focus is currently on one of the internal property editors, don't update.
  1753. updating = false;
  1754. return;
  1755. }
  1756. focus_parent = focus_parent->get_parent();
  1757. }
  1758. }
  1759. List<StringName> theme_types;
  1760. edited_theme->get_type_list(&theme_types);
  1761. theme_types.sort_custom<StringName::AlphCompare>();
  1762. theme_type_list->clear();
  1763. if (theme_types.size() > 0) {
  1764. theme_type_list->set_disabled(false);
  1765. bool item_reselected = false;
  1766. int e_idx = 0;
  1767. for (List<StringName>::Element *E = theme_types.front(); E; E = E->next()) {
  1768. Ref<Texture> item_icon;
  1769. if (E->get() == "") {
  1770. item_icon = get_icon("NodeDisabled", "EditorIcons");
  1771. } else {
  1772. item_icon = EditorNode::get_singleton()->get_class_icon(E->get(), "NodeDisabled");
  1773. }
  1774. theme_type_list->add_icon_item(item_icon, E->get());
  1775. if (E->get() == edited_type) {
  1776. theme_type_list->select(e_idx);
  1777. item_reselected = true;
  1778. }
  1779. e_idx++;
  1780. }
  1781. if (!item_reselected) {
  1782. theme_type_list->select(0);
  1783. _list_type_selected(0);
  1784. } else {
  1785. _update_type_items();
  1786. }
  1787. } else {
  1788. theme_type_list->set_disabled(true);
  1789. theme_type_list->add_item(TTR("None"));
  1790. edited_type = "";
  1791. _update_type_items();
  1792. }
  1793. updating = false;
  1794. }
  1795. void ThemeTypeEditor::_update_type_list_debounced() {
  1796. update_debounce_timer->start();
  1797. }
  1798. OrderedHashMap<StringName, bool> ThemeTypeEditor::_get_type_items(String p_type_name, void (Theme::*get_list_func)(StringName, List<StringName> *) const, bool include_default) {
  1799. OrderedHashMap<StringName, bool> items;
  1800. List<StringName> names;
  1801. if (include_default) {
  1802. names.clear();
  1803. String default_type = p_type_name;
  1804. if (edited_theme->get_type_variation_base(p_type_name) != StringName()) {
  1805. default_type = edited_theme->get_type_variation_base(p_type_name);
  1806. }
  1807. (Theme::get_default().operator->()->*get_list_func)(default_type, &names);
  1808. names.sort_custom<StringName::AlphCompare>();
  1809. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1810. items[E->get()] = false;
  1811. }
  1812. }
  1813. {
  1814. names.clear();
  1815. (edited_theme.operator->()->*get_list_func)(p_type_name, &names);
  1816. names.sort_custom<StringName::AlphCompare>();
  1817. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  1818. items[E->get()] = true;
  1819. }
  1820. }
  1821. List<StringName> keys;
  1822. for (OrderedHashMap<StringName, bool>::Element E = items.front(); E; E = E.next()) {
  1823. keys.push_back(E.key());
  1824. }
  1825. keys.sort_custom<StringName::AlphCompare>();
  1826. OrderedHashMap<StringName, bool> ordered_items;
  1827. for (List<StringName>::Element *E = keys.front(); E; E = E->next()) {
  1828. ordered_items[E->get()] = items[E->get()];
  1829. }
  1830. return ordered_items;
  1831. }
  1832. HBoxContainer *ThemeTypeEditor::_create_property_control(Theme::DataType p_data_type, String p_item_name, bool p_editable) {
  1833. HBoxContainer *item_control = memnew(HBoxContainer);
  1834. HBoxContainer *item_name_container = memnew(HBoxContainer);
  1835. item_name_container->set_h_size_flags(SIZE_EXPAND_FILL);
  1836. item_name_container->set_stretch_ratio(2.0);
  1837. item_control->add_child(item_name_container);
  1838. Label *item_name = memnew(Label);
  1839. item_name->set_h_size_flags(SIZE_EXPAND_FILL);
  1840. item_name->set_clip_text(true);
  1841. item_name->set_text(p_item_name);
  1842. item_name->set_tooltip(p_item_name);
  1843. item_name_container->add_child(item_name);
  1844. if (p_editable) {
  1845. LineEdit *item_name_edit = memnew(LineEdit);
  1846. item_name_edit->set_h_size_flags(SIZE_EXPAND_FILL);
  1847. item_name_edit->set_text(p_item_name);
  1848. item_name_container->add_child(item_name_edit);
  1849. item_name_edit->connect("text_entered", this, "_item_rename_entered", varray(p_data_type, p_item_name, item_name_container));
  1850. item_name_edit->hide();
  1851. Button *item_rename_button = memnew(Button);
  1852. item_rename_button->set_icon(get_icon("Edit", "EditorIcons"));
  1853. item_rename_button->set_tooltip(TTR("Rename Item"));
  1854. item_rename_button->set_flat(true);
  1855. item_name_container->add_child(item_rename_button);
  1856. item_rename_button->connect("pressed", this, "_item_rename_cbk", varray(p_data_type, p_item_name, item_name_container));
  1857. Button *item_remove_button = memnew(Button);
  1858. item_remove_button->set_icon(get_icon("Remove", "EditorIcons"));
  1859. item_remove_button->set_tooltip(TTR("Remove Item"));
  1860. item_remove_button->set_flat(true);
  1861. item_name_container->add_child(item_remove_button);
  1862. item_remove_button->connect("pressed", this, "_item_remove_cbk", varray(p_data_type, p_item_name));
  1863. Button *item_rename_confirm_button = memnew(Button);
  1864. item_rename_confirm_button->set_icon(get_icon("ImportCheck", "EditorIcons"));
  1865. item_rename_confirm_button->set_tooltip(TTR("Confirm Item Rename"));
  1866. item_rename_confirm_button->set_flat(true);
  1867. item_name_container->add_child(item_rename_confirm_button);
  1868. item_rename_confirm_button->connect("pressed", this, "_item_rename_confirmed", varray(p_data_type, p_item_name, item_name_container));
  1869. item_rename_confirm_button->hide();
  1870. Button *item_rename_cancel_button = memnew(Button);
  1871. item_rename_cancel_button->set_icon(get_icon("ImportFail", "EditorIcons"));
  1872. item_rename_cancel_button->set_tooltip(TTR("Cancel Item Rename"));
  1873. item_rename_cancel_button->set_flat(true);
  1874. item_name_container->add_child(item_rename_cancel_button);
  1875. item_rename_cancel_button->connect("pressed", this, "_item_rename_canceled", varray(p_data_type, p_item_name, item_name_container));
  1876. item_rename_cancel_button->hide();
  1877. } else {
  1878. item_name->add_color_override("font_color", get_color("disabled_font_color", "Editor"));
  1879. Button *item_override_button = memnew(Button);
  1880. item_override_button->set_icon(get_icon("Add", "EditorIcons"));
  1881. item_override_button->set_tooltip(TTR("Override Item"));
  1882. item_override_button->set_flat(true);
  1883. item_name_container->add_child(item_override_button);
  1884. item_override_button->connect("pressed", this, "_item_override_cbk", varray(p_data_type, p_item_name));
  1885. }
  1886. return item_control;
  1887. }
  1888. void ThemeTypeEditor::_add_focusable(Control *p_control) {
  1889. focusables.push_back(p_control);
  1890. }
  1891. void ThemeTypeEditor::_update_type_items() {
  1892. bool show_default = show_default_items_button->is_pressed();
  1893. List<StringName> names;
  1894. focusables.clear();
  1895. // Colors.
  1896. {
  1897. for (int i = color_items_list->get_child_count() - 1; i >= 0; i--) {
  1898. Node *node = color_items_list->get_child(i);
  1899. node->queue_delete();
  1900. color_items_list->remove_child(node);
  1901. }
  1902. OrderedHashMap<StringName, bool> color_items = _get_type_items(edited_type, &Theme::get_color_list, show_default);
  1903. for (OrderedHashMap<StringName, bool>::Element E = color_items.front(); E; E = E.next()) {
  1904. HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_COLOR, E.key(), E.get());
  1905. ColorPickerButton *item_editor = memnew(ColorPickerButton);
  1906. item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
  1907. item_control->add_child(item_editor);
  1908. if (E.get()) {
  1909. item_editor->set_pick_color(edited_theme->get_color(E.key(), edited_type));
  1910. item_editor->connect("color_changed", this, "_color_item_changed", varray(E.key()));
  1911. } else {
  1912. item_editor->set_pick_color(Theme::get_default()->get_color(E.key(), edited_type));
  1913. item_editor->set_disabled(true);
  1914. }
  1915. _add_focusable(item_editor);
  1916. color_items_list->add_child(item_control);
  1917. }
  1918. }
  1919. // Constants.
  1920. {
  1921. for (int i = constant_items_list->get_child_count() - 1; i >= 0; i--) {
  1922. Node *node = constant_items_list->get_child(i);
  1923. node->queue_delete();
  1924. constant_items_list->remove_child(node);
  1925. }
  1926. OrderedHashMap<StringName, bool> constant_items = _get_type_items(edited_type, &Theme::get_constant_list, show_default);
  1927. for (OrderedHashMap<StringName, bool>::Element E = constant_items.front(); E; E = E.next()) {
  1928. HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_CONSTANT, E.key(), E.get());
  1929. SpinBox *item_editor = memnew(SpinBox);
  1930. item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
  1931. item_editor->set_min(-100000);
  1932. item_editor->set_max(100000);
  1933. item_editor->set_step(1);
  1934. item_editor->set_allow_lesser(true);
  1935. item_editor->set_allow_greater(true);
  1936. item_control->add_child(item_editor);
  1937. if (E.get()) {
  1938. item_editor->set_value(edited_theme->get_constant(E.key(), edited_type));
  1939. item_editor->connect("value_changed", this, "_constant_item_changed", varray(E.key()));
  1940. } else {
  1941. item_editor->set_value(Theme::get_default()->get_constant(E.key(), edited_type));
  1942. item_editor->set_editable(false);
  1943. }
  1944. _add_focusable(item_editor);
  1945. constant_items_list->add_child(item_control);
  1946. }
  1947. }
  1948. // Fonts.
  1949. {
  1950. for (int i = font_items_list->get_child_count() - 1; i >= 0; i--) {
  1951. Node *node = font_items_list->get_child(i);
  1952. node->queue_delete();
  1953. font_items_list->remove_child(node);
  1954. }
  1955. OrderedHashMap<StringName, bool> font_items = _get_type_items(edited_type, &Theme::get_font_list, show_default);
  1956. for (OrderedHashMap<StringName, bool>::Element E = font_items.front(); E; E = E.next()) {
  1957. HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_FONT, E.key(), E.get());
  1958. EditorResourcePicker *item_editor = memnew(EditorResourcePicker);
  1959. item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
  1960. item_editor->set_base_type("Font");
  1961. item_control->add_child(item_editor);
  1962. if (E.get()) {
  1963. if (edited_theme->has_font(E.key(), edited_type)) {
  1964. item_editor->set_edited_resource(edited_theme->get_font(E.key(), edited_type));
  1965. } else {
  1966. item_editor->set_edited_resource(RES());
  1967. }
  1968. item_editor->connect("resource_selected", this, "_edit_resource_item");
  1969. item_editor->connect("resource_changed", this, "_font_item_changed", varray(E.key()));
  1970. } else {
  1971. if (Theme::get_default()->has_font(E.key(), edited_type)) {
  1972. item_editor->set_edited_resource(Theme::get_default()->get_font(E.key(), edited_type));
  1973. } else {
  1974. item_editor->set_edited_resource(RES());
  1975. }
  1976. item_editor->set_editable(false);
  1977. }
  1978. _add_focusable(item_editor);
  1979. font_items_list->add_child(item_control);
  1980. }
  1981. }
  1982. // Icons.
  1983. {
  1984. for (int i = icon_items_list->get_child_count() - 1; i >= 0; i--) {
  1985. Node *node = icon_items_list->get_child(i);
  1986. node->queue_delete();
  1987. icon_items_list->remove_child(node);
  1988. }
  1989. OrderedHashMap<StringName, bool> icon_items = _get_type_items(edited_type, &Theme::get_icon_list, show_default);
  1990. for (OrderedHashMap<StringName, bool>::Element E = icon_items.front(); E; E = E.next()) {
  1991. HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_ICON, E.key(), E.get());
  1992. EditorResourcePicker *item_editor = memnew(EditorResourcePicker);
  1993. item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
  1994. item_editor->set_base_type("Texture");
  1995. item_control->add_child(item_editor);
  1996. if (E.get()) {
  1997. if (edited_theme->has_icon(E.key(), edited_type)) {
  1998. item_editor->set_edited_resource(edited_theme->get_icon(E.key(), edited_type));
  1999. } else {
  2000. item_editor->set_edited_resource(RES());
  2001. }
  2002. item_editor->connect("resource_selected", this, "_edit_resource_item");
  2003. item_editor->connect("resource_changed", this, "_icon_item_changed", varray(E.key()));
  2004. } else {
  2005. if (Theme::get_default()->has_icon(E.key(), edited_type)) {
  2006. item_editor->set_edited_resource(Theme::get_default()->get_icon(E.key(), edited_type));
  2007. } else {
  2008. item_editor->set_edited_resource(RES());
  2009. }
  2010. item_editor->set_editable(false);
  2011. }
  2012. _add_focusable(item_editor);
  2013. icon_items_list->add_child(item_control);
  2014. }
  2015. }
  2016. // Styleboxes.
  2017. {
  2018. for (int i = stylebox_items_list->get_child_count() - 1; i >= 0; i--) {
  2019. Node *node = stylebox_items_list->get_child(i);
  2020. node->queue_delete();
  2021. stylebox_items_list->remove_child(node);
  2022. }
  2023. if (leading_stylebox.pinned) {
  2024. HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, leading_stylebox.item_name, true);
  2025. EditorResourcePicker *item_editor = memnew(EditorResourcePicker);
  2026. item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
  2027. item_editor->set_stretch_ratio(1.5);
  2028. item_editor->set_base_type("StyleBox");
  2029. Button *pin_leader_button = memnew(Button);
  2030. pin_leader_button->set_flat(true);
  2031. pin_leader_button->set_toggle_mode(true);
  2032. pin_leader_button->set_pressed(true);
  2033. pin_leader_button->set_icon(get_icon("Pin", "EditorIcons"));
  2034. pin_leader_button->set_tooltip(TTR("Unpin this StyleBox as a main style."));
  2035. item_control->add_child(pin_leader_button);
  2036. pin_leader_button->connect("pressed", this, "_unpin_leading_stylebox");
  2037. item_control->add_child(item_editor);
  2038. if (leading_stylebox.stylebox.is_valid()) {
  2039. item_editor->set_edited_resource(leading_stylebox.stylebox);
  2040. } else {
  2041. item_editor->set_edited_resource(RES());
  2042. }
  2043. item_editor->connect("resource_selected", this, "_edit_resource_item");
  2044. item_editor->connect("resource_changed", this, "_stylebox_item_changed", varray(leading_stylebox.item_name));
  2045. stylebox_items_list->add_child(item_control);
  2046. stylebox_items_list->add_child(memnew(HSeparator));
  2047. }
  2048. OrderedHashMap<StringName, bool> stylebox_items = _get_type_items(edited_type, &Theme::get_stylebox_list, show_default);
  2049. for (OrderedHashMap<StringName, bool>::Element E = stylebox_items.front(); E; E = E.next()) {
  2050. if (leading_stylebox.pinned && leading_stylebox.item_name == E.key()) {
  2051. continue;
  2052. }
  2053. HBoxContainer *item_control = _create_property_control(Theme::DATA_TYPE_STYLEBOX, E.key(), E.get());
  2054. EditorResourcePicker *item_editor = memnew(EditorResourcePicker);
  2055. item_editor->set_h_size_flags(SIZE_EXPAND_FILL);
  2056. item_editor->set_stretch_ratio(1.5);
  2057. item_editor->set_base_type("StyleBox");
  2058. if (E.get()) {
  2059. Ref<StyleBox> stylebox_value;
  2060. if (edited_theme->has_stylebox(E.key(), edited_type)) {
  2061. stylebox_value = edited_theme->get_stylebox(E.key(), edited_type);
  2062. item_editor->set_edited_resource(stylebox_value);
  2063. } else {
  2064. item_editor->set_edited_resource(RES());
  2065. }
  2066. item_editor->connect("resource_selected", this, "_edit_resource_item");
  2067. item_editor->connect("resource_changed", this, "_stylebox_item_changed", varray(E.key()));
  2068. Button *pin_leader_button = memnew(Button);
  2069. pin_leader_button->set_flat(true);
  2070. pin_leader_button->set_toggle_mode(true);
  2071. pin_leader_button->set_icon(get_icon("Pin", "EditorIcons"));
  2072. pin_leader_button->set_tooltip(TTR("Pin this StyleBox as a main style. Editing its properties will update the same properties in all other StyleBoxes of this type."));
  2073. item_control->add_child(pin_leader_button);
  2074. pin_leader_button->connect("pressed", this, "_pin_leading_stylebox", varray(item_editor, E.key()));
  2075. } else {
  2076. if (Theme::get_default()->has_stylebox(E.key(), edited_type)) {
  2077. item_editor->set_edited_resource(Theme::get_default()->get_stylebox(E.key(), edited_type));
  2078. } else {
  2079. item_editor->set_edited_resource(RES());
  2080. }
  2081. item_editor->set_editable(false);
  2082. }
  2083. item_control->add_child(item_editor);
  2084. _add_focusable(item_editor);
  2085. stylebox_items_list->add_child(item_control);
  2086. }
  2087. }
  2088. // Various type settings.
  2089. if (edited_type.empty() || ClassDB::class_exists(edited_type)) {
  2090. type_variation_edit->set_editable(false);
  2091. type_variation_edit->set_text("");
  2092. type_variation_button->hide();
  2093. type_variation_locked->set_visible(!edited_type.empty());
  2094. } else {
  2095. type_variation_edit->set_editable(true);
  2096. type_variation_edit->set_text(edited_theme->get_type_variation_base(edited_type));
  2097. _add_focusable(type_variation_edit);
  2098. type_variation_button->show();
  2099. type_variation_locked->hide();
  2100. }
  2101. }
  2102. void ThemeTypeEditor::_list_type_selected(int p_index) {
  2103. edited_type = theme_type_list->get_item_text(p_index);
  2104. _update_type_items();
  2105. }
  2106. void ThemeTypeEditor::_add_type_button_cbk() {
  2107. add_type_mode = ADD_THEME_TYPE;
  2108. add_type_dialog->set_title(TTR("Add Item Type"));
  2109. add_type_dialog->get_ok()->set_text(TTR("Add Type"));
  2110. add_type_dialog->set_include_own_types(false);
  2111. add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);
  2112. }
  2113. void ThemeTypeEditor::_add_default_type_items() {
  2114. List<StringName> names;
  2115. String default_type = edited_type;
  2116. if (edited_theme->get_type_variation_base(edited_type) != StringName()) {
  2117. default_type = edited_theme->get_type_variation_base(edited_type);
  2118. }
  2119. updating = true;
  2120. // Prevent changes from immediately being reported while the operation is still ongoing.
  2121. edited_theme->_freeze_change_propagation();
  2122. {
  2123. names.clear();
  2124. Theme::get_default()->get_icon_list(default_type, &names);
  2125. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  2126. if (!edited_theme->has_icon(E->get(), edited_type)) {
  2127. edited_theme->set_icon(E->get(), edited_type, Ref<Texture>());
  2128. }
  2129. }
  2130. }
  2131. {
  2132. names.clear();
  2133. Theme::get_default()->get_stylebox_list(default_type, &names);
  2134. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  2135. if (!edited_theme->has_stylebox(E->get(), edited_type)) {
  2136. edited_theme->set_stylebox(E->get(), edited_type, Ref<StyleBox>());
  2137. }
  2138. }
  2139. }
  2140. {
  2141. names.clear();
  2142. Theme::get_default()->get_font_list(default_type, &names);
  2143. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  2144. if (!edited_theme->has_font(E->get(), edited_type)) {
  2145. edited_theme->set_font(E->get(), edited_type, Ref<Font>());
  2146. }
  2147. }
  2148. }
  2149. {
  2150. names.clear();
  2151. Theme::get_default()->get_color_list(default_type, &names);
  2152. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  2153. if (!edited_theme->has_color(E->get(), edited_type)) {
  2154. edited_theme->set_color(E->get(), edited_type, Theme::get_default()->get_color(E->get(), edited_type));
  2155. }
  2156. }
  2157. }
  2158. {
  2159. names.clear();
  2160. Theme::get_default()->get_constant_list(default_type, &names);
  2161. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  2162. if (!edited_theme->has_constant(E->get(), edited_type)) {
  2163. edited_theme->set_constant(E->get(), edited_type, Theme::get_default()->get_constant(E->get(), edited_type));
  2164. }
  2165. }
  2166. }
  2167. // Allow changes to be reported now that the operation is finished.
  2168. edited_theme->_unfreeze_and_propagate_changes();
  2169. updating = false;
  2170. _update_type_items();
  2171. }
  2172. void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) {
  2173. LineEdit *le = Object::cast_to<LineEdit>(p_control);
  2174. if (le->get_text().strip_edges().empty()) {
  2175. return;
  2176. }
  2177. String item_name = le->get_text().strip_edges();
  2178. switch (p_data_type) {
  2179. case Theme::DATA_TYPE_COLOR: {
  2180. edited_theme->set_color(item_name, edited_type, Color());
  2181. } break;
  2182. case Theme::DATA_TYPE_CONSTANT: {
  2183. edited_theme->set_constant(item_name, edited_type, 0);
  2184. } break;
  2185. case Theme::DATA_TYPE_FONT: {
  2186. edited_theme->set_font(item_name, edited_type, Ref<Font>());
  2187. } break;
  2188. case Theme::DATA_TYPE_ICON: {
  2189. edited_theme->set_icon(item_name, edited_type, Ref<Texture>());
  2190. } break;
  2191. case Theme::DATA_TYPE_STYLEBOX: {
  2192. edited_theme->set_stylebox(item_name, edited_type, Ref<StyleBox>());
  2193. } break;
  2194. }
  2195. le->set_text("");
  2196. }
  2197. void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Control *p_control) {
  2198. _item_add_cbk(p_data_type, p_control);
  2199. }
  2200. void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
  2201. switch (p_data_type) {
  2202. case Theme::DATA_TYPE_COLOR: {
  2203. edited_theme->set_color(p_item_name, edited_type, Theme::get_default()->get_color(p_item_name, edited_type));
  2204. } break;
  2205. case Theme::DATA_TYPE_CONSTANT: {
  2206. edited_theme->set_constant(p_item_name, edited_type, Theme::get_default()->get_constant(p_item_name, edited_type));
  2207. } break;
  2208. case Theme::DATA_TYPE_FONT: {
  2209. edited_theme->set_font(p_item_name, edited_type, Ref<Font>());
  2210. } break;
  2211. case Theme::DATA_TYPE_ICON: {
  2212. edited_theme->set_icon(p_item_name, edited_type, Ref<Texture>());
  2213. } break;
  2214. case Theme::DATA_TYPE_STYLEBOX: {
  2215. edited_theme->set_stylebox(p_item_name, edited_type, Ref<StyleBox>());
  2216. } break;
  2217. }
  2218. }
  2219. void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) {
  2220. switch (p_data_type) {
  2221. case Theme::DATA_TYPE_COLOR: {
  2222. edited_theme->clear_color(p_item_name, edited_type);
  2223. } break;
  2224. case Theme::DATA_TYPE_CONSTANT: {
  2225. edited_theme->clear_constant(p_item_name, edited_type);
  2226. } break;
  2227. case Theme::DATA_TYPE_FONT: {
  2228. edited_theme->clear_font(p_item_name, edited_type);
  2229. } break;
  2230. case Theme::DATA_TYPE_ICON: {
  2231. edited_theme->clear_icon(p_item_name, edited_type);
  2232. } break;
  2233. case Theme::DATA_TYPE_STYLEBOX: {
  2234. edited_theme->clear_stylebox(p_item_name, edited_type);
  2235. if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {
  2236. _unpin_leading_stylebox();
  2237. }
  2238. } break;
  2239. }
  2240. }
  2241. void ThemeTypeEditor::_item_rename_cbk(int p_data_type, String p_item_name, Control *p_control) {
  2242. // Label
  2243. Object::cast_to<Label>(p_control->get_child(0))->hide();
  2244. // Label buttons
  2245. Object::cast_to<Button>(p_control->get_child(2))->hide();
  2246. Object::cast_to<Button>(p_control->get_child(3))->hide();
  2247. // LineEdit
  2248. Object::cast_to<LineEdit>(p_control->get_child(1))->set_text(p_item_name);
  2249. Object::cast_to<LineEdit>(p_control->get_child(1))->show();
  2250. // LineEdit buttons
  2251. Object::cast_to<Button>(p_control->get_child(4))->show();
  2252. Object::cast_to<Button>(p_control->get_child(5))->show();
  2253. }
  2254. void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name, Control *p_control) {
  2255. LineEdit *le = Object::cast_to<LineEdit>(p_control->get_child(1));
  2256. if (le->get_text().strip_edges().empty()) {
  2257. return;
  2258. }
  2259. String new_name = le->get_text().strip_edges();
  2260. if (new_name == p_item_name) {
  2261. _item_rename_canceled(p_data_type, p_item_name, p_control);
  2262. return;
  2263. }
  2264. switch (p_data_type) {
  2265. case Theme::DATA_TYPE_COLOR: {
  2266. edited_theme->rename_color(p_item_name, new_name, edited_type);
  2267. } break;
  2268. case Theme::DATA_TYPE_CONSTANT: {
  2269. edited_theme->rename_constant(p_item_name, new_name, edited_type);
  2270. } break;
  2271. case Theme::DATA_TYPE_FONT: {
  2272. edited_theme->rename_font(p_item_name, new_name, edited_type);
  2273. } break;
  2274. case Theme::DATA_TYPE_ICON: {
  2275. edited_theme->rename_icon(p_item_name, new_name, edited_type);
  2276. } break;
  2277. case Theme::DATA_TYPE_STYLEBOX: {
  2278. edited_theme->rename_stylebox(p_item_name, new_name, edited_type);
  2279. if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {
  2280. leading_stylebox.item_name = new_name;
  2281. }
  2282. } break;
  2283. }
  2284. }
  2285. void ThemeTypeEditor::_item_rename_entered(String p_value, int p_data_type, String p_item_name, Control *p_control) {
  2286. _item_rename_confirmed(p_data_type, p_item_name, p_control);
  2287. }
  2288. void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name, Control *p_control) {
  2289. // LineEdit
  2290. Object::cast_to<LineEdit>(p_control->get_child(1))->hide();
  2291. // LineEdit buttons
  2292. Object::cast_to<Button>(p_control->get_child(4))->hide();
  2293. Object::cast_to<Button>(p_control->get_child(5))->hide();
  2294. // Label
  2295. Object::cast_to<Label>(p_control->get_child(0))->show();
  2296. // Label buttons
  2297. Object::cast_to<Button>(p_control->get_child(2))->show();
  2298. Object::cast_to<Button>(p_control->get_child(3))->show();
  2299. }
  2300. void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {
  2301. edited_theme->set_color(p_item_name, edited_type, p_value);
  2302. }
  2303. void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) {
  2304. edited_theme->set_constant(p_item_name, edited_type, int(p_value));
  2305. }
  2306. void ThemeTypeEditor::_edit_resource_item(RES p_resource, bool p_edit) {
  2307. EditorNode::get_singleton()->edit_resource(p_resource);
  2308. }
  2309. void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) {
  2310. edited_theme->set_font(p_item_name, edited_type, p_value);
  2311. }
  2312. void ThemeTypeEditor::_icon_item_changed(Ref<Texture> p_value, String p_item_name) {
  2313. edited_theme->set_icon(p_item_name, edited_type, p_value);
  2314. }
  2315. void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) {
  2316. edited_theme->set_stylebox(p_item_name, edited_type, p_value);
  2317. if (leading_stylebox.pinned && leading_stylebox.item_name == p_item_name) {
  2318. if (leading_stylebox.stylebox.is_valid()) {
  2319. leading_stylebox.stylebox->disconnect("changed", this, "_update_stylebox_from_leading");
  2320. }
  2321. leading_stylebox.stylebox = p_value;
  2322. leading_stylebox.ref_stylebox = (p_value.is_valid() ? p_value->duplicate() : RES());
  2323. if (p_value.is_valid()) {
  2324. leading_stylebox.stylebox->connect("changed", this, "_update_stylebox_from_leading");
  2325. }
  2326. }
  2327. }
  2328. void ThemeTypeEditor::_pin_leading_stylebox(Control *p_editor, String p_item_name) {
  2329. if (leading_stylebox.stylebox.is_valid()) {
  2330. leading_stylebox.stylebox->disconnect("changed", this, "_update_stylebox_from_leading");
  2331. }
  2332. Ref<StyleBox> stylebox;
  2333. if (Object::cast_to<EditorResourcePicker>(p_editor)) {
  2334. stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource();
  2335. }
  2336. LeadingStylebox leader;
  2337. leader.pinned = true;
  2338. leader.item_name = p_item_name;
  2339. leader.stylebox = stylebox;
  2340. leader.ref_stylebox = (stylebox.is_valid() ? stylebox->duplicate() : RES());
  2341. leading_stylebox = leader;
  2342. if (leading_stylebox.stylebox.is_valid()) {
  2343. leading_stylebox.stylebox->connect("changed", this, "_update_stylebox_from_leading");
  2344. }
  2345. _update_type_items();
  2346. }
  2347. void ThemeTypeEditor::_unpin_leading_stylebox() {
  2348. if (leading_stylebox.stylebox.is_valid()) {
  2349. leading_stylebox.stylebox->disconnect("changed", this, "_update_stylebox_from_leading");
  2350. }
  2351. LeadingStylebox leader;
  2352. leader.pinned = false;
  2353. leading_stylebox = leader;
  2354. _update_type_items();
  2355. }
  2356. void ThemeTypeEditor::_update_stylebox_from_leading() {
  2357. if (!leading_stylebox.pinned || leading_stylebox.stylebox.is_null()) {
  2358. return;
  2359. }
  2360. // Prevent changes from immediately being reported while the operation is still ongoing.
  2361. edited_theme->_freeze_change_propagation();
  2362. List<StringName> names;
  2363. edited_theme->get_stylebox_list(edited_type, &names);
  2364. List<Ref<StyleBox>> styleboxes;
  2365. for (List<StringName>::Element *E = names.front(); E; E = E->next()) {
  2366. Ref<StyleBox> sb = edited_theme->get_stylebox(E->get(), edited_type);
  2367. // Avoid itself, stylebox can be shared between items.
  2368. if (sb == leading_stylebox.stylebox) {
  2369. continue;
  2370. }
  2371. if (sb->get_class() == leading_stylebox.stylebox->get_class()) {
  2372. styleboxes.push_back(sb);
  2373. }
  2374. }
  2375. List<PropertyInfo> props;
  2376. leading_stylebox.stylebox->get_property_list(&props);
  2377. for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
  2378. if (!(E->get().usage & PROPERTY_USAGE_STORAGE)) {
  2379. continue;
  2380. }
  2381. Variant value = leading_stylebox.stylebox->get(E->get().name);
  2382. Variant ref_value = leading_stylebox.ref_stylebox->get(E->get().name);
  2383. if (value == ref_value) {
  2384. continue;
  2385. }
  2386. for (List<Ref<StyleBox>>::Element *F = styleboxes.front(); F; F = F->next()) {
  2387. Ref<StyleBox> sb = F->get();
  2388. sb->set(E->get().name, value);
  2389. }
  2390. }
  2391. leading_stylebox.ref_stylebox = leading_stylebox.stylebox->duplicate();
  2392. // Allow changes to be reported now that the operation is finished.
  2393. edited_theme->_unfreeze_and_propagate_changes();
  2394. }
  2395. void ThemeTypeEditor::_type_variation_changed(const String p_value) {
  2396. if (p_value.empty()) {
  2397. edited_theme->clear_type_variation(edited_type);
  2398. } else {
  2399. edited_theme->set_type_variation(edited_type, StringName(p_value));
  2400. }
  2401. }
  2402. void ThemeTypeEditor::_add_type_variation_cbk() {
  2403. add_type_mode = ADD_VARIATION_BASE;
  2404. add_type_dialog->set_title(TTR("Set Variation Base Type"));
  2405. add_type_dialog->get_ok()->set_text(TTR("Set Base Type"));
  2406. add_type_dialog->set_include_own_types(true);
  2407. add_type_dialog->popup_centered(Size2(560, 420) * EDSCALE);
  2408. }
  2409. void ThemeTypeEditor::_add_type_dialog_selected(const String p_type_name) {
  2410. if (add_type_mode == ADD_THEME_TYPE) {
  2411. select_type(p_type_name);
  2412. } else if (add_type_mode == ADD_VARIATION_BASE) {
  2413. _type_variation_changed(p_type_name);
  2414. }
  2415. }
  2416. void ThemeTypeEditor::_notification(int p_what) {
  2417. switch (p_what) {
  2418. case NOTIFICATION_ENTER_TREE:
  2419. case NOTIFICATION_THEME_CHANGED: {
  2420. add_type_button->set_icon(get_icon("Add", "EditorIcons"));
  2421. data_type_tabs->set_tab_icon(0, get_icon("Color", "EditorIcons"));
  2422. data_type_tabs->set_tab_icon(1, get_icon("MemberConstant", "EditorIcons"));
  2423. data_type_tabs->set_tab_icon(2, get_icon("Font", "EditorIcons"));
  2424. data_type_tabs->set_tab_icon(3, get_icon("ImageTexture", "EditorIcons"));
  2425. data_type_tabs->set_tab_icon(4, get_icon("StyleBoxFlat", "EditorIcons"));
  2426. data_type_tabs->set_tab_icon(5, get_icon("Tools", "EditorIcons"));
  2427. data_type_tabs->add_style_override("tab_selected", get_stylebox("tab_selected_odd", "TabContainer"));
  2428. data_type_tabs->add_style_override("panel", get_stylebox("panel_odd", "TabContainer"));
  2429. type_variation_button->set_icon(get_icon("Add", "EditorIcons"));
  2430. } break;
  2431. }
  2432. }
  2433. void ThemeTypeEditor::_bind_methods() {
  2434. // Internal binds.
  2435. ClassDB::bind_method("_update_type_list", &ThemeTypeEditor::_update_type_list);
  2436. ClassDB::bind_method("_update_type_list_debounced", &ThemeTypeEditor::_update_type_list_debounced);
  2437. ClassDB::bind_method("_update_type_items", &ThemeTypeEditor::_update_type_items);
  2438. ClassDB::bind_method("_list_type_selected", &ThemeTypeEditor::_list_type_selected);
  2439. ClassDB::bind_method("_add_type_button_cbk", &ThemeTypeEditor::_add_type_button_cbk);
  2440. ClassDB::bind_method("_add_type_variation_cbk", &ThemeTypeEditor::_add_type_variation_cbk);
  2441. ClassDB::bind_method("_add_type_dialog_selected", &ThemeTypeEditor::_add_type_dialog_selected);
  2442. ClassDB::bind_method("_add_default_type_items", &ThemeTypeEditor::_add_default_type_items);
  2443. ClassDB::bind_method("_item_add_lineedit_cbk", &ThemeTypeEditor::_item_add_lineedit_cbk);
  2444. ClassDB::bind_method("_item_add_cbk", &ThemeTypeEditor::_item_add_cbk);
  2445. ClassDB::bind_method("_item_rename_cbk", &ThemeTypeEditor::_item_rename_cbk);
  2446. ClassDB::bind_method("_item_rename_entered", &ThemeTypeEditor::_item_rename_entered);
  2447. ClassDB::bind_method("_item_rename_confirmed", &ThemeTypeEditor::_item_rename_confirmed);
  2448. ClassDB::bind_method("_item_rename_canceled", &ThemeTypeEditor::_item_rename_canceled);
  2449. ClassDB::bind_method("_item_remove_cbk", &ThemeTypeEditor::_item_remove_cbk);
  2450. ClassDB::bind_method("_item_override_cbk", &ThemeTypeEditor::_item_override_cbk);
  2451. ClassDB::bind_method("_color_item_changed", &ThemeTypeEditor::_color_item_changed);
  2452. ClassDB::bind_method("_constant_item_changed", &ThemeTypeEditor::_constant_item_changed);
  2453. ClassDB::bind_method("_edit_resource_item", &ThemeTypeEditor::_edit_resource_item);
  2454. ClassDB::bind_method("_font_item_changed", &ThemeTypeEditor::_font_item_changed);
  2455. ClassDB::bind_method("_icon_item_changed", &ThemeTypeEditor::_icon_item_changed);
  2456. ClassDB::bind_method("_stylebox_item_changed", &ThemeTypeEditor::_stylebox_item_changed);
  2457. ClassDB::bind_method("_pin_leading_stylebox", &ThemeTypeEditor::_pin_leading_stylebox);
  2458. ClassDB::bind_method("_unpin_leading_stylebox", &ThemeTypeEditor::_unpin_leading_stylebox);
  2459. ClassDB::bind_method("_update_stylebox_from_leading", &ThemeTypeEditor::_update_stylebox_from_leading);
  2460. ClassDB::bind_method("_type_variation_changed", &ThemeTypeEditor::_type_variation_changed);
  2461. }
  2462. void ThemeTypeEditor::set_edited_theme(const Ref<Theme> &p_theme) {
  2463. if (edited_theme.is_valid()) {
  2464. edited_theme->disconnect("changed", this, "_update_type_list_debounced");
  2465. }
  2466. edited_theme = p_theme;
  2467. edited_theme->connect("changed", this, "_update_type_list_debounced");
  2468. _update_type_list();
  2469. add_type_dialog->set_edited_theme(edited_theme);
  2470. }
  2471. void ThemeTypeEditor::select_type(String p_type_name) {
  2472. edited_type = p_type_name;
  2473. bool type_exists = false;
  2474. for (int i = 0; i < theme_type_list->get_item_count(); i++) {
  2475. String type_name = theme_type_list->get_item_text(i);
  2476. if (type_name == edited_type) {
  2477. theme_type_list->select(i);
  2478. type_exists = true;
  2479. break;
  2480. }
  2481. }
  2482. if (type_exists) {
  2483. _update_type_items();
  2484. } else {
  2485. edited_theme->add_icon_type(edited_type);
  2486. edited_theme->add_stylebox_type(edited_type);
  2487. edited_theme->add_font_type(edited_type);
  2488. edited_theme->add_color_type(edited_type);
  2489. edited_theme->add_constant_type(edited_type);
  2490. _update_type_list();
  2491. }
  2492. }
  2493. ThemeTypeEditor::ThemeTypeEditor() {
  2494. VBoxContainer *main_vb = memnew(VBoxContainer);
  2495. add_child(main_vb);
  2496. HBoxContainer *type_list_hb = memnew(HBoxContainer);
  2497. main_vb->add_child(type_list_hb);
  2498. Label *type_list_label = memnew(Label);
  2499. type_list_label->set_text(TTR("Type:"));
  2500. type_list_hb->add_child(type_list_label);
  2501. theme_type_list = memnew(OptionButton);
  2502. theme_type_list->set_h_size_flags(SIZE_EXPAND_FILL);
  2503. type_list_hb->add_child(theme_type_list);
  2504. theme_type_list->connect("item_selected", this, "_list_type_selected");
  2505. add_type_button = memnew(Button);
  2506. add_type_button->set_tooltip(TTR("Add Type"));
  2507. type_list_hb->add_child(add_type_button);
  2508. add_type_button->connect("pressed", this, "_add_type_button_cbk");
  2509. HBoxContainer *type_controls = memnew(HBoxContainer);
  2510. main_vb->add_child(type_controls);
  2511. show_default_items_button = memnew(CheckButton);
  2512. show_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);
  2513. show_default_items_button->set_text(TTR("Show Default"));
  2514. show_default_items_button->set_tooltip(TTR("Show default type items alongside items that have been overridden."));
  2515. show_default_items_button->set_pressed(true);
  2516. type_controls->add_child(show_default_items_button);
  2517. show_default_items_button->connect("pressed", this, "_update_type_items");
  2518. Button *add_default_items_button = memnew(Button);
  2519. add_default_items_button->set_h_size_flags(SIZE_EXPAND_FILL);
  2520. add_default_items_button->set_text(TTR("Override All"));
  2521. add_default_items_button->set_tooltip(TTR("Override all default type items."));
  2522. type_controls->add_child(add_default_items_button);
  2523. add_default_items_button->connect("pressed", this, "_add_default_type_items");
  2524. data_type_tabs = memnew(TabContainer);
  2525. main_vb->add_child(data_type_tabs);
  2526. data_type_tabs->set_v_size_flags(SIZE_EXPAND_FILL);
  2527. data_type_tabs->set_use_hidden_tabs_for_min_size(true);
  2528. color_items_list = _create_item_list(Theme::DATA_TYPE_COLOR);
  2529. constant_items_list = _create_item_list(Theme::DATA_TYPE_CONSTANT);
  2530. font_items_list = _create_item_list(Theme::DATA_TYPE_FONT);
  2531. icon_items_list = _create_item_list(Theme::DATA_TYPE_ICON);
  2532. stylebox_items_list = _create_item_list(Theme::DATA_TYPE_STYLEBOX);
  2533. VBoxContainer *type_settings_tab = memnew(VBoxContainer);
  2534. type_settings_tab->set_custom_minimum_size(Size2(0, 160) * EDSCALE);
  2535. data_type_tabs->add_child(type_settings_tab);
  2536. data_type_tabs->set_tab_title(data_type_tabs->get_tab_count() - 1, "");
  2537. ScrollContainer *type_settings_sc = memnew(ScrollContainer);
  2538. type_settings_sc->set_v_size_flags(SIZE_EXPAND_FILL);
  2539. type_settings_sc->set_enable_h_scroll(false);
  2540. type_settings_tab->add_child(type_settings_sc);
  2541. VBoxContainer *type_settings_list = memnew(VBoxContainer);
  2542. type_settings_list->set_h_size_flags(SIZE_EXPAND_FILL);
  2543. type_settings_sc->add_child(type_settings_list);
  2544. VBoxContainer *type_variation_vb = memnew(VBoxContainer);
  2545. type_settings_list->add_child(type_variation_vb);
  2546. HBoxContainer *type_variation_hb = memnew(HBoxContainer);
  2547. type_variation_vb->add_child(type_variation_hb);
  2548. Label *type_variation_label = memnew(Label);
  2549. type_variation_hb->add_child(type_variation_label);
  2550. type_variation_label->set_text(TTR("Base Type"));
  2551. type_variation_label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  2552. type_variation_edit = memnew(LineEdit);
  2553. type_variation_hb->add_child(type_variation_edit);
  2554. type_variation_edit->set_h_size_flags(Control::SIZE_EXPAND_FILL);
  2555. type_variation_edit->connect("text_changed", this, "_type_variation_changed");
  2556. type_variation_edit->connect("focus_exited", this, "_update_type_items");
  2557. type_variation_button = memnew(Button);
  2558. type_variation_hb->add_child(type_variation_button);
  2559. type_variation_button->set_tooltip(TTR("Select the variation base type from a list of available types."));
  2560. type_variation_button->connect("pressed", this, "_add_type_variation_cbk");
  2561. type_variation_locked = memnew(Label);
  2562. type_variation_vb->add_child(type_variation_locked);
  2563. type_variation_locked->set_align(Label::ALIGN_CENTER);
  2564. type_variation_locked->set_autowrap(true);
  2565. type_variation_locked->set_text(TTR("A type associated with a built-in class cannot be marked as a variation of another type."));
  2566. type_variation_locked->hide();
  2567. add_type_dialog = memnew(ThemeTypeDialog);
  2568. add_type_dialog->set_title(TTR("Add Item Type"));
  2569. add_child(add_type_dialog);
  2570. add_type_dialog->connect("type_selected", this, "_add_type_dialog_selected");
  2571. update_debounce_timer = memnew(Timer);
  2572. update_debounce_timer->set_one_shot(true);
  2573. update_debounce_timer->set_wait_time(0.5);
  2574. update_debounce_timer->connect("timeout", this, "_update_type_list");
  2575. add_child(update_debounce_timer);
  2576. }
  2577. void ThemeEditor::edit(const Ref<Theme> &p_theme) {
  2578. if (theme == p_theme) {
  2579. return;
  2580. }
  2581. theme = p_theme;
  2582. theme_type_editor->set_edited_theme(p_theme);
  2583. theme_edit_dialog->set_edited_theme(p_theme);
  2584. for (int i = 0; i < preview_tabs_content->get_child_count(); i++) {
  2585. ThemeEditorPreview *preview_tab = Object::cast_to<ThemeEditorPreview>(preview_tabs_content->get_child(i));
  2586. if (!preview_tab) {
  2587. continue;
  2588. }
  2589. preview_tab->set_preview_theme(p_theme);
  2590. }
  2591. theme_name->set_text(TTR("Theme:") + " " + theme->get_path().get_file());
  2592. }
  2593. Ref<Theme> ThemeEditor::get_edited_theme() {
  2594. return theme;
  2595. }
  2596. void ThemeEditor::_theme_save_button_cbk(bool p_save_as) {
  2597. ERR_FAIL_COND_MSG(theme.is_null(), "Invalid state of the Theme Editor; the Theme resource is missing.");
  2598. if (p_save_as) {
  2599. EditorNode::get_singleton()->save_resource_as(theme);
  2600. } else {
  2601. EditorNode::get_singleton()->save_resource(theme);
  2602. }
  2603. }
  2604. void ThemeEditor::_theme_edit_button_cbk() {
  2605. theme_edit_dialog->popup_centered(Size2(850, 700) * EDSCALE);
  2606. }
  2607. void ThemeEditor::_add_preview_button_cbk() {
  2608. preview_scene_dialog->popup_centered_ratio();
  2609. }
  2610. void ThemeEditor::_preview_scene_dialog_cbk(const String &p_path) {
  2611. SceneThemeEditorPreview *preview_tab = memnew(SceneThemeEditorPreview);
  2612. if (!preview_tab->set_preview_scene(p_path)) {
  2613. return;
  2614. }
  2615. _add_preview_tab(preview_tab, p_path.get_file(), get_icon("PackedScene", "EditorIcons"));
  2616. preview_tab->connect("scene_invalidated", this, "_remove_preview_tab_invalid", varray(preview_tab));
  2617. preview_tab->connect("scene_reloaded", this, "_update_preview_tab", varray(preview_tab));
  2618. }
  2619. void ThemeEditor::_add_preview_tab(ThemeEditorPreview *p_preview_tab, const String &p_preview_name, const Ref<Texture> &p_icon) {
  2620. p_preview_tab->set_preview_theme(theme);
  2621. preview_tabs->add_tab(p_preview_name, p_icon);
  2622. preview_tabs_content->add_child(p_preview_tab);
  2623. preview_tabs->set_tab_right_button(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_gui_base()->get_icon("close", "Tabs"));
  2624. p_preview_tab->connect("control_picked", this, "_preview_control_picked");
  2625. preview_tabs->set_current_tab(preview_tabs->get_tab_count() - 1);
  2626. }
  2627. void ThemeEditor::_change_preview_tab(int p_tab) {
  2628. ERR_FAIL_INDEX_MSG(p_tab, preview_tabs_content->get_child_count(), "Attempting to open a preview tab that doesn't exist.");
  2629. for (int i = 0; i < preview_tabs_content->get_child_count(); i++) {
  2630. Control *c = Object::cast_to<Control>(preview_tabs_content->get_child(i));
  2631. if (!c) {
  2632. continue;
  2633. }
  2634. c->set_visible(i == p_tab);
  2635. }
  2636. }
  2637. void ThemeEditor::_remove_preview_tab(int p_tab) {
  2638. ERR_FAIL_INDEX_MSG(p_tab, preview_tabs_content->get_child_count(), "Attempting to remove a preview tab that doesn't exist.");
  2639. ThemeEditorPreview *preview_tab = Object::cast_to<ThemeEditorPreview>(preview_tabs_content->get_child(p_tab));
  2640. ERR_FAIL_COND_MSG(Object::cast_to<DefaultThemeEditorPreview>(preview_tab), "Attemptying to remove the default preview tab.");
  2641. if (preview_tab) {
  2642. preview_tab->disconnect("control_picked", this, "_preview_control_picked");
  2643. if (preview_tab->is_connected("scene_invalidated", this, "_remove_preview_tab_invalid")) {
  2644. preview_tab->disconnect("scene_invalidated", this, "_remove_preview_tab_invalid");
  2645. }
  2646. if (preview_tab->is_connected("scene_reloaded", this, "_update_preview_tab")) {
  2647. preview_tab->disconnect("scene_reloaded", this, "_update_preview_tab");
  2648. }
  2649. preview_tabs_content->remove_child(preview_tab);
  2650. preview_tabs->remove_tab(p_tab);
  2651. _change_preview_tab(preview_tabs->get_current_tab());
  2652. }
  2653. }
  2654. void ThemeEditor::_remove_preview_tab_invalid(Node *p_tab_control) {
  2655. int tab_index = p_tab_control->get_index();
  2656. _remove_preview_tab(tab_index);
  2657. }
  2658. void ThemeEditor::_update_preview_tab(Node *p_tab_control) {
  2659. if (!Object::cast_to<SceneThemeEditorPreview>(p_tab_control)) {
  2660. return;
  2661. }
  2662. int tab_index = p_tab_control->get_index();
  2663. SceneThemeEditorPreview *scene_preview = Object::cast_to<SceneThemeEditorPreview>(p_tab_control);
  2664. preview_tabs->set_tab_title(tab_index, scene_preview->get_preview_scene_path().get_file());
  2665. }
  2666. void ThemeEditor::_preview_control_picked(String p_class_name) {
  2667. theme_type_editor->select_type(p_class_name);
  2668. }
  2669. void ThemeEditor::_notification(int p_what) {
  2670. switch (p_what) {
  2671. case NOTIFICATION_ENTER_TREE:
  2672. case NOTIFICATION_THEME_CHANGED: {
  2673. preview_tabs->add_style_override("tab_fg", get_stylebox("ThemeEditorPreviewFG", "EditorStyles"));
  2674. preview_tabs->add_style_override("tab_bg", get_stylebox("ThemeEditorPreviewBG", "EditorStyles"));
  2675. preview_tabs_content->add_style_override("panel", get_stylebox("panel_odd", "TabContainer"));
  2676. add_preview_button->set_icon(get_icon("Add", "EditorIcons"));
  2677. } break;
  2678. }
  2679. }
  2680. void ThemeEditor::_bind_methods() {
  2681. // Internal binds.
  2682. ClassDB::bind_method("_theme_save_button_cbk", &ThemeEditor::_theme_save_button_cbk);
  2683. ClassDB::bind_method("_theme_edit_button_cbk", &ThemeEditor::_theme_edit_button_cbk);
  2684. ClassDB::bind_method("_change_preview_tab", &ThemeEditor::_change_preview_tab);
  2685. ClassDB::bind_method("_remove_preview_tab", &ThemeEditor::_remove_preview_tab);
  2686. ClassDB::bind_method("_add_preview_button_cbk", &ThemeEditor::_add_preview_button_cbk);
  2687. ClassDB::bind_method("_preview_control_picked", &ThemeEditor::_preview_control_picked);
  2688. ClassDB::bind_method("_preview_scene_dialog_cbk", &ThemeEditor::_preview_scene_dialog_cbk);
  2689. ClassDB::bind_method("_remove_preview_tab_invalid", &ThemeEditor::_remove_preview_tab_invalid);
  2690. ClassDB::bind_method("_update_preview_tab", &ThemeEditor::_update_preview_tab);
  2691. }
  2692. ThemeEditor::ThemeEditor() {
  2693. HBoxContainer *top_menu = memnew(HBoxContainer);
  2694. add_child(top_menu);
  2695. theme_name = memnew(Label);
  2696. theme_name->set_text(TTR("Theme:"));
  2697. top_menu->add_child(theme_name);
  2698. top_menu->add_spacer(false);
  2699. Button *theme_save_button = memnew(Button);
  2700. theme_save_button->set_text(TTR("Save"));
  2701. theme_save_button->set_flat(true);
  2702. theme_save_button->connect("pressed", this, "_theme_save_button_cbk", varray(false));
  2703. top_menu->add_child(theme_save_button);
  2704. Button *theme_save_as_button = memnew(Button);
  2705. theme_save_as_button->set_text(TTR("Save As..."));
  2706. theme_save_as_button->set_flat(true);
  2707. theme_save_as_button->connect("pressed", this, "_theme_save_button_cbk", varray(true));
  2708. top_menu->add_child(theme_save_as_button);
  2709. top_menu->add_child(memnew(VSeparator));
  2710. Button *theme_edit_button = memnew(Button);
  2711. theme_edit_button->set_text(TTR("Manage Items..."));
  2712. theme_edit_button->set_tooltip(TTR("Add, remove, organize and import Theme items."));
  2713. theme_edit_button->set_flat(true);
  2714. theme_edit_button->connect("pressed", this, "_theme_edit_button_cbk");
  2715. top_menu->add_child(theme_edit_button);
  2716. theme_edit_dialog = memnew(ThemeItemEditorDialog);
  2717. theme_edit_dialog->hide();
  2718. top_menu->add_child(theme_edit_dialog);
  2719. HSplitContainer *main_hs = memnew(HSplitContainer);
  2720. main_hs->set_v_size_flags(SIZE_EXPAND_FILL);
  2721. add_child(main_hs);
  2722. VBoxContainer *preview_tabs_vb = memnew(VBoxContainer);
  2723. preview_tabs_vb->set_h_size_flags(SIZE_EXPAND_FILL);
  2724. preview_tabs_vb->set_custom_minimum_size(Size2(520, 0) * EDSCALE);
  2725. preview_tabs_vb->add_constant_override("separation", 2 * EDSCALE);
  2726. main_hs->add_child(preview_tabs_vb);
  2727. HBoxContainer *preview_tabbar_hb = memnew(HBoxContainer);
  2728. preview_tabs_vb->add_child(preview_tabbar_hb);
  2729. preview_tabs_content = memnew(PanelContainer);
  2730. preview_tabs_content->set_v_size_flags(SIZE_EXPAND_FILL);
  2731. preview_tabs_content->set_draw_behind_parent(true);
  2732. preview_tabs_vb->add_child(preview_tabs_content);
  2733. preview_tabs = memnew(Tabs);
  2734. preview_tabs->set_tab_align(Tabs::ALIGN_LEFT);
  2735. preview_tabs->set_h_size_flags(SIZE_EXPAND_FILL);
  2736. preview_tabbar_hb->add_child(preview_tabs);
  2737. preview_tabs->connect("tab_changed", this, "_change_preview_tab");
  2738. preview_tabs->connect("right_button_pressed", this, "_remove_preview_tab");
  2739. HBoxContainer *add_preview_button_hb = memnew(HBoxContainer);
  2740. preview_tabbar_hb->add_child(add_preview_button_hb);
  2741. add_preview_button = memnew(Button);
  2742. add_preview_button->set_text(TTR("Add Preview"));
  2743. add_preview_button_hb->add_child(add_preview_button);
  2744. add_preview_button->connect("pressed", this, "_add_preview_button_cbk");
  2745. DefaultThemeEditorPreview *default_preview_tab = memnew(DefaultThemeEditorPreview);
  2746. preview_tabs_content->add_child(default_preview_tab);
  2747. default_preview_tab->connect("control_picked", this, "_preview_control_picked");
  2748. preview_tabs->add_tab(TTR("Default Preview"));
  2749. preview_scene_dialog = memnew(EditorFileDialog);
  2750. preview_scene_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE);
  2751. preview_scene_dialog->set_title(TTR("Select UI Scene:"));
  2752. List<String> ext;
  2753. ResourceLoader::get_recognized_extensions_for_type("PackedScene", &ext);
  2754. for (List<String>::Element *E = ext.front(); E; E = E->next()) {
  2755. preview_scene_dialog->add_filter(vformat("*.%s; %s", E->get(), TTR("Scene")));
  2756. }
  2757. main_hs->add_child(preview_scene_dialog);
  2758. preview_scene_dialog->connect("file_selected", this, "_preview_scene_dialog_cbk");
  2759. theme_type_editor = memnew(ThemeTypeEditor);
  2760. main_hs->add_child(theme_type_editor);
  2761. theme_type_editor->set_custom_minimum_size(Size2(280, 0) * EDSCALE);
  2762. }
  2763. void ThemeEditorPlugin::edit(Object *p_node) {
  2764. if (Object::cast_to<Theme>(p_node)) {
  2765. theme_editor->edit(Object::cast_to<Theme>(p_node));
  2766. } else if (Object::cast_to<Font>(p_node) || Object::cast_to<StyleBox>(p_node) || Object::cast_to<Texture>(p_node)) {
  2767. // Do nothing, keep editing the existing theme.
  2768. } else {
  2769. theme_editor->edit(Ref<Theme>());
  2770. }
  2771. }
  2772. bool ThemeEditorPlugin::handles(Object *p_node) const {
  2773. if (Object::cast_to<Theme>(p_node)) {
  2774. return true;
  2775. }
  2776. Ref<Theme> edited_theme = theme_editor->get_edited_theme();
  2777. if (edited_theme.is_null()) {
  2778. return false;
  2779. }
  2780. // If we are editing a theme already and this particular resource happens to belong to it,
  2781. // then we just keep editing it, despite not being able to directly handle it.
  2782. // This only goes one layer deep, but if required this can be extended to support, say, FontData inside of Font.
  2783. bool belongs_to_theme = false;
  2784. if (Object::cast_to<Font>(p_node)) {
  2785. Ref<Font> font_item = Object::cast_to<Font>(p_node);
  2786. List<StringName> types;
  2787. List<StringName> names;
  2788. edited_theme->get_font_types(&types);
  2789. for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
  2790. names.clear();
  2791. edited_theme->get_font_list(E->get(), &names);
  2792. for (List<StringName>::Element *F = names.front(); F; F = F->next()) {
  2793. if (font_item == edited_theme->get_font(F->get(), E->get())) {
  2794. belongs_to_theme = true;
  2795. break;
  2796. }
  2797. }
  2798. }
  2799. } else if (Object::cast_to<StyleBox>(p_node)) {
  2800. Ref<StyleBox> stylebox_item = Object::cast_to<StyleBox>(p_node);
  2801. List<StringName> types;
  2802. List<StringName> names;
  2803. edited_theme->get_stylebox_types(&types);
  2804. for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
  2805. names.clear();
  2806. edited_theme->get_stylebox_list(E->get(), &names);
  2807. for (List<StringName>::Element *F = names.front(); F; F = F->next()) {
  2808. if (stylebox_item == edited_theme->get_stylebox(F->get(), E->get())) {
  2809. belongs_to_theme = true;
  2810. break;
  2811. }
  2812. }
  2813. }
  2814. } else if (Object::cast_to<Texture>(p_node)) {
  2815. Ref<Texture> icon_item = Object::cast_to<Texture>(p_node);
  2816. List<StringName> types;
  2817. List<StringName> names;
  2818. edited_theme->get_icon_types(&types);
  2819. for (List<StringName>::Element *E = types.front(); E; E = E->next()) {
  2820. names.clear();
  2821. edited_theme->get_icon_list(E->get(), &names);
  2822. for (List<StringName>::Element *F = names.front(); F; F = F->next()) {
  2823. if (icon_item == edited_theme->get_icon(F->get(), E->get())) {
  2824. belongs_to_theme = true;
  2825. break;
  2826. }
  2827. }
  2828. }
  2829. }
  2830. return belongs_to_theme;
  2831. }
  2832. void ThemeEditorPlugin::make_visible(bool p_visible) {
  2833. if (p_visible) {
  2834. button->show();
  2835. editor->make_bottom_panel_item_visible(theme_editor);
  2836. } else {
  2837. if (theme_editor->is_visible_in_tree()) {
  2838. editor->hide_bottom_panel();
  2839. }
  2840. button->hide();
  2841. }
  2842. }
  2843. ThemeEditorPlugin::ThemeEditorPlugin(EditorNode *p_node) {
  2844. editor = p_node;
  2845. theme_editor = memnew(ThemeEditor);
  2846. theme_editor->set_custom_minimum_size(Size2(0, 200) * EDSCALE);
  2847. button = editor->add_bottom_panel_item(TTR("Theme"), theme_editor);
  2848. button->hide();
  2849. }