create_dialog.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678
  1. /*************************************************************************/
  2. /* create_dialog.cpp */
  3. /*************************************************************************/
  4. /* This file is part of: */
  5. /* GODOT ENGINE */
  6. /* https://godotengine.org */
  7. /*************************************************************************/
  8. /* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
  9. /* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */
  10. /* */
  11. /* Permission is hereby granted, free of charge, to any person obtaining */
  12. /* a copy of this software and associated documentation files (the */
  13. /* "Software"), to deal in the Software without restriction, including */
  14. /* without limitation the rights to use, copy, modify, merge, publish, */
  15. /* distribute, sublicense, and/or sell copies of the Software, and to */
  16. /* permit persons to whom the Software is furnished to do so, subject to */
  17. /* the following conditions: */
  18. /* */
  19. /* The above copyright notice and this permission notice shall be */
  20. /* included in all copies or substantial portions of the Software. */
  21. /* */
  22. /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
  23. /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
  24. /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
  25. /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
  26. /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
  27. /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
  28. /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
  29. /*************************************************************************/
  30. #include "create_dialog.h"
  31. #include "class_db.h"
  32. #include "editor_help.h"
  33. #include "editor_node.h"
  34. #include "editor_settings.h"
  35. #include "os/keyboard.h"
  36. #include "print_string.h"
  37. #include "scene/gui/box_container.h"
  38. void CreateDialog::popup_create(bool p_dontclear) {
  39. recent->clear();
  40. FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("create_recent." + base_type), FileAccess::READ);
  41. if (f) {
  42. TreeItem *root = recent->create_item();
  43. while (!f->eof_reached()) {
  44. String l = f->get_line().strip_edges();
  45. if (l != String()) {
  46. TreeItem *ti = recent->create_item(root);
  47. ti->set_text(0, l);
  48. ti->set_icon(0, _get_editor_icon(l));
  49. }
  50. }
  51. memdelete(f);
  52. }
  53. favorites->clear();
  54. f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("favorites." + base_type), FileAccess::READ);
  55. favorite_list.clear();
  56. if (f) {
  57. while (!f->eof_reached()) {
  58. String l = f->get_line().strip_edges();
  59. if (l != String()) {
  60. favorite_list.push_back(l);
  61. }
  62. }
  63. memdelete(f);
  64. }
  65. _update_favorite_list();
  66. // Restore valid window bounds or pop up at default size.
  67. if (EditorSettings::get_singleton()->has_setting("interface/dialogs/create_new_node_bounds")) {
  68. popup(EditorSettings::get_singleton()->get("interface/dialogs/create_new_node_bounds"));
  69. } else {
  70. popup_centered_ratio();
  71. }
  72. if (p_dontclear)
  73. search_box->select_all();
  74. else {
  75. search_box->clear();
  76. }
  77. search_box->grab_focus();
  78. _update_search();
  79. }
  80. void CreateDialog::_text_changed(const String &p_newtext) {
  81. _update_search();
  82. }
  83. void CreateDialog::_sbox_input(const Ref<InputEvent> &p_ie) {
  84. Ref<InputEventKey> k = p_ie;
  85. if (k.is_valid() && (k->get_scancode() == KEY_UP ||
  86. k->get_scancode() == KEY_DOWN ||
  87. k->get_scancode() == KEY_PAGEUP ||
  88. k->get_scancode() == KEY_PAGEDOWN)) {
  89. search_options->call("_gui_input", k);
  90. search_box->accept_event();
  91. }
  92. }
  93. Ref<Texture> CreateDialog::_get_editor_icon(const String &p_type) const {
  94. if (has_icon(p_type, "EditorIcons")) {
  95. return get_icon(p_type, "EditorIcons");
  96. }
  97. const Map<String, Vector<EditorData::CustomType> > &p_map = EditorNode::get_editor_data().get_custom_types();
  98. for (const Map<String, Vector<EditorData::CustomType> >::Element *E = p_map.front(); E; E = E->next()) {
  99. const Vector<EditorData::CustomType> &ct = E->value();
  100. for (int i = 0; i < ct.size(); ++i) {
  101. if (ct[i].name == p_type) {
  102. if (ct[i].icon.is_valid()) {
  103. return ct[i].icon;
  104. } else {
  105. return get_icon("Object", "EditorIcons");
  106. }
  107. }
  108. }
  109. }
  110. return get_icon("Object", "EditorIcons");
  111. }
  112. void CreateDialog::add_type(const String &p_type, HashMap<String, TreeItem *> &p_types, TreeItem *p_root, TreeItem **to_select) {
  113. if (p_types.has(p_type))
  114. return;
  115. if (!ClassDB::is_parent_class(p_type, base_type) || p_type == base_type)
  116. return;
  117. String inherits = ClassDB::get_parent_class(p_type);
  118. TreeItem *parent = p_root;
  119. if (inherits.length()) {
  120. if (!p_types.has(inherits)) {
  121. add_type(inherits, p_types, p_root, to_select);
  122. }
  123. if (p_types.has(inherits))
  124. parent = p_types[inherits];
  125. }
  126. TreeItem *item = search_options->create_item(parent);
  127. item->set_text(0, p_type);
  128. if (!ClassDB::can_instance(p_type)) {
  129. item->set_custom_color(0, get_color("disabled_font_color", "Editor"));
  130. item->set_selectable(0, false);
  131. } else {
  132. bool is_search_subsequence = search_box->get_text().is_subsequence_ofi(p_type);
  133. String to_select_type = *to_select ? (*to_select)->get_text(0) : "";
  134. bool current_item_is_preffered = ClassDB::is_parent_class(p_type, preferred_search_result_type) && !ClassDB::is_parent_class(to_select_type, preferred_search_result_type);
  135. if (*to_select && p_type.length() < (*to_select)->get_text(0).length()) {
  136. current_item_is_preffered = true;
  137. }
  138. if (((!*to_select || current_item_is_preffered) && is_search_subsequence) || search_box->get_text() == p_type) {
  139. *to_select = item;
  140. }
  141. }
  142. if (bool(EditorSettings::get_singleton()->get("docks/scene_tree/start_create_dialog_fully_expanded"))) {
  143. item->set_collapsed(false);
  144. } else {
  145. // don't collapse search results
  146. bool collapse = (search_box->get_text() == "");
  147. // don't collapse the root node
  148. collapse &= (item != p_root);
  149. // don't collapse abstract nodes on the first tree level
  150. collapse &= ((parent != p_root) || (ClassDB::can_instance(p_type)));
  151. item->set_collapsed(collapse);
  152. }
  153. const String &description = EditorHelp::get_doc_data()->class_list[p_type].brief_description;
  154. item->set_tooltip(0, description);
  155. if (has_icon(p_type, "EditorIcons")) {
  156. item->set_icon(0, get_icon(p_type, "EditorIcons"));
  157. }
  158. p_types[p_type] = item;
  159. }
  160. void CreateDialog::_update_search() {
  161. search_options->clear();
  162. favorite->set_disabled(true);
  163. help_bit->set_text("");
  164. /*
  165. TreeItem *root = search_options->create_item();
  166. _parse_fs(EditorFileSystem::get_singleton()->get_filesystem());
  167. */
  168. HashMap<String, TreeItem *> types;
  169. TreeItem *root = search_options->create_item();
  170. root->set_text(0, base_type);
  171. if (has_icon(base_type, "EditorIcons")) {
  172. root->set_icon(0, get_icon(base_type, "EditorIcons"));
  173. }
  174. List<StringName>::Element *I = type_list.front();
  175. TreeItem *to_select = search_box->get_text() == base_type ? root : NULL;
  176. for (; I; I = I->next()) {
  177. String type = I->get();
  178. if (base_type == "Node" && type.begins_with("Editor"))
  179. continue; // do not show editor nodes
  180. if (!ClassDB::can_instance(type))
  181. continue; // can't create what can't be instanced
  182. if (search_box->get_text() == "") {
  183. add_type(type, types, root, &to_select);
  184. } else {
  185. bool found = false;
  186. String type = I->get();
  187. while (type != "" && ClassDB::is_parent_class(type, base_type) && type != base_type) {
  188. if (search_box->get_text().is_subsequence_ofi(type)) {
  189. found = true;
  190. break;
  191. }
  192. type = ClassDB::get_parent_class(type);
  193. }
  194. if (found)
  195. add_type(I->get(), types, root, &to_select);
  196. }
  197. if (EditorNode::get_editor_data().get_custom_types().has(type) && ClassDB::is_parent_class(type, base_type)) {
  198. //there are custom types based on this... cool.
  199. //print_line("there are custom types");
  200. const Vector<EditorData::CustomType> &ct = EditorNode::get_editor_data().get_custom_types()[type];
  201. for (int i = 0; i < ct.size(); i++) {
  202. bool show = search_box->get_text().is_subsequence_ofi(ct[i].name);
  203. if (!show)
  204. continue;
  205. if (!types.has(type))
  206. add_type(type, types, root, &to_select);
  207. TreeItem *ti;
  208. if (types.has(type))
  209. ti = types[type];
  210. else
  211. ti = search_options->get_root();
  212. TreeItem *item = search_options->create_item(ti);
  213. item->set_metadata(0, type);
  214. item->set_text(0, ct[i].name);
  215. if (ct[i].icon.is_valid()) {
  216. item->set_icon(0, ct[i].icon);
  217. }
  218. if (!to_select || ct[i].name == search_box->get_text()) {
  219. to_select = item;
  220. }
  221. }
  222. }
  223. }
  224. if (to_select) {
  225. to_select->select(0);
  226. search_options->scroll_to_item(to_select);
  227. favorite->set_disabled(false);
  228. favorite->set_pressed(favorite_list.find(to_select->get_text(0)) != -1);
  229. }
  230. get_ok()->set_disabled(root->get_children() == NULL);
  231. }
  232. void CreateDialog::_confirmed() {
  233. TreeItem *ti = search_options->get_selected();
  234. if (!ti)
  235. return;
  236. FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("create_recent." + base_type), FileAccess::WRITE);
  237. if (f) {
  238. f->store_line(get_selected_type());
  239. TreeItem *t = recent->get_root();
  240. if (t)
  241. t = t->get_children();
  242. int count = 0;
  243. while (t) {
  244. if (t->get_text(0) != get_selected_type()) {
  245. f->store_line(t->get_text(0));
  246. }
  247. if (count > 32) {
  248. //limit it to 32 entries..
  249. break;
  250. }
  251. t = t->get_next();
  252. count++;
  253. }
  254. memdelete(f);
  255. }
  256. emit_signal("create");
  257. hide();
  258. }
  259. void CreateDialog::_notification(int p_what) {
  260. switch (p_what) {
  261. case NOTIFICATION_ENTER_TREE: {
  262. connect("confirmed", this, "_confirmed");
  263. favorite->set_icon(get_icon("Favorites", "EditorIcons"));
  264. } break;
  265. case NOTIFICATION_EXIT_TREE: {
  266. disconnect("confirmed", this, "_confirmed");
  267. } break;
  268. case NOTIFICATION_VISIBILITY_CHANGED: {
  269. if (is_visible_in_tree()) {
  270. search_box->call_deferred("grab_focus"); // still not visible
  271. search_box->select_all();
  272. }
  273. } break;
  274. case NOTIFICATION_POPUP_HIDE: {
  275. EditorSettings::get_singleton()->set("interface/dialogs/create_new_node_bounds", get_rect());
  276. } break;
  277. }
  278. }
  279. void CreateDialog::set_base_type(const String &p_base) {
  280. base_type = p_base;
  281. set_title(TTR("Create New") + " " + p_base);
  282. _update_search();
  283. }
  284. String CreateDialog::get_base_type() const {
  285. return base_type;
  286. }
  287. void CreateDialog::set_preferred_search_result_type(const String &p_preferred_type) {
  288. preferred_search_result_type = p_preferred_type;
  289. }
  290. String CreateDialog::get_preferred_search_result_type() {
  291. return preferred_search_result_type;
  292. }
  293. String CreateDialog::get_selected_type() {
  294. TreeItem *selected = search_options->get_selected();
  295. if (selected)
  296. return selected->get_text(0);
  297. else
  298. return String();
  299. }
  300. Object *CreateDialog::instance_selected() {
  301. TreeItem *selected = search_options->get_selected();
  302. if (selected) {
  303. Variant md = selected->get_metadata(0);
  304. String custom;
  305. if (md.get_type() != Variant::NIL)
  306. custom = md;
  307. if (custom != String()) {
  308. if (EditorNode::get_editor_data().get_custom_types().has(custom)) {
  309. for (int i = 0; i < EditorNode::get_editor_data().get_custom_types()[custom].size(); i++) {
  310. if (EditorNode::get_editor_data().get_custom_types()[custom][i].name == selected->get_text(0)) {
  311. Ref<Texture> icon = EditorNode::get_editor_data().get_custom_types()[custom][i].icon;
  312. Ref<Script> script = EditorNode::get_editor_data().get_custom_types()[custom][i].script;
  313. String name = selected->get_text(0);
  314. Object *ob = ClassDB::instance(custom);
  315. ERR_FAIL_COND_V(!ob, NULL);
  316. if (ob->is_class("Node")) {
  317. ob->call("set_name", name);
  318. }
  319. ob->set_script(script.get_ref_ptr());
  320. if (icon.is_valid())
  321. ob->set_meta("_editor_icon", icon);
  322. return ob;
  323. }
  324. }
  325. }
  326. } else {
  327. return ClassDB::instance(selected->get_text(0));
  328. }
  329. }
  330. return NULL;
  331. }
  332. void CreateDialog::_item_selected() {
  333. TreeItem *item = search_options->get_selected();
  334. if (!item)
  335. return;
  336. String name = item->get_text(0);
  337. favorite->set_disabled(false);
  338. favorite->set_pressed(favorite_list.find(name) != -1);
  339. if (!EditorHelp::get_doc_data()->class_list.has(name))
  340. return;
  341. help_bit->set_text(EditorHelp::get_doc_data()->class_list[name].brief_description);
  342. }
  343. void CreateDialog::_favorite_toggled() {
  344. TreeItem *item = search_options->get_selected();
  345. if (!item)
  346. return;
  347. String name = item->get_text(0);
  348. if (favorite_list.find(name) == -1) {
  349. favorite_list.push_back(name);
  350. favorite->set_pressed(true);
  351. } else {
  352. favorite_list.erase(name);
  353. favorite->set_pressed(false);
  354. }
  355. _save_favorite_list();
  356. _update_favorite_list();
  357. }
  358. void CreateDialog::_save_favorite_list() {
  359. FileAccess *f = FileAccess::open(EditorSettings::get_singleton()->get_project_settings_path().plus_file("favorites." + base_type), FileAccess::WRITE);
  360. if (f) {
  361. for (int i = 0; i < favorite_list.size(); i++) {
  362. f->store_line(favorite_list[i]);
  363. }
  364. memdelete(f);
  365. }
  366. }
  367. void CreateDialog::_update_favorite_list() {
  368. favorites->clear();
  369. TreeItem *root = favorites->create_item();
  370. for (int i = 0; i < favorite_list.size(); i++) {
  371. TreeItem *ti = favorites->create_item(root);
  372. String l = favorite_list[i];
  373. ti->set_text(0, l);
  374. ti->set_icon(0, _get_editor_icon(l));
  375. }
  376. }
  377. void CreateDialog::_history_selected() {
  378. TreeItem *item = recent->get_selected();
  379. if (!item)
  380. return;
  381. search_box->set_text(item->get_text(0));
  382. _update_search();
  383. }
  384. void CreateDialog::_favorite_selected() {
  385. TreeItem *item = favorites->get_selected();
  386. if (!item)
  387. return;
  388. search_box->set_text(item->get_text(0));
  389. _update_search();
  390. }
  391. void CreateDialog::_history_activated() {
  392. _history_selected();
  393. _confirmed();
  394. }
  395. void CreateDialog::_favorite_activated() {
  396. _favorite_selected();
  397. _confirmed();
  398. }
  399. Variant CreateDialog::get_drag_data_fw(const Point2 &p_point, Control *p_from) {
  400. TreeItem *ti = favorites->get_item_at_position(p_point);
  401. if (ti) {
  402. Dictionary d;
  403. d["type"] = "create_favorite_drag";
  404. d["class"] = ti->get_text(0);
  405. ToolButton *tb = memnew(ToolButton);
  406. tb->set_icon(ti->get_icon(0));
  407. tb->set_text(ti->get_text(0));
  408. set_drag_preview(tb);
  409. return d;
  410. }
  411. return Variant();
  412. }
  413. bool CreateDialog::can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
  414. Dictionary d = p_data;
  415. if (d.has("type") && String(d["type"]) == "create_favorite_drag") {
  416. favorites->set_drop_mode_flags(Tree::DROP_MODE_INBETWEEN);
  417. return true;
  418. }
  419. return false;
  420. }
  421. void CreateDialog::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) {
  422. Dictionary d = p_data;
  423. TreeItem *ti = favorites->get_item_at_position(p_point);
  424. if (!ti)
  425. return;
  426. String drop_at = ti->get_text(0);
  427. int ds = favorites->get_drop_section_at_position(p_point);
  428. int drop_idx = favorite_list.find(drop_at);
  429. if (drop_idx < 0)
  430. return;
  431. String type = d["class"];
  432. int from_idx = favorite_list.find(type);
  433. if (from_idx < 0)
  434. return;
  435. if (drop_idx == from_idx) {
  436. ds = -1; //cause it will be gone
  437. } else if (drop_idx > from_idx) {
  438. drop_idx--;
  439. }
  440. favorite_list.remove(from_idx);
  441. if (ds < 0) {
  442. favorite_list.insert(drop_idx, type);
  443. } else {
  444. if (drop_idx >= favorite_list.size() - 1) {
  445. favorite_list.push_back(type);
  446. } else {
  447. favorite_list.insert(drop_idx + 1, type);
  448. }
  449. }
  450. _save_favorite_list();
  451. _update_favorite_list();
  452. }
  453. void CreateDialog::_bind_methods() {
  454. ClassDB::bind_method(D_METHOD("_text_changed"), &CreateDialog::_text_changed);
  455. ClassDB::bind_method(D_METHOD("_confirmed"), &CreateDialog::_confirmed);
  456. ClassDB::bind_method(D_METHOD("_sbox_input"), &CreateDialog::_sbox_input);
  457. ClassDB::bind_method(D_METHOD("_item_selected"), &CreateDialog::_item_selected);
  458. ClassDB::bind_method(D_METHOD("_favorite_toggled"), &CreateDialog::_favorite_toggled);
  459. ClassDB::bind_method(D_METHOD("_history_selected"), &CreateDialog::_history_selected);
  460. ClassDB::bind_method(D_METHOD("_favorite_selected"), &CreateDialog::_favorite_selected);
  461. ClassDB::bind_method(D_METHOD("_history_activated"), &CreateDialog::_history_activated);
  462. ClassDB::bind_method(D_METHOD("_favorite_activated"), &CreateDialog::_favorite_activated);
  463. ClassDB::bind_method("get_drag_data_fw", &CreateDialog::get_drag_data_fw);
  464. ClassDB::bind_method("can_drop_data_fw", &CreateDialog::can_drop_data_fw);
  465. ClassDB::bind_method("drop_data_fw", &CreateDialog::drop_data_fw);
  466. ADD_SIGNAL(MethodInfo("create"));
  467. }
  468. CreateDialog::CreateDialog() {
  469. ClassDB::get_class_list(&type_list);
  470. type_list.sort_custom<StringName::AlphCompare>();
  471. set_resizable(true);
  472. HSplitContainer *hbc = memnew(HSplitContainer);
  473. add_child(hbc);
  474. VBoxContainer *lvbc = memnew(VBoxContainer);
  475. hbc->add_child(lvbc);
  476. lvbc->set_custom_minimum_size(Size2(150, 0) * EDSCALE);
  477. favorites = memnew(Tree);
  478. lvbc->add_margin_child(TTR("Favorites:"), favorites, true);
  479. favorites->set_hide_root(true);
  480. favorites->set_hide_folding(true);
  481. favorites->connect("cell_selected", this, "_favorite_selected");
  482. favorites->connect("item_activated", this, "_favorite_activated");
  483. favorites->set_drag_forwarding(this);
  484. recent = memnew(Tree);
  485. lvbc->add_margin_child(TTR("Recent:"), recent, true);
  486. recent->set_hide_root(true);
  487. recent->set_hide_folding(true);
  488. recent->connect("cell_selected", this, "_history_selected");
  489. recent->connect("item_activated", this, "_history_activated");
  490. VBoxContainer *vbc = memnew(VBoxContainer);
  491. hbc->add_child(vbc);
  492. vbc->set_h_size_flags(SIZE_EXPAND_FILL);
  493. HBoxContainer *search_hb = memnew(HBoxContainer);
  494. search_box = memnew(LineEdit);
  495. search_box->set_h_size_flags(SIZE_EXPAND_FILL);
  496. search_hb->add_child(search_box);
  497. favorite = memnew(Button);
  498. favorite->set_flat(true);
  499. favorite->set_toggle_mode(true);
  500. search_hb->add_child(favorite);
  501. favorite->connect("pressed", this, "_favorite_toggled");
  502. vbc->add_margin_child(TTR("Search:"), search_hb);
  503. search_box->connect("text_changed", this, "_text_changed");
  504. search_box->connect("gui_input", this, "_sbox_input");
  505. search_options = memnew(Tree);
  506. vbc->add_margin_child(TTR("Matches:"), search_options, true);
  507. get_ok()->set_text(TTR("Create"));
  508. get_ok()->set_disabled(true);
  509. register_text_enter(search_box);
  510. set_hide_on_ok(false);
  511. search_options->connect("item_activated", this, "_confirmed");
  512. search_options->connect("cell_selected", this, "_item_selected");
  513. //search_options->set_hide_root(true);
  514. base_type = "Object";
  515. preferred_search_result_type = "";
  516. help_bit = memnew(EditorHelpBit);
  517. vbc->add_margin_child(TTR("Description:"), help_bit);
  518. help_bit->connect("request_hide", this, "_closed");
  519. }