1 /*************************************************************************/
2 /* settings_config_dialog.cpp */
3 /*************************************************************************/
4 /* This file is part of: */
5 /* GODOT ENGINE */
6 /* https://godotengine.org */
7 /*************************************************************************/
8 /* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
9 /* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
10 /* */
11 /* Permission is hereby granted, free of charge, to any person obtaining */
12 /* a copy of this software and associated documentation files (the */
13 /* "Software"), to deal in the Software without restriction, including */
14 /* without limitation the rights to use, copy, modify, merge, publish, */
15 /* distribute, sublicense, and/or sell copies of the Software, and to */
16 /* permit persons to whom the Software is furnished to do so, subject to */
17 /* the following conditions: */
18 /* */
19 /* The above copyright notice and this permission notice shall be */
20 /* included in all copies or substantial portions of the Software. */
21 /* */
22 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25 /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26 /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29 /*************************************************************************/
30 #include "settings_config_dialog.h"
31 #include "editor_file_system.h"
32 #include "editor_node.h"
33 #include "editor_settings.h"
34 #include "globals.h"
35 #include "os/keyboard.h"
36 #include "scene/gui/margin_container.h"
37
ok_pressed()38 void EditorSettingsDialog::ok_pressed() {
39
40 if (!EditorSettings::get_singleton())
41 return;
42
43 _settings_save();
44 timer->stop();
45 }
46
_settings_changed()47 void EditorSettingsDialog::_settings_changed() {
48
49 timer->start();
50 }
51
_settings_property_edited(const String & p_name)52 void EditorSettingsDialog::_settings_property_edited(const String &p_name) {
53
54 String full_name = property_editor->get_full_item_path(p_name);
55
56 // Small usability workaround to update the text color settings when the
57 // color theme is changed
58 if (full_name == "text_editor/color_theme") {
59 property_editor->get_property_editor()->update_tree();
60 }
61 }
62
_settings_save()63 void EditorSettingsDialog::_settings_save() {
64
65 EditorSettings::get_singleton()->notify_changes();
66 EditorSettings::get_singleton()->save();
67 }
68
cancel_pressed()69 void EditorSettingsDialog::cancel_pressed() {
70
71 if (!EditorSettings::get_singleton())
72 return;
73
74 EditorSettings::get_singleton()->notify_changes();
75 }
76
popup_edit_settings()77 void EditorSettingsDialog::popup_edit_settings() {
78
79 if (!EditorSettings::get_singleton())
80 return;
81
82 EditorSettings::get_singleton()->list_text_editor_themes(); // make sure we have an up to date list of themes
83
84 property_editor->edit(EditorSettings::get_singleton());
85 property_editor->get_property_editor()->update_tree();
86
87 search_box->select_all();
88 search_box->grab_focus();
89
90 _update_shortcuts();
91 popup_centered_ratio(0.7);
92 }
93
_clear_search_box()94 void EditorSettingsDialog::_clear_search_box() {
95
96 if (search_box->get_text() == "")
97 return;
98
99 search_box->clear();
100 property_editor->get_property_editor()->update_tree();
101 }
102
_clear_shortcut_search_box()103 void EditorSettingsDialog::_clear_shortcut_search_box() {
104 if (shortcut_search_box->get_text() == "")
105 return;
106
107 shortcut_search_box->clear();
108 }
109
_filter_shortcuts(const String & p_filter)110 void EditorSettingsDialog::_filter_shortcuts(const String &p_filter) {
111 shortcut_filter = p_filter;
112 _update_shortcuts();
113 }
114
_notification(int p_what)115 void EditorSettingsDialog::_notification(int p_what) {
116
117 if (p_what == NOTIFICATION_ENTER_TREE) {
118
119 clear_button->set_icon(get_icon("Close", "EditorIcons"));
120 shortcut_clear_button->set_icon(get_icon("Close", "EditorIcons"));
121 }
122 }
123
_update_shortcuts()124 void EditorSettingsDialog::_update_shortcuts() {
125
126 shortcuts->clear();
127
128 List<String> slist;
129 EditorSettings::get_singleton()->get_shortcut_list(&slist);
130 TreeItem *root = shortcuts->create_item();
131
132 Map<String, TreeItem *> sections;
133
134 for (List<String>::Element *E = slist.front(); E; E = E->next()) {
135
136 Ref<ShortCut> sc = EditorSettings::get_singleton()->get_shortcut(E->get());
137 if (!sc->has_meta("original"))
138 continue;
139
140 InputEvent original = sc->get_meta("original");
141
142 String section_name = E->get().get_slice("/", 0);
143
144 TreeItem *section;
145
146 if (sections.has(section_name)) {
147 section = sections[section_name];
148 } else {
149 section = shortcuts->create_item(root);
150 section->set_text(0, section_name.capitalize());
151
152 sections[section_name] = section;
153 section->set_custom_bg_color(0, get_color("prop_subsection", "Editor"));
154 section->set_custom_bg_color(1, get_color("prop_subsection", "Editor"));
155 }
156
157 if (shortcut_filter.is_subsequence_ofi(sc->get_name())) {
158 TreeItem *item = shortcuts->create_item(section);
159
160 item->set_text(0, sc->get_name());
161 item->set_text(1, sc->get_as_text());
162 if (!sc->is_shortcut(original) && !(sc->get_shortcut().type == InputEvent::NONE && original.type == InputEvent::NONE)) {
163 item->add_button(1, get_icon("Reload", "EditorIcons"), 2);
164 }
165 item->add_button(1, get_icon("Edit", "EditorIcons"), 0);
166 item->add_button(1, get_icon("Close", "EditorIcons"), 1);
167 item->set_tooltip(0, E->get());
168 item->set_metadata(0, E->get());
169 }
170 }
171
172 // remove sections with no shortcuts
173 for (Map<String, TreeItem *>::Element *E = sections.front(); E; E = E->next()) {
174 TreeItem *section = E->get();
175 if (section->get_children() == NULL) {
176 root->remove_child(section);
177 }
178 }
179 }
180
_shortcut_button_pressed(Object * p_item,int p_column,int p_idx)181 void EditorSettingsDialog::_shortcut_button_pressed(Object *p_item, int p_column, int p_idx) {
182
183 TreeItem *ti = p_item->cast_to<TreeItem>();
184 ERR_FAIL_COND(!ti);
185
186 String item = ti->get_metadata(0);
187 Ref<ShortCut> sc = EditorSettings::get_singleton()->get_shortcut(item);
188
189 if (p_idx == 0) {
190 press_a_key_label->set_text(TTR("Press a Key.."));
191 last_wait_for_key = InputEvent();
192 press_a_key->popup_centered(Size2(250, 80) * EDSCALE);
193 press_a_key->grab_focus();
194 press_a_key->get_ok()->set_focus_mode(FOCUS_NONE);
195 press_a_key->get_cancel()->set_focus_mode(FOCUS_NONE);
196 shortcut_configured = item;
197
198 } else if (p_idx == 1) { //erase
199 if (!sc.is_valid())
200 return; //pointless, there is nothing
201
202 UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
203 ur->create_action("Erase Shortcut");
204 ur->add_do_method(sc.ptr(), "set_shortcut", InputEvent());
205 ur->add_undo_method(sc.ptr(), "set_shortcut", sc->get_shortcut());
206 ur->add_do_method(this, "_update_shortcuts");
207 ur->add_undo_method(this, "_update_shortcuts");
208 ur->add_do_method(this, "_settings_changed");
209 ur->add_undo_method(this, "_settings_changed");
210 ur->commit_action();
211 } else if (p_idx == 2) { //revert to original
212 if (!sc.is_valid())
213 return; //pointless, there is nothing
214
215 InputEvent original = sc->get_meta("original");
216
217 UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
218 ur->create_action("Restore Shortcut");
219 ur->add_do_method(sc.ptr(), "set_shortcut", original);
220 ur->add_undo_method(sc.ptr(), "set_shortcut", sc->get_shortcut());
221 ur->add_do_method(this, "_update_shortcuts");
222 ur->add_undo_method(this, "_update_shortcuts");
223 ur->add_do_method(this, "_settings_changed");
224 ur->add_undo_method(this, "_settings_changed");
225 ur->commit_action();
226 }
227 }
228
_wait_for_key(const InputEvent & p_event)229 void EditorSettingsDialog::_wait_for_key(const InputEvent &p_event) {
230
231 if (p_event.type == InputEvent::KEY && p_event.key.pressed && p_event.key.scancode != 0) {
232
233 last_wait_for_key = p_event;
234 String str = keycode_get_string(p_event.key.scancode).capitalize();
235 if (p_event.key.mod.meta)
236 str = TTR("Meta+") + str;
237 if (p_event.key.mod.shift)
238 str = TTR("Shift+") + str;
239 if (p_event.key.mod.alt)
240 str = TTR("Alt+") + str;
241 if (p_event.key.mod.control)
242 str = TTR("Control+") + str;
243
244 press_a_key_label->set_text(str);
245 press_a_key->accept_event();
246 }
247 }
248
_press_a_key_confirm()249 void EditorSettingsDialog::_press_a_key_confirm() {
250
251 if (last_wait_for_key.type != InputEvent::KEY)
252 return;
253
254 InputEvent ie;
255 ie.type = InputEvent::KEY;
256 ie.key.scancode = last_wait_for_key.key.scancode;
257 ie.key.mod = last_wait_for_key.key.mod;
258
259 Ref<ShortCut> sc = EditorSettings::get_singleton()->get_shortcut(shortcut_configured);
260
261 UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo();
262 ur->create_action("Change Shortcut '" + shortcut_configured + "'");
263 ur->add_do_method(sc.ptr(), "set_shortcut", ie);
264 ur->add_undo_method(sc.ptr(), "set_shortcut", sc->get_shortcut());
265 ur->add_do_method(this, "_update_shortcuts");
266 ur->add_undo_method(this, "_update_shortcuts");
267 ur->add_do_method(this, "_settings_changed");
268 ur->add_undo_method(this, "_settings_changed");
269 ur->commit_action();
270 }
271
_bind_methods()272 void EditorSettingsDialog::_bind_methods() {
273
274 ObjectTypeDB::bind_method(_MD("_settings_save"), &EditorSettingsDialog::_settings_save);
275 ObjectTypeDB::bind_method(_MD("_settings_changed"), &EditorSettingsDialog::_settings_changed);
276 ObjectTypeDB::bind_method(_MD("_settings_property_edited"), &EditorSettingsDialog::_settings_property_edited);
277 ObjectTypeDB::bind_method(_MD("_clear_search_box"), &EditorSettingsDialog::_clear_search_box);
278 ObjectTypeDB::bind_method(_MD("_clear_shortcut_search_box"), &EditorSettingsDialog::_clear_shortcut_search_box);
279 ObjectTypeDB::bind_method(_MD("_shortcut_button_pressed"), &EditorSettingsDialog::_shortcut_button_pressed);
280 ObjectTypeDB::bind_method(_MD("_filter_shortcuts"), &EditorSettingsDialog::_filter_shortcuts);
281 ObjectTypeDB::bind_method(_MD("_update_shortcuts"), &EditorSettingsDialog::_update_shortcuts);
282 ObjectTypeDB::bind_method(_MD("_press_a_key_confirm"), &EditorSettingsDialog::_press_a_key_confirm);
283 ObjectTypeDB::bind_method(_MD("_wait_for_key"), &EditorSettingsDialog::_wait_for_key);
284 }
285
EditorSettingsDialog()286 EditorSettingsDialog::EditorSettingsDialog() {
287
288 set_title(TTR("Editor Settings"));
289
290 tabs = memnew(TabContainer);
291 add_child(tabs);
292 set_child_rect(tabs);
293
294 VBoxContainer *vbc = memnew(VBoxContainer);
295 tabs->add_child(vbc);
296 vbc->set_name(TTR("General"));
297
298 HBoxContainer *hbc = memnew(HBoxContainer);
299 hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
300 vbc->add_child(hbc);
301
302 Label *l = memnew(Label);
303 l->set_text(TTR("Search:") + " ");
304 hbc->add_child(l);
305
306 search_box = memnew(LineEdit);
307 search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
308 hbc->add_child(search_box);
309
310 clear_button = memnew(ToolButton);
311 hbc->add_child(clear_button);
312 clear_button->connect("pressed", this, "_clear_search_box");
313
314 property_editor = memnew(SectionedPropertyEditor);
315 //property_editor->hide_top_label();
316 property_editor->get_property_editor()->set_use_filter(true);
317 property_editor->get_property_editor()->register_text_enter(search_box);
318 property_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL);
319 vbc->add_child(property_editor);
320 property_editor->get_property_editor()->connect("property_edited", this, "_settings_property_edited");
321
322 vbc = memnew(VBoxContainer);
323 tabs->add_child(vbc);
324 vbc->set_name(TTR("Shortcuts"));
325
326 hbc = memnew(HBoxContainer);
327 hbc->set_h_size_flags(Control::SIZE_EXPAND_FILL);
328 vbc->add_child(hbc);
329
330 l = memnew(Label);
331 l->set_text(TTR("Search:") + " ");
332 hbc->add_child(l);
333
334 shortcut_search_box = memnew(LineEdit);
335 shortcut_search_box->set_h_size_flags(Control::SIZE_EXPAND_FILL);
336 hbc->add_child(shortcut_search_box);
337 shortcut_search_box->connect("text_changed", this, "_filter_shortcuts");
338
339 shortcut_clear_button = memnew(ToolButton);
340 hbc->add_child(shortcut_clear_button);
341 shortcut_clear_button->connect("pressed", this, "_clear_shortcut_search_box");
342
343 shortcuts = memnew(Tree);
344 vbc->add_margin_child("Shortcut List:", shortcuts, true);
345 shortcuts->set_columns(2);
346 shortcuts->set_hide_root(true);
347 //shortcuts->set_hide_folding(true);
348 shortcuts->set_column_titles_visible(true);
349 shortcuts->set_column_title(0, "Name");
350 shortcuts->set_column_title(1, "Binding");
351 shortcuts->connect("button_pressed", this, "_shortcut_button_pressed");
352
353 press_a_key = memnew(ConfirmationDialog);
354 press_a_key->set_focus_mode(FOCUS_ALL);
355 add_child(press_a_key);
356
357 l = memnew(Label);
358 l->set_text(TTR("Press a Key.."));
359 l->set_area_as_parent_rect();
360 l->set_align(Label::ALIGN_CENTER);
361 l->set_margin(MARGIN_TOP, 20);
362 l->set_anchor_and_margin(MARGIN_BOTTOM, ANCHOR_BEGIN, 30);
363 press_a_key_label = l;
364 press_a_key->add_child(l);
365 press_a_key->connect("input_event", this, "_wait_for_key");
366 press_a_key->connect("confirmed", this, "_press_a_key_confirm");
367
368 //get_ok()->set_text("Apply");
369 set_hide_on_ok(true);
370 //get_cancel()->set_text("Close");
371
372 timer = memnew(Timer);
373 timer->set_wait_time(1.5);
374 timer->connect("timeout", this, "_settings_save");
375 timer->set_one_shot(true);
376 add_child(timer);
377 EditorSettings::get_singleton()->connect("settings_changed", this, "_settings_changed");
378 get_ok()->set_text(TTR("Close"));
379
380 updating = false;
381 }
382