diff options
-rw-r--r-- | editor/code_editor.cpp | 339 | ||||
-rw-r--r-- | editor/code_editor.h | 23 | ||||
-rw-r--r-- | editor/editor_node.cpp | 2 | ||||
-rw-r--r-- | editor/inspector_dock.cpp | 1 | ||||
-rw-r--r-- | editor/plugins/script_editor_plugin.cpp | 371 | ||||
-rw-r--r-- | editor/plugins/script_editor_plugin.h | 20 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.cpp | 419 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.h | 12 | ||||
-rw-r--r-- | editor/plugins/shader_editor_plugin.cpp | 127 | ||||
-rw-r--r-- | editor/plugins/text_editor.cpp | 607 | ||||
-rw-r--r-- | editor/plugins/text_editor.h | 146 | ||||
-rw-r--r-- | modules/visual_script/visual_script_editor.cpp | 25 | ||||
-rw-r--r-- | modules/visual_script/visual_script_editor.h | 4 | ||||
-rw-r--r-- | scene/register_scene_types.cpp | 3 | ||||
-rw-r--r-- | scene/resources/text_file.cpp | 77 | ||||
-rw-r--r-- | scene/resources/text_file.h | 55 |
16 files changed, 1628 insertions, 603 deletions
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 6aec6135f1..925f97de8e 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -784,6 +784,345 @@ void CodeTextEditor::update_editor_settings() { text_editor->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/open_scripts/v_scroll_speed")); } +void CodeTextEditor::trim_trailing_whitespace() { + bool trimed_whitespace = false; + for (int i = 0; i < text_editor->get_line_count(); i++) { + String line = text_editor->get_line(i); + if (line.ends_with(" ") || line.ends_with("\t")) { + + if (!trimed_whitespace) { + text_editor->begin_complex_operation(); + trimed_whitespace = true; + } + + int end = 0; + for (int j = line.length() - 1; j > -1; j--) { + if (line[j] != ' ' && line[j] != '\t') { + end = j + 1; + break; + } + } + text_editor->set_line(i, line.substr(0, end)); + } + } + + if (trimed_whitespace) { + text_editor->end_complex_operation(); + text_editor->update(); + } +} + +void CodeTextEditor::convert_indent_to_spaces() { + int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size"); + String indent = ""; + + for (int i = 0; i < indent_size; i++) { + indent += " "; + } + + int cursor_line = text_editor->cursor_get_line(); + int cursor_column = text_editor->cursor_get_column(); + + bool changed_indentation = false; + for (int i = 0; i < text_editor->get_line_count(); i++) { + String line = text_editor->get_line(i); + + if (line.length() <= 0) { + continue; + } + + int j = 0; + while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) { + if (line[j] == '\t') { + if (!changed_indentation) { + text_editor->begin_complex_operation(); + changed_indentation = true; + } + if (cursor_line == i && cursor_column > j) { + cursor_column += indent_size - 1; + } + line = line.left(j) + indent + line.right(j + 1); + } + j++; + } + if (changed_indentation) { + text_editor->set_line(i, line); + } + } + if (changed_indentation) { + text_editor->cursor_set_column(cursor_column); + text_editor->end_complex_operation(); + text_editor->update(); + } +} + +void CodeTextEditor::convert_indent_to_tabs() { + int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size"); + indent_size -= 1; + + int cursor_line = text_editor->cursor_get_line(); + int cursor_column = text_editor->cursor_get_column(); + + bool changed_indentation = false; + for (int i = 0; i < text_editor->get_line_count(); i++) { + String line = text_editor->get_line(i); + + if (line.length() <= 0) { + continue; + } + + int j = 0; + int space_count = -1; + while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) { + if (line[j] != '\t') { + space_count++; + + if (space_count == indent_size) { + if (!changed_indentation) { + text_editor->begin_complex_operation(); + changed_indentation = true; + } + if (cursor_line == i && cursor_column > j) { + cursor_column -= indent_size; + } + line = line.left(j - indent_size) + "\t" + line.right(j + 1); + j = 0; + space_count = -1; + } + } else { + space_count = -1; + } + j++; + } + if (changed_indentation) { + text_editor->set_line(i, line); + } + } + if (changed_indentation) { + text_editor->cursor_set_column(cursor_column); + text_editor->end_complex_operation(); + text_editor->update(); + } +} + +void CodeTextEditor::convert_case(CaseStyle p_case) { + if (!text_editor->is_selection_active()) { + return; + } + + text_editor->begin_complex_operation(); + + int begin = text_editor->get_selection_from_line(); + int end = text_editor->get_selection_to_line(); + int begin_col = text_editor->get_selection_from_column(); + int end_col = text_editor->get_selection_to_column(); + + for (int i = begin; i <= end; i++) { + int len = text_editor->get_line(i).length(); + if (i == end) + len -= len - end_col; + if (i == begin) + len -= begin_col; + String new_line = text_editor->get_line(i).substr(i == begin ? begin_col : 0, len); + + switch (p_case) { + case UPPER: { + new_line = new_line.to_upper(); + } break; + case LOWER: { + new_line = new_line.to_lower(); + } break; + case CAPITALIZE: { + new_line = new_line.capitalize(); + } break; + } + + if (i == begin) { + new_line = text_editor->get_line(i).left(begin_col) + new_line; + } + if (i == end) { + new_line = new_line + text_editor->get_line(i).right(end_col); + } + text_editor->set_line(i, new_line); + } + text_editor->end_complex_operation(); +} + +void CodeTextEditor::move_lines_up() { + text_editor->begin_complex_operation(); + if (text_editor->is_selection_active()) { + int from_line = text_editor->get_selection_from_line(); + int from_col = text_editor->get_selection_from_column(); + int to_line = text_editor->get_selection_to_line(); + int to_column = text_editor->get_selection_to_column(); + + for (int i = from_line; i <= to_line; i++) { + int line_id = i; + int next_id = i - 1; + + if (line_id == 0 || next_id < 0) + return; + + text_editor->unfold_line(line_id); + text_editor->unfold_line(next_id); + + text_editor->swap_lines(line_id, next_id); + text_editor->cursor_set_line(next_id); + } + int from_line_up = from_line > 0 ? from_line - 1 : from_line; + int to_line_up = to_line > 0 ? to_line - 1 : to_line; + text_editor->select(from_line_up, from_col, to_line_up, to_column); + } else { + int line_id = text_editor->cursor_get_line(); + int next_id = line_id - 1; + + if (line_id == 0 || next_id < 0) + return; + + text_editor->unfold_line(line_id); + text_editor->unfold_line(next_id); + + text_editor->swap_lines(line_id, next_id); + text_editor->cursor_set_line(next_id); + } + text_editor->end_complex_operation(); + text_editor->update(); +} + +void CodeTextEditor::move_lines_down() { + text_editor->begin_complex_operation(); + if (text_editor->is_selection_active()) { + int from_line = text_editor->get_selection_from_line(); + int from_col = text_editor->get_selection_from_column(); + int to_line = text_editor->get_selection_to_line(); + int to_column = text_editor->get_selection_to_column(); + + for (int i = to_line; i >= from_line; i--) { + int line_id = i; + int next_id = i + 1; + + if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count()) + return; + + text_editor->unfold_line(line_id); + text_editor->unfold_line(next_id); + + text_editor->swap_lines(line_id, next_id); + text_editor->cursor_set_line(next_id); + } + int from_line_down = from_line < text_editor->get_line_count() ? from_line + 1 : from_line; + int to_line_down = to_line < text_editor->get_line_count() ? to_line + 1 : to_line; + text_editor->select(from_line_down, from_col, to_line_down, to_column); + } else { + int line_id = text_editor->cursor_get_line(); + int next_id = line_id + 1; + + if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count()) + return; + + text_editor->unfold_line(line_id); + text_editor->unfold_line(next_id); + + text_editor->swap_lines(line_id, next_id); + text_editor->cursor_set_line(next_id); + } + text_editor->end_complex_operation(); + text_editor->update(); +} + +void CodeTextEditor::delete_lines() { + text_editor->begin_complex_operation(); + if (text_editor->is_selection_active()) { + int to_line = text_editor->get_selection_to_line(); + int from_line = text_editor->get_selection_from_line(); + int count = Math::abs(to_line - from_line) + 1; + while (count) { + text_editor->set_line(text_editor->cursor_get_line(), ""); + text_editor->backspace_at_cursor(); + count--; + if (count) + text_editor->unfold_line(from_line); + } + text_editor->cursor_set_line(from_line - 1); + text_editor->deselect(); + } else { + int line = text_editor->cursor_get_line(); + text_editor->set_line(text_editor->cursor_get_line(), ""); + text_editor->backspace_at_cursor(); + text_editor->unfold_line(line); + text_editor->cursor_set_line(line); + } + text_editor->end_complex_operation(); +} + +void CodeTextEditor::code_lines_down() { + int from_line = text_editor->cursor_get_line(); + int to_line = text_editor->cursor_get_line(); + int column = text_editor->cursor_get_column(); + + if (text_editor->is_selection_active()) { + from_line = text_editor->get_selection_from_line(); + to_line = text_editor->get_selection_to_line(); + column = text_editor->cursor_get_column(); + } + int next_line = to_line + 1; + + if (to_line >= text_editor->get_line_count() - 1) { + text_editor->set_line(to_line, text_editor->get_line(to_line) + "\n"); + } + + text_editor->begin_complex_operation(); + for (int i = from_line; i <= to_line; i++) { + + text_editor->unfold_line(i); + if (i >= text_editor->get_line_count() - 1) { + text_editor->set_line(i, text_editor->get_line(i) + "\n"); + } + String line_clone = text_editor->get_line(i); + text_editor->insert_at(line_clone, next_line); + next_line++; + } + + text_editor->cursor_set_column(column); + if (text_editor->is_selection_active()) { + text_editor->select(to_line + 1, text_editor->get_selection_from_column(), next_line - 1, text_editor->get_selection_to_column()); + } + + text_editor->end_complex_operation(); + text_editor->update(); +} + +void CodeTextEditor::goto_line(int p_line) { + text_editor->deselect(); + text_editor->unfold_line(p_line); + text_editor->call_deferred("cursor_set_line", p_line); +} + +void CodeTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { + text_editor->unfold_line(p_line); + text_editor->call_deferred("cursor_set_line", p_line); + text_editor->call_deferred("cursor_set_column", p_begin); + text_editor->select(p_line, p_begin, p_line, p_end); +} + +Variant CodeTextEditor::get_edit_state() { + Dictionary state; + + state["scroll_position"] = text_editor->get_v_scroll(); + state["column"] = text_editor->cursor_get_column(); + state["row"] = text_editor->cursor_get_line(); + + return state; +} + +void CodeTextEditor::set_edit_state(const Variant &p_state) { + Dictionary state = p_state; + text_editor->cursor_set_column(state["column"]); + text_editor->cursor_set_line(state["row"]); + text_editor->set_v_scroll(state["scroll_position"]); + text_editor->grab_focus(); +} + void CodeTextEditor::set_error(const String &p_error) { error->set_text(p_error); diff --git a/editor/code_editor.h b/editor/code_editor.h index 2a3bb1ba76..903f61d87d 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -186,6 +186,29 @@ protected: static void _bind_methods(); public: + void trim_trailing_whitespace(); + + void convert_indent_to_spaces(); + void convert_indent_to_tabs(); + + enum CaseStyle { + UPPER, + LOWER, + CAPITALIZE, + }; + void convert_case(CaseStyle p_case); + + void move_lines_up(); + void move_lines_down(); + void delete_lines(); + void code_lines_down(); + + void goto_line(int p_line); + void goto_line_selection(int p_line, int p_begin, int p_end); + + Variant get_edit_state(); + void set_edit_state(const Variant &p_state); + void update_editor_settings(); void set_error(const String &p_error); void update_line_and_column() { _line_col_changed(); } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index a68a0779c5..b366ebd911 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -112,6 +112,7 @@ #include "editor/plugins/sprite_editor_plugin.h" #include "editor/plugins/sprite_frames_editor_plugin.h" #include "editor/plugins/style_box_editor_plugin.h" +#include "editor/plugins/text_editor.h" #include "editor/plugins/texture_editor_plugin.h" #include "editor/plugins/texture_region_editor_plugin.h" #include "editor/plugins/theme_editor_plugin.h" @@ -5468,6 +5469,7 @@ EditorNode::EditorNode() { EditorAudioBuses *audio_bus_editor = EditorAudioBuses::register_editor(); ScriptTextEditor::register_editor(); //register one for text scripts + TextEditor::register_editor(); if (StreamPeerSSL::is_available()) { add_editor_plugin(memnew(AssetLibraryEditorPlugin(this))); diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp index 0d0b12c911..43baabe2f5 100644 --- a/editor/inspector_dock.cpp +++ b/editor/inspector_dock.cpp @@ -140,6 +140,7 @@ void InspectorDock::_load_resource(const String &p_type) { void InspectorDock::_resource_file_selected(String p_file) { RES res = ResourceLoader::load(p_file); + if (res.is_null()) { warning_dialog->get_ok()->set_text("Ugh"); warning_dialog->set_text(TTR("Failed to load resource.")); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index de57a4ad51..a1dc746702 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -31,7 +31,6 @@ #include "script_editor_plugin.h" #include "core/io/resource_loader.h" -#include "core/io/resource_saver.h" #include "core/os/file_access.h" #include "core/os/input.h" #include "core/os/keyboard.h" @@ -283,7 +282,6 @@ void ScriptEditor::_breaked(bool p_breaked, bool p_can_debug) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (!se) { - continue; } @@ -402,7 +400,10 @@ void ScriptEditor::_go_to_tab(int p_idx) { if (is_visible_in_tree()) Object::cast_to<ScriptEditorBase>(c)->ensure_focus(); - notify_script_changed(Object::cast_to<ScriptEditorBase>(c)->get_edited_script()); + Ref<Script> script = Object::cast_to<ScriptEditorBase>(c)->get_edited_resource(); + if (script != NULL) { + notify_script_changed(script); + } } if (Object::cast_to<EditorHelp>(c)) { @@ -482,12 +483,23 @@ void ScriptEditor::_open_recent_script(int p_idx) { String path = rc[p_idx]; // if its not on disk its a help file or deleted if (FileAccess::exists(path)) { - Ref<Script> script = ResourceLoader::load(path); - if (script.is_valid()) { - edit(script, true); - return; + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); + + if (extensions.find(path.get_extension())) { + Ref<Script> script = ResourceLoader::load(path); + if (script.is_valid()) { + edit(script, true); + return; + } } + Error err; + Ref<TextFile> text_file = _load_text_file(path, &err); + if (text_file.is_valid()) { + edit(text_file, true); + return; + } // if it's a path then its most likely a deleted file not help } else if (!path.is_resource_file()) { _help_class_open(path); @@ -513,12 +525,17 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { return; Node *tselected = tab_container->get_child(selected); + ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected)); if (current) { if (p_save) { apply_scripts(); } - notify_script_close(current->get_edited_script()); + + Ref<Script> script = current->get_edited_resource(); + if (script != NULL) { + notify_script_close(script); + } } // roll back to previous tab @@ -589,7 +606,7 @@ void ScriptEditor::_close_docs_tab() { void ScriptEditor::_copy_script_path() { ScriptEditorBase *se = _get_current_editor(); - Ref<Script> script = se->get_edited_script(); + RES script = se->get_edited_resource(); OS::get_singleton()->set_clipboard(script->get_path()); } @@ -655,7 +672,7 @@ void ScriptEditor::_resave_scripts(const String &p_str) { if (!se) continue; - Ref<Script> script = se->get_edited_script(); + RES script = se->get_edited_resource(); if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) continue; //internal script, who cares @@ -672,7 +689,14 @@ void ScriptEditor::_resave_scripts(const String &p_str) { } } - editor->save_resource(script); + Ref<TextFile> text_file = script; + if (text_file != NULL) { + se->apply_code(); + _save_text_file(text_file, text_file->get_path()); + break; + } else { + editor->save_resource(script); + } se->tag_saved_version(); } @@ -689,25 +713,37 @@ void ScriptEditor::_reload_scripts() { continue; } - Ref<Script> script = se->get_edited_script(); + RES edited_res = se->get_edited_resource(); - if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) { + if (edited_res->get_path() == "" || edited_res->get_path().find("local://") != -1 || edited_res->get_path().find("::") != -1) { continue; //internal script, who cares } - uint64_t last_date = script->get_last_modified_time(); - uint64_t date = FileAccess::get_modified_time(script->get_path()); + uint64_t last_date = edited_res->get_last_modified_time(); + uint64_t date = FileAccess::get_modified_time(edited_res->get_path()); if (last_date == date) { continue; } - Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), true); - ERR_CONTINUE(!rel_script.is_valid()); - script->set_source_code(rel_script->get_source_code()); - script->set_last_modified_time(rel_script->get_last_modified_time()); - script->reload(); + Ref<Script> script = edited_res; + if (script != NULL) { + Ref<Script> rel_script = ResourceLoader::load(script->get_path(), script->get_class(), true); + ERR_CONTINUE(!rel_script.is_valid()); + script->set_source_code(rel_script->get_source_code()); + script->set_last_modified_time(rel_script->get_last_modified_time()); + script->reload(); + } + + Ref<TextFile> text_file = edited_res; + if (text_file != NULL) { + Error err; + Ref<TextFile> rel_text_file = _load_text_file(text_file->get_path(), &err); + ERR_CONTINUE(!rel_text_file.is_valid()); + text_file->set_text(rel_text_file->get_text()); + text_file->set_last_modified_time(rel_text_file->get_last_modified_time()); + } se->reload_text(); } @@ -725,7 +761,7 @@ void ScriptEditor::_res_saved_callback(const Ref<Resource> &p_res) { continue; } - Ref<Script> script = se->get_edited_script(); + RES script = se->get_edited_resource(); if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) { continue; //internal script, who cares @@ -750,7 +786,7 @@ void ScriptEditor::_live_auto_reload_running_scripts() { debugger->reload_scripts(); } -bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { +bool ScriptEditor::_test_script_times_on_disk(RES p_for_script) { disk_changed_list->clear(); TreeItem *r = disk_changed_list->create_item(); @@ -765,21 +801,20 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - Ref<Script> script = se->get_edited_script(); - - if (p_for_script.is_valid() && p_for_script != script) + RES edited_res = se->get_edited_resource(); + if (edited_res.is_valid() && p_for_script != edited_res) continue; - if (script->get_path() == "" || script->get_path().find("local://") != -1 || script->get_path().find("::") != -1) + if (edited_res->get_path() == "" || edited_res->get_path().find("local://") != -1 || edited_res->get_path().find("::") != -1) continue; //internal script, who cares - uint64_t last_date = script->get_last_modified_time(); - uint64_t date = FileAccess::get_modified_time(script->get_path()); + uint64_t last_date = edited_res->get_last_modified_time(); + uint64_t date = FileAccess::get_modified_time(edited_res->get_path()); if (last_date != date) { TreeItem *ti = disk_changed_list->create_item(r); - ti->set_text(0, script->get_path().get_file()); + ti->set_text(0, edited_res->get_path().get_file()); if (!use_autoreload || se->is_unsaved()) { need_ask = true; @@ -804,6 +839,49 @@ bool ScriptEditor::_test_script_times_on_disk(Ref<Script> p_for_script) { void ScriptEditor::_file_dialog_action(String p_file) { switch (file_dialog_option) { + case FILE_OPEN: { + + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); + if (extensions.find(p_file.get_extension())) { + Ref<Script> scr = ResourceLoader::load(p_file); + if (!scr.is_valid()) { + editor->show_warning(TTR("Error could not load file."), TTR("Error!")); + file_dialog_option = -1; + return; + } + + edit(scr); + file_dialog_option = -1; + return; + } + + Error error; + Ref<TextFile> text_file = _load_text_file(p_file, &error); + if (error != OK) { + editor->show_warning(TTR("Error could not load file."), TTR("Error!")); + } + + if (text_file.is_valid()) { + edit(text_file); + file_dialog_option = -1; + return; + } + } + case FILE_SAVE_AS: { + ScriptEditorBase *current = _get_current_editor(); + + String path = ProjectSettings::get_singleton()->localize_path(p_file); + Error err = _save_text_file(current->get_edited_resource(), path); + + if (err != OK) { + editor->show_accept(TTR("Error saving file!"), TTR("OK")); + return; + } + + ((Resource *)current->get_edited_resource().ptr())->set_path(path); + _update_script_names(); + } break; case THEME_SAVE_AS: { if (!EditorSettings::get_singleton()->save_text_editor_theme_as(p_file)) { editor->show_warning(TTR("Error while saving theme"), TTR("Error saving")); @@ -823,7 +901,8 @@ Ref<Script> ScriptEditor::_get_current_script() { ScriptEditorBase *current = _get_current_editor(); if (current) { - return current->get_edited_script(); + Ref<Script> script = current->get_edited_resource(); + return script != NULL ? script : NULL; } else { return NULL; } @@ -848,8 +927,19 @@ void ScriptEditor::_menu_option(int p_option) { script_create_dialog->popup_centered(Size2(300, 300) * EDSCALE); } break; case FILE_OPEN: { + file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); + file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + file_dialog_option = FILE_OPEN; - editor->open_resource("Script"); + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); + file_dialog->clear_filters(); + for (int i = 0; i < extensions.size(); i++) { + file_dialog->add_filter("*." + extensions[i] + " ; " + extensions[i].to_upper()); + } + + file_dialog->popup_centered_ratio(); + file_dialog->set_title(TTR("Open File")); return; } break; case FILE_SAVE_ALL: { @@ -929,7 +1019,14 @@ void ScriptEditor::_menu_option(int p_option) { current->convert_indent_to_tabs(); } } - editor->save_resource(current->get_edited_script()); + + Ref<TextFile> text_file = current->get_edited_resource(); + if (text_file != NULL) { + current->apply_code(); + _save_text_file(text_file, text_file->get_path()); + break; + } + editor->save_resource(current->get_edited_resource()); } break; case FILE_SAVE_AS: { @@ -943,8 +1040,25 @@ void ScriptEditor::_menu_option(int p_option) { current->convert_indent_to_tabs(); } } - editor->push_item(Object::cast_to<Object>(current->get_edited_script().ptr())); - editor->save_resource_as(current->get_edited_script()); + + Ref<TextFile> text_file = current->get_edited_resource(); + if (text_file != NULL) { + file_dialog->set_mode(EditorFileDialog::MODE_SAVE_FILE); + file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); + file_dialog_option = FILE_SAVE_AS; + + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); + file_dialog->clear_filters(); + file_dialog->set_current_dir(text_file->get_path().get_base_dir()); + file_dialog->set_current_file(text_file->get_path().get_file()); + file_dialog->popup_centered_ratio(); + file_dialog->set_title(TTR("Save File As...")); + break; + } + + editor->push_item(Object::cast_to<Object>(current->get_edited_resource().ptr())); + editor->save_resource_as(current->get_edited_resource()); } break; @@ -956,8 +1070,8 @@ void ScriptEditor::_menu_option(int p_option) { } break; case FILE_RUN: { - Ref<Script> scr = current->get_edited_script(); - if (scr.is_null()) { + Ref<Script> scr = current->get_edited_resource(); + if (scr == NULL || scr.is_null()) { EditorNode::get_singleton()->show_warning("Can't obtain the script for running"); break; } @@ -1000,8 +1114,7 @@ void ScriptEditor::_menu_option(int p_option) { _copy_script_path(); } break; case SHOW_IN_FILE_SYSTEM: { - ScriptEditorBase *se = _get_current_editor(); - Ref<Script> script = se->get_edited_script(); + RES script = current->get_edited_resource(); FileSystemDock *file_system_dock = EditorNode::get_singleton()->get_filesystem_dock(); file_system_dock->navigate_to_path(script->get_path()); // Ensure that the FileSystem dock is visible. @@ -1259,8 +1372,8 @@ void ScriptEditor::close_builtin_scripts_from_scene(const String &p_scene) { if (se) { - Ref<Script> script = se->get_edited_script(); - if (!script.is_valid()) + Ref<Script> script = se->get_edited_resource(); + if (script == NULL || !script.is_valid()) continue; if (script->get_path().find("::") != -1 && script->get_path().begins_with(p_scene)) { //is an internal script and belongs to scene being closed @@ -1307,9 +1420,13 @@ void ScriptEditor::get_breakpoints(List<String> *p_breakpoints) { if (!se) continue; + Ref<Script> script = se->get_edited_resource(); + if (script == NULL) { + continue; + } + List<int> bpoints; se->get_breakpoints(&bpoints); - Ref<Script> script = se->get_edited_script(); String base = script->get_path(); ERR_CONTINUE(base.begins_with("local://") || base == ""); @@ -1452,7 +1569,7 @@ void ScriptEditor::_update_members_overview() { members_overview->set_item_metadata(i, functions[i].get_slice(":", 1).to_int() - 1); } - String path = se->get_edited_script()->get_path(); + String path = se->get_edited_resource()->get_path(); bool built_in = !path.is_resource_file(); String name = built_in ? path.get_file() : se->get_name(); filename->set_text(name); @@ -1570,7 +1687,7 @@ void ScriptEditor::_update_script_names() { if (se) { Ref<Texture> icon = se->get_icon(); - String path = se->get_edited_script()->get_path(); + String path = se->get_edited_resource()->get_path(); bool built_in = !path.is_resource_file(); String name = built_in ? path.get_file() : se->get_name(); @@ -1579,7 +1696,7 @@ void ScriptEditor::_update_script_names() { sd.name = name; sd.tooltip = path; sd.index = i; - sd.used = used.has(se->get_edited_script()); + sd.used = used.has(se->get_edited_resource()); sd.category = 0; sd.ref = se; @@ -1681,11 +1798,65 @@ void ScriptEditor::_update_script_names() { _update_script_colors(); } -bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool p_grab_focus) { +Ref<TextFile> ScriptEditor::_load_text_file(const String &p_path, Error *r_error) { + if (r_error) { + *r_error = ERR_FILE_CANT_OPEN; + } + + String local_path = ProjectSettings::get_singleton()->localize_path(p_path); + String path = ResourceLoader::path_remap(local_path); + + TextFile *text_file = memnew(TextFile); + Ref<TextFile> text_res(text_file); + Error err = text_file->load_text(path); + + if (err != OK) { + ERR_FAIL_COND_V(err != OK, RES()); + } + + text_file->set_file_path(local_path); + text_file->set_path(local_path, true); + + if (r_error) { + *r_error = OK; + } + + return text_res; +} + +Error ScriptEditor::_save_text_file(Ref<TextFile> p_text_file, const String &p_path) { + Ref<TextFile> sqscr = p_text_file; + ERR_FAIL_COND_V(sqscr.is_null(), ERR_INVALID_PARAMETER); + + String source = sqscr->get_text(); + + Error err; + FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + + if (err) { + + ERR_FAIL_COND_V(err, err); + } + + file->store_string(source); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + memdelete(file); + return ERR_CANT_CREATE; + } + file->close(); + memdelete(file); + + _res_saved_callback(sqscr); + return OK; +} + +bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_grab_focus) { - if (p_script.is_null()) + if (p_resource.is_null()) return false; + Ref<Script> script = p_resource; + // refuse to open built-in if scene is not loaded // see if already has it @@ -1694,17 +1865,17 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool const bool should_open = open_dominant || !EditorNode::get_singleton()->is_changing_scene(); - if (p_script->get_language()->overrides_external_editor()) { + if (script != NULL && script->get_language()->overrides_external_editor()) { if (should_open) { - Error err = p_script->get_language()->open_in_external_editor(p_script, p_line >= 0 ? p_line : 0, p_col); + Error err = script->get_language()->open_in_external_editor(script, p_line >= 0 ? p_line : 0, p_col); if (err != OK) ERR_PRINT("Couldn't open script in the overridden external text editor"); } return false; } - if ((debugger->get_dump_stack_script() != p_script || debugger->get_debug_with_external_editor()) && - p_script->get_path().is_resource_file() && + if ((debugger->get_dump_stack_script() != p_resource || debugger->get_debug_with_external_editor()) && + p_resource->get_path().is_resource_file() && bool(EditorSettings::get_singleton()->get("text_editor/external/use_external_editor"))) { String path = EditorSettings::get_singleton()->get("text_editor/external/exec_path"); @@ -1714,7 +1885,7 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool if (flags.size()) { String project_path = ProjectSettings::get_singleton()->get_resource_path(); - String script_path = ProjectSettings::get_singleton()->globalize_path(p_script->get_path()); + String script_path = ProjectSettings::get_singleton()->globalize_path(p_resource->get_path()); flags = flags.replacen("{line}", itos(p_line > 0 ? p_line : 0)); flags = flags.replacen("{col}", itos(p_col)); @@ -1762,7 +1933,7 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool if (!se) continue; - if (se->get_edited_script() == p_script) { + if (se->get_edited_resource() == p_resource) { if (should_open) { if (tab_container->get_current_tab() != i) { @@ -1784,7 +1955,7 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool ScriptEditorBase *se; for (int i = script_editor_func_count - 1; i >= 0; i--) { - se = script_editor_funcs[i](p_script); + se = script_editor_funcs[i](p_resource); if (se) break; } @@ -1795,9 +1966,9 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool SyntaxHighlighter *highlighter = syntax_highlighters_funcs[i](); se->add_syntax_highlighter(highlighter); - if (!highlighter_set) { + if (script != NULL && !highlighter_set) { List<String> languages = highlighter->get_supported_languages(); - if (languages.find(p_script->get_language()->get_name())) { + if (languages.find(script->get_language()->get_name())) { se->set_syntax_highlighter(highlighter); highlighter_set = true; } @@ -1805,7 +1976,7 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool } tab_container->add_child(se); - se->set_edited_script(p_script); + se->set_edited_resource(p_resource); se->set_tooltip_request_func("_get_debug_tooltip", this); if (se->get_edit_menu()) { se->get_edit_menu()->hide(); @@ -1829,14 +2000,14 @@ bool ScriptEditor::edit(const Ref<Script> &p_script, int p_line, int p_col, bool //test for modification, maybe the script was not edited but was loaded - _test_script_times_on_disk(p_script); - _update_modified_scripts_for_external_editor(p_script); + _test_script_times_on_disk(p_resource); + _update_modified_scripts_for_external_editor(p_resource); if (p_line >= 0) se->goto_line(p_line - 1); - notify_script_changed(p_script); - _add_recent_script(p_script->get_path()); + notify_script_changed(p_resource); + _add_recent_script(p_resource->get_path()); return true; } @@ -1863,12 +2034,19 @@ void ScriptEditor::save_all_scripts() { if (!se->is_unsaved()) continue; - Ref<Script> script = se->get_edited_script(); - if (script.is_valid()) + RES edited_res = se->get_edited_resource(); + if (edited_res.is_valid()) { se->apply_code(); + } - if (script->get_path() != "" && script->get_path().find("local://") == -1 && script->get_path().find("::") == -1) - editor->save_resource(script); //external script, save it + if (edited_res->get_path() != "" && edited_res->get_path().find("local://") == -1 && edited_res->get_path().find("::") == -1) { + Ref<TextFile> text_file = edited_res; + if (text_file != NULL) { + _save_text_file(text_file, text_file->get_path()); + continue; + } + editor->save_resource(edited_res); //external script, save it + } } _update_script_names(); @@ -1938,7 +2116,7 @@ void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (!se) continue; - if (se->get_edited_script() != script) + if (se->get_edited_resource() != script) continue; se->add_callback(p_function, p_args); @@ -2228,9 +2406,12 @@ void ScriptEditor::_make_script_list_context_menu() { context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_other_tabs"), CLOSE_OTHER_TABS); context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/copy_path"), FILE_COPY_PATH); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/show_in_file_system"), SHOW_IN_FILE_SYSTEM); - Ref<Script> scr = se->get_edited_script(); + } + + Ref<Script> scr = se->get_edited_resource(); + if (scr != NULL) { + context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/reload_script_soft"), FILE_TOOL_RELOAD_SOFT); if (!scr.is_null() && scr->is_tool()) { context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/run_file"), FILE_RUN); @@ -2266,14 +2447,28 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { restoring_layout = true; + List<String> extensions; + ResourceLoader::get_recognized_extensions_for_type("Script", &extensions); + for (int i = 0; i < scripts.size(); i++) { String path = scripts[i]; if (!FileAccess::exists(path)) continue; - Ref<Script> scr = ResourceLoader::load(path); - if (scr.is_valid()) { - edit(scr); + + if (extensions.find(path.get_extension())) { + Ref<Script> scr = ResourceLoader::load(path); + if (scr.is_valid()) { + edit(scr); + continue; + } + } + + Error error; + Ref<TextFile> text_file = _load_text_file(path, &error); + if (error == OK && text_file.is_valid()) { + edit(text_file); + continue; } } @@ -2309,7 +2504,7 @@ void ScriptEditor::get_window_layout(Ref<ConfigFile> p_layout) { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (se) { - String path = se->get_edited_script()->get_path(); + String path = se->get_edited_resource()->get_path(); if (!path.is_resource_file()) continue; @@ -2434,7 +2629,10 @@ void ScriptEditor::_update_history_pos(int p_new_pos) { Object::cast_to<ScriptEditorBase>(n)->set_edit_state(history[history_pos].state); Object::cast_to<ScriptEditorBase>(n)->ensure_focus(); - notify_script_changed(Object::cast_to<ScriptEditorBase>(n)->get_edited_script()); + Ref<Script> script = Object::cast_to<ScriptEditorBase>(n)->get_edited_resource(); + if (script != NULL) { + notify_script_changed(script); + } } if (Object::cast_to<EditorHelp>(n)) { @@ -2471,7 +2669,11 @@ Vector<Ref<Script> > ScriptEditor::get_open_scripts() const { ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(tab_container->get_child(i)); if (!se) continue; - out_scripts.push_back(se->get_edited_script()); + + Ref<Script> script = se->get_edited_resource(); + if (script != NULL) { + out_scripts.push_back(script); + } } return out_scripts; @@ -2517,6 +2719,14 @@ void ScriptEditor::_open_script_request(const String &p_path) { Ref<Script> script = ResourceLoader::load(p_path); if (script.is_valid()) { script_editor->edit(script, false); + return; + } + + Error err; + Ref<TextFile> text_file = script_editor->_load_text_file(p_path, &err); + if (text_file.is_valid()) { + script_editor->edit(text_file, false); + return; } } @@ -2550,7 +2760,7 @@ void ScriptEditor::_on_find_in_files_requested(String text) { void ScriptEditor::_on_find_in_files_result_selected(String fpath, int line_number, int begin, int end) { - Ref<Resource> res = ResourceLoader::load(fpath); + RES res = ResourceLoader::load(fpath); edit(res); ScriptEditorBase *seb = _get_current_editor(); @@ -2966,14 +3176,21 @@ ScriptEditor::~ScriptEditor() { void ScriptEditorPlugin::edit(Object *p_object) { - if (!Object::cast_to<Script>(p_object)) - return; + if (Object::cast_to<Script>(p_object)) { + script_editor->edit(Object::cast_to<Script>(p_object)); + } - script_editor->edit(Object::cast_to<Script>(p_object)); + if (Object::cast_to<TextFile>(p_object)) { + script_editor->edit(Object::cast_to<TextFile>(p_object)); + } } bool ScriptEditorPlugin::handles(Object *p_object) const { + if (Object::cast_to<TextFile>(p_object)) { + return true; + } + if (Object::cast_to<Script>(p_object)) { bool valid = _can_open_in_editor(Object::cast_to<Script>(p_object)); diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index ad12add53f..186c80a5f9 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -43,6 +43,7 @@ #include "scene/gui/tool_button.h" #include "scene/gui/tree.h" #include "scene/main/timer.h" +#include "scene/resources/text_file.h" #include "script_language.h" class ScriptEditorQuickOpen : public ConfirmationDialog { @@ -74,7 +75,7 @@ class ScriptEditorDebugger; class ScriptEditorBase : public VBoxContainer { - GDCLASS(ScriptEditorBase, VBoxContainer); + GDCLASS(ScriptEditorBase, VBoxContainer) protected: static void _bind_methods(); @@ -84,9 +85,9 @@ public: virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter) = 0; virtual void apply_code() = 0; - virtual Ref<Script> get_edited_script() const = 0; + virtual RES get_edited_resource() const = 0; virtual Vector<String> get_functions() = 0; - virtual void set_edited_script(const Ref<Script> &p_script) = 0; + virtual void set_edited_resource(const RES &p_res) = 0; virtual void reload_text() = 0; virtual String get_name() = 0; virtual Ref<Texture> get_icon() = 0; @@ -99,7 +100,7 @@ public: virtual void convert_indent_to_tabs() = 0; virtual void ensure_focus() = 0; virtual void tag_saved_version() = 0; - virtual void reload(bool p_soft) = 0; + virtual void reload(bool p_soft) {} virtual void get_breakpoints(List<int> *p_breakpoints) = 0; virtual void add_callback(const String &p_function, PoolStringArray p_args) = 0; virtual void update_settings() = 0; @@ -116,7 +117,7 @@ public: }; typedef SyntaxHighlighter *(*CreateSyntaxHighlighterFunc)(); -typedef ScriptEditorBase *(*CreateScriptEditorFunc)(const Ref<Script> &p_script); +typedef ScriptEditorBase *(*CreateScriptEditorFunc)(const RES &p_resource); class EditorScriptCodeCompletionCache; class FindInFilesDialog; @@ -268,7 +269,7 @@ class ScriptEditor : public PanelContainer { void _resave_scripts(const String &p_str); void _reload_scripts(); - bool _test_script_times_on_disk(Ref<Script> p_for_script = Ref<Script>()); + bool _test_script_times_on_disk(RES p_for_script = Ref<Resource>()); void _add_recent_script(String p_path); void _update_recent_scripts(); @@ -378,6 +379,9 @@ class ScriptEditor : public PanelContainer { Ref<Script> _get_current_script(); Array _get_open_scripts() const; + Ref<TextFile> _load_text_file(const String &p_path, Error *r_error); + Error _save_text_file(Ref<TextFile> p_text_file, const String &p_path); + void _on_find_in_files_requested(String text); void _on_find_in_files_result_selected(String fpath, int line_number, int begin, int end); void _start_find_in_files(bool with_replace); @@ -400,8 +404,8 @@ public: void ensure_select_current(); - _FORCE_INLINE_ bool edit(const Ref<Script> &p_script, bool p_grab_focus = true) { return edit(p_script, -1, 0, p_grab_focus); } - bool edit(const Ref<Script> &p_script, int p_line, int p_col, bool p_grab_focus = true); + _FORCE_INLINE_ bool edit(const RES &p_resource, bool p_grab_focus = true) { return edit(p_resource, -1, 0, p_grab_focus); } + bool edit(const RES &p_resource, int p_line, int p_col, bool p_grab_focus = true); void get_breakpoints(List<String> *p_breakpoints); diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 2263d782d9..165d7e32b9 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -66,11 +66,24 @@ void ScriptTextEditor::apply_code() { _update_member_keywords(); } -Ref<Script> ScriptTextEditor::get_edited_script() const { - +RES ScriptTextEditor::get_edited_resource() const { return script; } +void ScriptTextEditor::set_edited_resource(const RES &p_res) { + ERR_FAIL_COND(!script.is_null()); + + script = p_res; + _set_theme_for_script(); + + code_editor->get_text_edit()->set_text(script->get_source_code()); + code_editor->get_text_edit()->clear_undo_history(); + code_editor->get_text_edit()->tag_saved_version(); + + emit_signal("name_changed"); + code_editor->update_line_and_column(); +} + void ScriptTextEditor::_update_member_keywords() { member_keywords.clear(); code_editor->get_text_edit()->clear_member_keywords(); @@ -190,6 +203,7 @@ void ScriptTextEditor::_set_theme_for_script() { List<String> keywords; script->get_language()->get_reserved_words(&keywords); + for (List<String>::Element *E = keywords.front(); E; E = E->next()) { text_edit->add_keyword_color(E->get(), colors_cache.keyword_color); @@ -251,7 +265,6 @@ void ScriptTextEditor::_set_theme_for_script() { //colorize strings List<String> strings; script->get_language()->get_string_delimiters(&strings); - for (List<String>::Element *E = strings.front(); E; E = E->next()) { String string = E->get(); @@ -326,197 +339,32 @@ bool ScriptTextEditor::is_unsaved() { Variant ScriptTextEditor::get_edit_state() { - Dictionary state; + return code_editor->get_edit_state(); +} - state["scroll_position"] = code_editor->get_text_edit()->get_v_scroll(); - state["column"] = code_editor->get_text_edit()->cursor_get_column(); - state["row"] = code_editor->get_text_edit()->cursor_get_line(); +void ScriptTextEditor::set_edit_state(const Variant &p_state) { - return state; + code_editor->set_edit_state(p_state); } -void ScriptTextEditor::_convert_case(CaseStyle p_case) { - TextEdit *te = code_editor->get_text_edit(); - Ref<Script> scr = get_edited_script(); - if (scr.is_null()) { - return; - } - - if (te->is_selection_active()) { - te->begin_complex_operation(); - - int begin = te->get_selection_from_line(); - int end = te->get_selection_to_line(); - int begin_col = te->get_selection_from_column(); - int end_col = te->get_selection_to_column(); - - for (int i = begin; i <= end; i++) { - int len = te->get_line(i).length(); - if (i == end) - len -= len - end_col; - if (i == begin) - len -= begin_col; - String new_line = te->get_line(i).substr(i == begin ? begin_col : 0, len); - - switch (p_case) { - case UPPER: { - new_line = new_line.to_upper(); - } break; - case LOWER: { - new_line = new_line.to_lower(); - } break; - case CAPITALIZE: { - new_line = new_line.capitalize(); - } break; - } +void ScriptTextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { - if (i == begin) { - new_line = te->get_line(i).left(begin_col) + new_line; - } - if (i == end) { - new_line = new_line + te->get_line(i).right(end_col); - } - te->set_line(i, new_line); - } - te->end_complex_operation(); - } + code_editor->convert_case(p_case); } void ScriptTextEditor::trim_trailing_whitespace() { - TextEdit *tx = code_editor->get_text_edit(); - - bool trimed_whitespace = false; - for (int i = 0; i < tx->get_line_count(); i++) { - String line = tx->get_line(i); - if (line.ends_with(" ") || line.ends_with("\t")) { - - if (!trimed_whitespace) { - tx->begin_complex_operation(); - trimed_whitespace = true; - } - - int end = 0; - for (int j = line.length() - 1; j > -1; j--) { - if (line[j] != ' ' && line[j] != '\t') { - end = j + 1; - break; - } - } - tx->set_line(i, line.substr(0, end)); - } - } - if (trimed_whitespace) { - tx->end_complex_operation(); - tx->update(); - } + code_editor->trim_trailing_whitespace(); } void ScriptTextEditor::convert_indent_to_spaces() { - TextEdit *tx = code_editor->get_text_edit(); - Ref<Script> scr = get_edited_script(); - if (scr.is_null()) { - return; - } - - int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size"); - String indent = ""; - - for (int i = 0; i < indent_size; i++) { - indent += " "; - } - - int cursor_line = tx->cursor_get_line(); - int cursor_column = tx->cursor_get_column(); - - bool changed_indentation = false; - for (int i = 0; i < tx->get_line_count(); i++) { - String line = tx->get_line(i); - - if (line.length() <= 0) { - continue; - } - - int j = 0; - while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) { - if (line[j] == '\t') { - if (!changed_indentation) { - tx->begin_complex_operation(); - changed_indentation = true; - } - if (cursor_line == i && cursor_column > j) { - cursor_column += indent_size - 1; - } - line = line.left(j) + indent + line.right(j + 1); - } - j++; - } - if (changed_indentation) { - tx->set_line(i, line); - } - } - if (changed_indentation) { - tx->cursor_set_column(cursor_column); - tx->end_complex_operation(); - tx->update(); - } + code_editor->convert_indent_to_spaces(); } void ScriptTextEditor::convert_indent_to_tabs() { - TextEdit *tx = code_editor->get_text_edit(); - Ref<Script> scr = get_edited_script(); - - if (scr.is_null()) { - return; - } - - int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size"); - indent_size -= 1; - - int cursor_line = tx->cursor_get_line(); - int cursor_column = tx->cursor_get_column(); - - bool changed_indentation = false; - for (int i = 0; i < tx->get_line_count(); i++) { - String line = tx->get_line(i); - - if (line.length() <= 0) { - continue; - } - - int j = 0; - int space_count = -1; - while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) { - if (line[j] != '\t') { - space_count++; - if (space_count == indent_size) { - if (!changed_indentation) { - tx->begin_complex_operation(); - changed_indentation = true; - } - if (cursor_line == i && cursor_column > j) { - cursor_column -= indent_size; - } - line = line.left(j - indent_size) + "\t" + line.right(j + 1); - j = 0; - space_count = -1; - } - } else { - space_count = -1; - } - j++; - } - if (changed_indentation) { - tx->set_line(i, line); - } - } - if (changed_indentation) { - tx->cursor_set_column(cursor_column); - tx->end_complex_operation(); - tx->update(); - } + code_editor->convert_indent_to_tabs(); } void ScriptTextEditor::tag_saved_version() { @@ -525,31 +373,17 @@ void ScriptTextEditor::tag_saved_version() { } void ScriptTextEditor::goto_line(int p_line, bool p_with_error) { - TextEdit *tx = code_editor->get_text_edit(); - tx->deselect(); - tx->unfold_line(p_line); - tx->call_deferred("cursor_set_line", p_line); -} -void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { - TextEdit *tx = code_editor->get_text_edit(); - tx->unfold_line(p_line); - tx->call_deferred("cursor_set_line", p_line); - tx->call_deferred("cursor_set_column", p_begin); - tx->select(p_line, p_begin, p_line, p_end); + code_editor->goto_line(p_line); } -void ScriptTextEditor::ensure_focus() { +void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) { - code_editor->get_text_edit()->grab_focus(); + code_editor->goto_line_selection(p_line, p_begin, p_end); } -void ScriptTextEditor::set_edit_state(const Variant &p_state) { +void ScriptTextEditor::ensure_focus() { - Dictionary state = p_state; - code_editor->get_text_edit()->cursor_set_column(state["column"]); - code_editor->get_text_edit()->cursor_set_line(state["row"]); - code_editor->get_text_edit()->set_v_scroll(state["scroll_position"]); code_editor->get_text_edit()->grab_focus(); } @@ -578,22 +412,6 @@ Ref<Texture> ScriptTextEditor::get_icon() { return Ref<Texture>(); } -void ScriptTextEditor::set_edited_script(const Ref<Script> &p_script) { - - ERR_FAIL_COND(!script.is_null()); - - script = p_script; - _set_theme_for_script(); - - code_editor->get_text_edit()->set_text(script->get_source_code()); - code_editor->get_text_edit()->clear_undo_history(); - code_editor->get_text_edit()->tag_saved_version(); - - emit_signal("name_changed"); - code_editor->update_line_and_column(); - call_deferred("_validate_script"); -} - void ScriptTextEditor::_validate_script() { String errortxt; @@ -878,98 +696,15 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_MOVE_LINE_UP: { - Ref<Script> scr = script; - if (scr.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int from_line = tx->get_selection_from_line(); - int from_col = tx->get_selection_from_column(); - int to_line = tx->get_selection_to_line(); - int to_column = tx->get_selection_to_column(); - - for (int i = from_line; i <= to_line; i++) { - int line_id = i; - int next_id = i - 1; - - if (line_id == 0 || next_id < 0) - return; - - tx->unfold_line(line_id); - tx->unfold_line(next_id); - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - int from_line_up = from_line > 0 ? from_line - 1 : from_line; - int to_line_up = to_line > 0 ? to_line - 1 : to_line; - tx->select(from_line_up, from_col, to_line_up, to_column); - } else { - int line_id = tx->cursor_get_line(); - int next_id = line_id - 1; - - if (line_id == 0 || next_id < 0) - return; - - tx->unfold_line(line_id); - tx->unfold_line(next_id); - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - tx->end_complex_operation(); - tx->update(); + code_editor->move_lines_up(); } break; case EDIT_MOVE_LINE_DOWN: { - Ref<Script> scr = get_edited_script(); - if (scr.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int from_line = tx->get_selection_from_line(); - int from_col = tx->get_selection_from_column(); - int to_line = tx->get_selection_to_line(); - int to_column = tx->get_selection_to_column(); - - for (int i = to_line; i >= from_line; i--) { - int line_id = i; - int next_id = i + 1; - - if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) - return; - - tx->unfold_line(line_id); - tx->unfold_line(next_id); - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - int from_line_down = from_line < tx->get_line_count() ? from_line + 1 : from_line; - int to_line_down = to_line < tx->get_line_count() ? to_line + 1 : to_line; - tx->select(from_line_down, from_col, to_line_down, to_column); - } else { - int line_id = tx->cursor_get_line(); - int next_id = line_id + 1; - - if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) - return; - - tx->unfold_line(line_id); - tx->unfold_line(next_id); - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - tx->end_complex_operation(); - tx->update(); - + code_editor->move_lines_down(); } break; case EDIT_INDENT_LEFT: { - Ref<Script> scr = get_edited_script(); + Ref<Script> scr = script; if (scr.is_null()) return; @@ -977,7 +712,7 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_INDENT_RIGHT: { - Ref<Script> scr = get_edited_script(); + Ref<Script> scr = script; if (scr.is_null()) return; @@ -985,72 +720,11 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_DELETE_LINE: { - Ref<Script> scr = get_edited_script(); - if (scr.is_null()) - return; - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int to_line = tx->get_selection_to_line(); - int from_line = tx->get_selection_from_line(); - int count = Math::abs(to_line - from_line) + 1; - while (count) { - tx->set_line(tx->cursor_get_line(), ""); - tx->backspace_at_cursor(); - count--; - if (count) - tx->unfold_line(from_line); - } - tx->cursor_set_line(from_line - 1); - tx->deselect(); - } else { - int line = tx->cursor_get_line(); - tx->set_line(tx->cursor_get_line(), ""); - tx->backspace_at_cursor(); - tx->unfold_line(line); - tx->cursor_set_line(line); - } - tx->end_complex_operation(); + code_editor->delete_lines(); } break; case EDIT_CLONE_DOWN: { - Ref<Script> scr = get_edited_script(); - if (scr.is_null()) - return; - - int from_line = tx->cursor_get_line(); - int to_line = tx->cursor_get_line(); - int column = tx->cursor_get_column(); - - if (tx->is_selection_active()) { - from_line = tx->get_selection_from_line(); - to_line = tx->get_selection_to_line(); - column = tx->cursor_get_column(); - } - int next_line = to_line + 1; - - if (to_line >= tx->get_line_count() - 1) { - tx->set_line(to_line, tx->get_line(to_line) + "\n"); - } - - tx->begin_complex_operation(); - for (int i = from_line; i <= to_line; i++) { - - tx->unfold_line(i); - if (i >= tx->get_line_count() - 1) { - tx->set_line(i, tx->get_line(i) + "\n"); - } - String line_clone = tx->get_line(i); - tx->insert_at(line_clone, next_line); - next_line++; - } - - tx->cursor_set_column(column); - if (tx->is_selection_active()) { - tx->select(to_line + 1, tx->get_selection_from_column(), next_line - 1, tx->get_selection_to_column()); - } - - tx->end_complex_operation(); - tx->update(); + code_editor->code_lines_down(); } break; case EDIT_TOGGLE_FOLD_LINE: { @@ -1069,7 +743,7 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_TOGGLE_COMMENT: { - Ref<Script> scr = get_edited_script(); + Ref<Script> scr = script; if (scr.is_null()) return; @@ -1137,7 +811,7 @@ void ScriptTextEditor::_edit_option(int p_op) { case EDIT_AUTO_INDENT: { String text = tx->get_text(); - Ref<Script> scr = get_edited_script(); + Ref<Script> scr = script; if (scr.is_null()) return; @@ -1180,15 +854,15 @@ void ScriptTextEditor::_edit_option(int p_op) { } break; case EDIT_TO_UPPERCASE: { - _convert_case(UPPER); + _convert_case(CodeTextEditor::UPPER); } break; case EDIT_TO_LOWERCASE: { - _convert_case(LOWER); + _convert_case(CodeTextEditor::LOWER); } break; case EDIT_CAPITALIZE: { - _convert_case(CAPITALIZE); + _convert_case(CodeTextEditor::CAPITALIZE); } break; case SEARCH_FIND: { @@ -1228,7 +902,7 @@ void ScriptTextEditor::_edit_option(int p_op) { int line = tx->cursor_get_line(); bool dobreak = !tx->is_line_set_as_breakpoint(line); tx->set_line_as_breakpoint(line, dobreak); - ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak); + ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), line + 1, dobreak); } break; case DEBUG_REMOVE_ALL_BREAKPOINTS: { @@ -1239,7 +913,7 @@ void ScriptTextEditor::_edit_option(int p_op) { int line = E->get(); bool dobreak = !tx->is_line_set_as_breakpoint(line); tx->set_line_as_breakpoint(line, dobreak); - ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(get_edited_script()->get_path(), line + 1, dobreak); + ScriptEditor::get_singleton()->get_debugger()->set_breakpoint(script->get_path(), line + 1, dobreak); } } case DEBUG_GOTO_NEXT_BREAKPOINT: { @@ -1359,7 +1033,7 @@ void ScriptTextEditor::clear_edit_menu() { void ScriptTextEditor::reload(bool p_soft) { TextEdit *te = code_editor->get_text_edit(); - Ref<Script> scr = get_edited_script(); + Ref<Script> scr = script; if (scr.is_null()) return; scr->set_source_code(te->get_text()); @@ -1743,9 +1417,12 @@ ScriptTextEditor::ScriptTextEditor() { code_editor->get_text_edit()->set_drag_forwarding(this); } -static ScriptEditorBase *create_editor(const Ref<Script> &p_script) { +static ScriptEditorBase *create_editor(const RES &p_resource) { - return memnew(ScriptTextEditor); + if (Object::cast_to<Script>(*p_resource)) { + return memnew(ScriptTextEditor); + } + return NULL; } void ScriptTextEditor::register_editor() { diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index a415f478e8..f0b00a9117 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -138,12 +138,7 @@ protected: void _goto_line(int p_line) { goto_line(p_line); } void _lookup_symbol(const String &p_symbol, int p_row, int p_column); - enum CaseStyle { - UPPER, - LOWER, - CAPITALIZE, - }; - void _convert_case(CaseStyle p_case); + void _convert_case(CodeTextEditor::CaseStyle p_case); Variant get_drag_data_fw(const Point2 &p_point, Control *p_from); bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const; @@ -154,14 +149,13 @@ public: virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter); virtual void apply_code(); - virtual Ref<Script> get_edited_script() const; + virtual RES get_edited_resource() const; + virtual void set_edited_resource(const RES &p_res); virtual Vector<String> get_functions(); - virtual void set_edited_script(const Ref<Script> &p_script); virtual void reload_text(); virtual String get_name(); virtual Ref<Texture> get_icon(); virtual bool is_unsaved(); - virtual Variant get_edit_state(); virtual void set_edit_state(const Variant &p_state); virtual void ensure_focus(); diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 4b7f27c0c1..7650cd6ae7 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -258,84 +258,10 @@ void ShaderEditor::_menu_option(int p_option) { shader_editor->get_text_edit()->select_all(); } break; case EDIT_MOVE_LINE_UP: { - - TextEdit *tx = shader_editor->get_text_edit(); - if (shader.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int from_line = tx->get_selection_from_line(); - int from_col = tx->get_selection_from_column(); - int to_line = tx->get_selection_to_line(); - int to_column = tx->get_selection_to_column(); - - for (int i = from_line; i <= to_line; i++) { - int line_id = i; - int next_id = i - 1; - - if (line_id == 0 || next_id < 0) - return; - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - int from_line_up = from_line > 0 ? from_line - 1 : from_line; - int to_line_up = to_line > 0 ? to_line - 1 : to_line; - tx->select(from_line_up, from_col, to_line_up, to_column); - } else { - int line_id = tx->cursor_get_line(); - int next_id = line_id - 1; - - if (line_id == 0 || next_id < 0) - return; - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - tx->end_complex_operation(); - tx->update(); - + shader_editor->move_lines_up(); } break; case EDIT_MOVE_LINE_DOWN: { - - TextEdit *tx = shader_editor->get_text_edit(); - if (shader.is_null()) - return; - - tx->begin_complex_operation(); - if (tx->is_selection_active()) { - int from_line = tx->get_selection_from_line(); - int from_col = tx->get_selection_from_column(); - int to_line = tx->get_selection_to_line(); - int to_column = tx->get_selection_to_column(); - - for (int i = to_line; i >= from_line; i--) { - int line_id = i; - int next_id = i + 1; - - if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) - return; - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - int from_line_down = from_line < tx->get_line_count() ? from_line + 1 : from_line; - int to_line_down = to_line < tx->get_line_count() ? to_line + 1 : to_line; - tx->select(from_line_down, from_col, to_line_down, to_column); - } else { - int line_id = tx->cursor_get_line(); - int next_id = line_id + 1; - - if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count()) - return; - - tx->swap_lines(line_id, next_id); - tx->cursor_set_line(next_id); - } - tx->end_complex_operation(); - tx->update(); - + shader_editor->move_lines_down(); } break; case EDIT_INDENT_LEFT: { @@ -356,55 +282,10 @@ void ShaderEditor::_menu_option(int p_option) { } break; case EDIT_DELETE_LINE: { - - TextEdit *tx = shader_editor->get_text_edit(); - if (shader.is_null()) - return; - - tx->begin_complex_operation(); - int line = tx->cursor_get_line(); - tx->set_line(tx->cursor_get_line(), ""); - tx->backspace_at_cursor(); - tx->cursor_set_line(line); - tx->end_complex_operation(); - + shader_editor->delete_lines(); } break; case EDIT_CLONE_DOWN: { - - TextEdit *tx = shader_editor->get_text_edit(); - if (shader.is_null()) - return; - - int from_line = tx->cursor_get_line(); - int to_line = tx->cursor_get_line(); - int column = tx->cursor_get_column(); - - if (tx->is_selection_active()) { - from_line = tx->get_selection_from_line(); - to_line = tx->get_selection_to_line(); - column = tx->cursor_get_column(); - } - int next_line = to_line + 1; - - tx->begin_complex_operation(); - for (int i = from_line; i <= to_line; i++) { - - if (i >= tx->get_line_count() - 1) { - tx->set_line(i, tx->get_line(i) + "\n"); - } - String line_clone = tx->get_line(i); - tx->insert_at(line_clone, next_line); - next_line++; - } - - tx->cursor_set_column(column); - if (tx->is_selection_active()) { - tx->select(to_line + 1, tx->get_selection_from_column(), next_line - 1, tx->get_selection_to_column()); - } - - tx->end_complex_operation(); - tx->update(); - + shader_editor->code_lines_down(); } break; case EDIT_TOGGLE_COMMENT: { diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp new file mode 100644 index 0000000000..16c25f3074 --- /dev/null +++ b/editor/plugins/text_editor.cpp @@ -0,0 +1,607 @@ +/*************************************************************************/ +/* text_editor.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "text_editor.h" + +void TextEditor::add_syntax_highlighter(SyntaxHighlighter *p_highlighter) { + highlighters[p_highlighter->get_name()] = p_highlighter; + highlighter_menu->add_radio_check_item(p_highlighter->get_name()); +} + +void TextEditor::set_syntax_highlighter(SyntaxHighlighter *p_highlighter) { + TextEdit *te = code_editor->get_text_edit(); + te->_set_syntax_highlighting(p_highlighter); + if (p_highlighter != NULL) { + highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->get_name()), true); + } else { + highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text("Standard"), true); + } + + // little work around. GDScript highlighter goes through text_edit for colours, + // so to remove all colours we need to set and unset them here. + if (p_highlighter == NULL) { // standard + TextEdit *text_edit = code_editor->get_text_edit(); + text_edit->add_color_override("number_color", colors_cache.font_color); + text_edit->add_color_override("function_color", colors_cache.font_color); + text_edit->add_color_override("number_color", colors_cache.font_color); + text_edit->add_color_override("member_variable_color", colors_cache.font_color); + } else { + _load_theme_settings(); + } +} + +void TextEditor::_change_syntax_highlighter(int p_idx) { + Map<String, SyntaxHighlighter *>::Element *el = highlighters.front(); + while (el != NULL) { + highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false); + el = el->next(); + } + set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]); +} + +void TextEditor::_load_theme_settings() { + + TextEdit *text_edit = code_editor->get_text_edit(); + text_edit->clear_colors(); + + Color background_color = EDITOR_GET("text_editor/highlighting/background_color"); + Color completion_background_color = EDITOR_GET("text_editor/highlighting/completion_background_color"); + Color completion_selected_color = EDITOR_GET("text_editor/highlighting/completion_selected_color"); + Color completion_existing_color = EDITOR_GET("text_editor/highlighting/completion_existing_color"); + Color completion_scroll_color = EDITOR_GET("text_editor/highlighting/completion_scroll_color"); + Color completion_font_color = EDITOR_GET("text_editor/highlighting/completion_font_color"); + Color text_color = EDITOR_GET("text_editor/highlighting/text_color"); + Color line_number_color = EDITOR_GET("text_editor/highlighting/line_number_color"); + Color caret_color = EDITOR_GET("text_editor/highlighting/caret_color"); + Color caret_background_color = EDITOR_GET("text_editor/highlighting/caret_background_color"); + Color text_selected_color = EDITOR_GET("text_editor/highlighting/text_selected_color"); + Color selection_color = EDITOR_GET("text_editor/highlighting/selection_color"); + Color brace_mismatch_color = EDITOR_GET("text_editor/highlighting/brace_mismatch_color"); + Color current_line_color = EDITOR_GET("text_editor/highlighting/current_line_color"); + Color line_length_guideline_color = EDITOR_GET("text_editor/highlighting/line_length_guideline_color"); + Color word_highlighted_color = EDITOR_GET("text_editor/highlighting/word_highlighted_color"); + Color number_color = EDITOR_GET("text_editor/highlighting/number_color"); + Color function_color = EDITOR_GET("text_editor/highlighting/function_color"); + Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); + Color mark_color = EDITOR_GET("text_editor/highlighting/mark_color"); + Color breakpoint_color = EDITOR_GET("text_editor/highlighting/breakpoint_color"); + Color code_folding_color = EDITOR_GET("text_editor/highlighting/code_folding_color"); + Color search_result_color = EDITOR_GET("text_editor/highlighting/search_result_color"); + Color search_result_border_color = EDITOR_GET("text_editor/highlighting/search_result_border_color"); + Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); + Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); + Color basetype_color = EDITOR_GET("text_editor/highlighting/base_type_color"); + Color type_color = EDITOR_GET("text_editor/highlighting/engine_type_color"); + Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); + Color string_color = EDITOR_GET("text_editor/highlighting/string_color"); + + text_edit->add_color_override("background_color", background_color); + text_edit->add_color_override("completion_background_color", completion_background_color); + text_edit->add_color_override("completion_selected_color", completion_selected_color); + text_edit->add_color_override("completion_existing_color", completion_existing_color); + text_edit->add_color_override("completion_scroll_color", completion_scroll_color); + text_edit->add_color_override("completion_font_color", completion_font_color); + text_edit->add_color_override("font_color", text_color); + text_edit->add_color_override("line_number_color", line_number_color); + text_edit->add_color_override("caret_color", caret_color); + text_edit->add_color_override("caret_background_color", caret_background_color); + text_edit->add_color_override("font_selected_color", text_selected_color); + text_edit->add_color_override("selection_color", selection_color); + text_edit->add_color_override("brace_mismatch_color", brace_mismatch_color); + text_edit->add_color_override("current_line_color", current_line_color); + text_edit->add_color_override("line_length_guideline_color", line_length_guideline_color); + text_edit->add_color_override("word_highlighted_color", word_highlighted_color); + text_edit->add_color_override("number_color", number_color); + text_edit->add_color_override("function_color", function_color); + text_edit->add_color_override("member_variable_color", member_variable_color); + text_edit->add_color_override("breakpoint_color", breakpoint_color); + text_edit->add_color_override("mark_color", mark_color); + text_edit->add_color_override("code_folding_color", code_folding_color); + text_edit->add_color_override("search_result_color", search_result_color); + text_edit->add_color_override("search_result_border_color", search_result_border_color); + text_edit->add_color_override("symbol_color", symbol_color); + + text_edit->add_constant_override("line_spacing", EDITOR_DEF("text_editor/theme/line_spacing", 4)); + + colors_cache.font_color = text_color; + colors_cache.symbol_color = symbol_color; + colors_cache.keyword_color = keyword_color; + colors_cache.basetype_color = basetype_color; + colors_cache.type_color = type_color; + colors_cache.comment_color = comment_color; + colors_cache.string_color = string_color; +} + +String TextEditor::get_name() { + String name; + + if (text_file->get_path().find("local://") == -1 && text_file->get_path().find("::") == -1) { + name = text_file->get_path().get_file(); + if (is_unsaved()) { + name += "(*)"; + } + } else if (text_file->get_name() != "") { + name = text_file->get_name(); + } else { + name = text_file->get_class() + "(" + itos(text_file->get_instance_id()) + ")"; + } + + return name; +} + +Ref<Texture> TextEditor::get_icon() { + + if (get_parent_control() && get_parent_control()->has_icon(text_file->get_class(), "EditorIcons")) { + return get_parent_control()->get_icon(text_file->get_class(), "EditorIcons"); + } + return Ref<Texture>(); +} + +RES TextEditor::get_edited_resource() const { + return text_file; +} + +void TextEditor::set_edited_resource(const RES &p_res) { + ERR_FAIL_COND(!text_file.is_null()); + + text_file = p_res; + + code_editor->get_text_edit()->set_text(text_file->get_text()); + code_editor->get_text_edit()->clear_undo_history(); + code_editor->get_text_edit()->tag_saved_version(); + + emit_signal("name_changed"); + code_editor->update_line_and_column(); +} + +void TextEditor::add_callback(const String &p_function, PoolStringArray p_args) { +} + +void TextEditor::set_debugger_active(bool p_active) { +} + +void TextEditor::get_breakpoints(List<int> *p_breakpoints) { +} + +void TextEditor::reload_text() { + + ERR_FAIL_COND(text_file.is_null()); + + TextEdit *te = code_editor->get_text_edit(); + int column = te->cursor_get_column(); + int row = te->cursor_get_line(); + int h = te->get_h_scroll(); + int v = te->get_v_scroll(); + + te->set_text(text_file->get_text()); + te->clear_undo_history(); + te->cursor_set_line(row); + te->cursor_set_column(column); + te->set_h_scroll(h); + te->set_v_scroll(v); + + te->tag_saved_version(); + + code_editor->update_line_and_column(); +} + +void TextEditor::_validate_script() { + emit_signal("name_changed"); + emit_signal("edited_script_changed"); +} + +void TextEditor::apply_code() { + text_file->set_text(code_editor->get_text_edit()->get_text()); +} + +bool TextEditor::is_unsaved() { + + return code_editor->get_text_edit()->get_version() != code_editor->get_text_edit()->get_saved_version(); +} + +Variant TextEditor::get_edit_state() { + + return code_editor->get_edit_state(); +} + +void TextEditor::set_edit_state(const Variant &p_state) { + + code_editor->set_edit_state(p_state); +} + +void TextEditor::trim_trailing_whitespace() { + + code_editor->trim_trailing_whitespace(); +} + +void TextEditor::convert_indent_to_spaces() { + + code_editor->convert_indent_to_spaces(); +} + +void TextEditor::convert_indent_to_tabs() { + + code_editor->convert_indent_to_tabs(); +} + +void TextEditor::tag_saved_version() { + + code_editor->get_text_edit()->tag_saved_version(); +} + +void TextEditor::goto_line(int p_line, bool p_with_error) { + + code_editor->goto_line(p_line); +} + +void TextEditor::ensure_focus() { + + code_editor->get_text_edit()->grab_focus(); +} + +Vector<String> TextEditor::get_functions() { + + return Vector<String>(); +} + +bool TextEditor::show_members_overview() { + return true; +} + +void TextEditor::update_settings() { + + code_editor->update_editor_settings(); +} + +void TextEditor::set_tooltip_request_func(String p_method, Object *p_obj) { + + code_editor->get_text_edit()->set_tooltip_request_func(p_obj, p_method, this); +} + +Control *TextEditor::get_edit_menu() { + + return edit_hb; +} + +void TextEditor::clear_edit_menu() { + memdelete(edit_hb); +} + +void TextEditor::_notification(int p_what) { + + switch (p_what) { + case NOTIFICATION_READY: + _load_theme_settings(); + set_syntax_highlighter(NULL); + break; + } +} + +void TextEditor::_edit_option(int p_op) { + TextEdit *tx = code_editor->get_text_edit(); + + switch (p_op) { + case EDIT_UNDO: { + + tx->undo(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_REDO: { + + tx->redo(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_CUT: { + + tx->cut(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_COPY: { + + tx->copy(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_PASTE: { + + tx->paste(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_SELECT_ALL: { + + tx->select_all(); + tx->call_deferred("grab_focus"); + } break; + case EDIT_MOVE_LINE_UP: { + + code_editor->move_lines_up(); + } break; + case EDIT_MOVE_LINE_DOWN: { + + code_editor->move_lines_down(); + } break; + case EDIT_INDENT_LEFT: { + + tx->indent_left(); + } break; + case EDIT_INDENT_RIGHT: { + + tx->indent_right(); + } break; + case EDIT_DELETE_LINE: { + + code_editor->delete_lines(); + } break; + case EDIT_CLONE_DOWN: { + + code_editor->code_lines_down(); + } break; + case EDIT_TOGGLE_FOLD_LINE: { + + tx->toggle_fold_line(tx->cursor_get_line()); + tx->update(); + } break; + case EDIT_FOLD_ALL_LINES: { + + tx->fold_all_lines(); + tx->update(); + } break; + case EDIT_UNFOLD_ALL_LINES: { + + tx->unhide_all_lines(); + tx->update(); + } break; + case EDIT_TRIM_TRAILING_WHITESAPCE: { + + trim_trailing_whitespace(); + } break; + case EDIT_CONVERT_INDENT_TO_SPACES: { + + convert_indent_to_spaces(); + } break; + case EDIT_CONVERT_INDENT_TO_TABS: { + + convert_indent_to_tabs(); + } break; + case EDIT_TO_UPPERCASE: { + + _convert_case(CodeTextEditor::UPPER); + } break; + case EDIT_TO_LOWERCASE: { + + _convert_case(CodeTextEditor::LOWER); + } break; + case EDIT_CAPITALIZE: { + + _convert_case(CodeTextEditor::CAPITALIZE); + } break; + case SEARCH_FIND: { + + code_editor->get_find_replace_bar()->popup_search(); + } break; + case SEARCH_FIND_NEXT: { + + code_editor->get_find_replace_bar()->search_next(); + } break; + case SEARCH_FIND_PREV: { + + code_editor->get_find_replace_bar()->search_prev(); + } break; + case SEARCH_REPLACE: { + + code_editor->get_find_replace_bar()->popup_replace(); + } break; + case SEARCH_GOTO_LINE: { + + goto_line_dialog->popup_find_line(tx); + } break; + } +} + +void TextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { + + code_editor->convert_case(p_case); +} + +void TextEditor::_bind_methods() { + + ClassDB::bind_method("_validate_script", &TextEditor::_validate_script); + ClassDB::bind_method("_load_theme_settings", &TextEditor::_load_theme_settings); + ClassDB::bind_method("_edit_option", &TextEditor::_edit_option); + ClassDB::bind_method("_change_syntax_highlighter", &TextEditor::_change_syntax_highlighter); + ClassDB::bind_method("_text_edit_gui_input", &TextEditor::_text_edit_gui_input); +} + +static ScriptEditorBase *create_editor(const RES &p_resource) { + + if (Object::cast_to<TextFile>(*p_resource)) { + return memnew(TextEditor); + } + return NULL; +} + +void TextEditor::register_editor() { + + ScriptEditor::register_create_script_editor_function(create_editor); +} + +void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { + + Ref<InputEventMouseButton> mb = ev; + + if (mb.is_valid()) { + if (mb->get_button_index() == BUTTON_RIGHT) { + + int col, row; + TextEdit *tx = code_editor->get_text_edit(); + tx->_get_mouse_pos(mb->get_global_position() - tx->get_global_position(), row, col); + + tx->set_right_click_moves_caret(EditorSettings::get_singleton()->get("text_editor/cursor/right_click_moves_caret")); + bool can_fold = tx->can_fold(row); + bool is_folded = tx->is_folded(row); + + if (tx->is_right_click_moving_caret()) { + if (tx->is_selection_active()) { + + int from_line = tx->get_selection_from_line(); + int to_line = tx->get_selection_to_line(); + int from_column = tx->get_selection_from_column(); + int to_column = tx->get_selection_to_column(); + + if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) { + // Right click is outside the seleted text + tx->deselect(); + } + } + if (!tx->is_selection_active()) { + tx->cursor_set_line(row, true, false); + tx->cursor_set_column(col); + } + } + + if (!mb->is_pressed()) { + _make_context_menu(tx->is_selection_active(), can_fold, is_folded); + } + } + } +} + +void TextEditor::_make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded) { + + context_menu->clear(); + if (p_selection) { + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY); + } + + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE); + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); + + if (p_selection) { + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE); + } + if (p_can_fold || p_is_folded) + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); + + context_menu->set_position(get_global_transform().xform(get_local_mouse_position())); + context_menu->set_size(Vector2(1, 1)); + context_menu->popup(); +} + +TextEditor::TextEditor() { + code_editor = memnew(CodeTextEditor); + add_child(code_editor); + code_editor->add_constant_override("separation", 0); + code_editor->connect("load_theme_settings", this, "_load_theme_settings"); + code_editor->connect("validate_script", this, "_validate_script"); + code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + code_editor->set_v_size_flags(Control::SIZE_EXPAND_FILL); + + update_settings(); + + code_editor->get_text_edit()->set_context_menu_enabled(false); + code_editor->get_text_edit()->connect("gui_input", this, "_text_edit_gui_input"); + + context_menu = memnew(PopupMenu); + add_child(context_menu); + context_menu->connect("id_pressed", this, "_edit_option"); + + edit_hb = memnew(HBoxContainer); + + search_menu = memnew(MenuButton); + edit_hb->add_child(search_menu); + search_menu->set_text(TTR("Search")); + search_menu->get_popup()->connect("id_pressed", this, "_edit_option"); + + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); + search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); + + goto_line_dialog = memnew(GotoLineDialog); + add_child(goto_line_dialog); + + edit_menu = memnew(MenuButton); + edit_menu->set_text(TTR("Edit")); + edit_menu->get_popup()->connect("id_pressed", this, "_edit_option"); + + edit_hb->add_child(edit_menu); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_up"), EDIT_MOVE_LINE_UP); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/move_down"), EDIT_MOVE_LINE_DOWN); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/delete_line"), EDIT_DELETE_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES); + edit_menu->get_popup()->add_separator(); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS); + + edit_menu->get_popup()->add_separator(); + PopupMenu *convert_case = memnew(PopupMenu); + convert_case->set_name("convert_case"); + edit_menu->get_popup()->add_child(convert_case); + edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case"); + convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase")), EDIT_TO_UPPERCASE); + convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_lowercase", TTR("Lowercase")), EDIT_TO_LOWERCASE); + convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize")), EDIT_CAPITALIZE); + convert_case->connect("id_pressed", this, "_edit_option"); + + highlighters["Standard"] = NULL; + highlighter_menu = memnew(PopupMenu); + highlighter_menu->set_name("highlighter_menu"); + edit_menu->get_popup()->add_child(highlighter_menu); + edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "highlighter_menu"); + highlighter_menu->add_radio_check_item(TTR("Standard")); + highlighter_menu->connect("id_pressed", this, "_change_syntax_highlighter"); + + code_editor->get_text_edit()->set_drag_forwarding(this); +} diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h new file mode 100644 index 0000000000..8b1983d891 --- /dev/null +++ b/editor/plugins/text_editor.h @@ -0,0 +1,146 @@ +/*************************************************************************/ +/* text_editor.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEXT_EDITOR_H +#define TEXT_EDITOR_H + +#include "script_editor_plugin.h" + +class TextEditor : public ScriptEditorBase { + + GDCLASS(TextEditor, ScriptEditorBase) + +private: + CodeTextEditor *code_editor; + + Ref<TextFile> text_file; + + HBoxContainer *edit_hb; + MenuButton *edit_menu; + PopupMenu *highlighter_menu; + MenuButton *search_menu; + PopupMenu *context_menu; + + GotoLineDialog *goto_line_dialog; + + struct ColorsCache { + Color font_color; + Color symbol_color; + Color keyword_color; + Color basetype_color; + Color type_color; + Color comment_color; + Color string_color; + } colors_cache; + + enum { + EDIT_UNDO, + EDIT_REDO, + EDIT_CUT, + EDIT_COPY, + EDIT_PASTE, + EDIT_SELECT_ALL, + EDIT_TRIM_TRAILING_WHITESAPCE, + EDIT_CONVERT_INDENT_TO_SPACES, + EDIT_CONVERT_INDENT_TO_TABS, + EDIT_MOVE_LINE_UP, + EDIT_MOVE_LINE_DOWN, + EDIT_INDENT_RIGHT, + EDIT_INDENT_LEFT, + EDIT_DELETE_LINE, + EDIT_CLONE_DOWN, + EDIT_TO_UPPERCASE, + EDIT_TO_LOWERCASE, + EDIT_CAPITALIZE, + EDIT_TOGGLE_FOLD_LINE, + EDIT_FOLD_ALL_LINES, + EDIT_UNFOLD_ALL_LINES, + SEARCH_FIND, + SEARCH_FIND_NEXT, + SEARCH_FIND_PREV, + SEARCH_REPLACE, + SEARCH_GOTO_LINE, + }; + +protected: + static void _bind_methods(); + + void _notification(int p_what); + + void _edit_option(int p_op); + void _make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded); + void _text_edit_gui_input(const Ref<InputEvent> &ev); + + Map<String, SyntaxHighlighter *> highlighters; + void _change_syntax_highlighter(int p_idx); + void _load_theme_settings(); + + void _convert_case(CodeTextEditor::CaseStyle p_case); + + void _validate_script(); + +public: + virtual void add_syntax_highlighter(SyntaxHighlighter *p_highlighter); + virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter); + + virtual String get_name(); + virtual Ref<Texture> get_icon(); + virtual RES get_edited_resource() const; + virtual void set_edited_resource(const RES &p_res); + void set_edited_file(const Ref<TextFile> &p_file); + virtual void reload_text(); + virtual void apply_code(); + virtual bool is_unsaved(); + virtual Variant get_edit_state(); + virtual void set_edit_state(const Variant &p_state); + virtual Vector<String> get_functions(); + virtual void get_breakpoints(List<int> *p_breakpoints); + virtual void goto_line(int p_line, bool p_with_error = false); + virtual void trim_trailing_whitespace(); + virtual void convert_indent_to_spaces(); + virtual void convert_indent_to_tabs(); + virtual void ensure_focus(); + virtual void tag_saved_version(); + virtual void update_settings(); + virtual bool show_members_overview(); + virtual bool can_lose_focus_on_node_selection() { return true; } + virtual void set_debugger_active(bool p_active); + virtual void set_tooltip_request_func(String p_method, Object *p_obj); + virtual void add_callback(const String &p_function, PoolStringArray p_args); + + virtual Control *get_edit_menu(); + virtual void clear_edit_menu(); + + static void register_editor(); + + TextEditor(); +}; + +#endif // TEXT_EDITOR_H diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 873cc293c9..cad6128eca 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -1962,22 +1962,16 @@ void VisualScriptEditor::_button_resource_previewed(const String &p_path, const void VisualScriptEditor::apply_code() { } -Ref<Script> VisualScriptEditor::get_edited_script() const { - +RES VisualScriptEditor::get_edited_resource() const { return script; } -Vector<String> VisualScriptEditor::get_functions() { - - return Vector<String>(); -} - -void VisualScriptEditor::set_edited_script(const Ref<Script> &p_script) { +void VisualScriptEditor::set_edited_resource(const RES &p_res) { - script = p_script; - signal_editor->script = p_script; + script = p_res; + signal_editor->script = script; signal_editor->undo_redo = undo_redo; - variable_editor->script = p_script; + variable_editor->script = script; variable_editor->undo_redo = undo_redo; script->connect("node_ports_changed", this, "_node_ports_changed"); @@ -1986,6 +1980,11 @@ void VisualScriptEditor::set_edited_script(const Ref<Script> &p_script) { _update_available_nodes(); } +Vector<String> VisualScriptEditor::get_functions() { + + return Vector<String>(); +} + void VisualScriptEditor::reload_text() { } @@ -3515,9 +3514,9 @@ VisualScriptEditor::~VisualScriptEditor() { memdelete(variable_editor); } -static ScriptEditorBase *create_editor(const Ref<Script> &p_script) { +static ScriptEditorBase *create_editor(const RES &p_resource) { - if (Object::cast_to<VisualScript>(*p_script)) { + if (Object::cast_to<VisualScript>(*p_resource)) { return memnew(VisualScriptEditor); } diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index 0bd64d6a1d..843afa8f3c 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -250,9 +250,9 @@ public: virtual void set_syntax_highlighter(SyntaxHighlighter *p_highlighter); virtual void apply_code(); - virtual Ref<Script> get_edited_script() const; + virtual RES get_edited_resource() const; + virtual void set_edited_resource(const RES &p_res); virtual Vector<String> get_functions(); - virtual void set_edited_script(const Ref<Script> &p_script); virtual void reload_text(); virtual String get_name(); virtual Ref<Texture> get_icon(); diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp index 0d69c037fe..a4fd35304a 100644 --- a/scene/register_scene_types.cpp +++ b/scene/register_scene_types.cpp @@ -156,6 +156,7 @@ #include "scene/resources/sky_box.h" #include "scene/resources/sphere_shape.h" #include "scene/resources/surface_tool.h" +#include "scene/resources/text_file.h" #include "scene/resources/texture.h" #include "scene/resources/tile_set.h" #include "scene/resources/video_stream.h" @@ -617,6 +618,8 @@ void register_scene_types() { ClassDB::register_class<BitmapFont>(); ClassDB::register_class<Curve>(); + ClassDB::register_class<TextFile>(); + ClassDB::register_class<DynamicFontData>(); ClassDB::register_class<DynamicFont>(); diff --git a/scene/resources/text_file.cpp b/scene/resources/text_file.cpp new file mode 100644 index 0000000000..e2fe0adfc5 --- /dev/null +++ b/scene/resources/text_file.cpp @@ -0,0 +1,77 @@ +/*************************************************************************/ +/* text_file.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "text_file.h" + +#include "os/file_access.h" + +bool TextFile::has_text() const { + return text != ""; +} + +String TextFile::get_text() const { + return text; +} + +void TextFile::set_text(const String &p_code) { + text = p_code; +} + +void TextFile::reload_from_file() { + load_text(path); +} + +Error TextFile::load_text(const String &p_path) { + + PoolVector<uint8_t> sourcef; + Error err; + FileAccess *f = FileAccess::open(p_path, FileAccess::READ, &err); + if (err) { + ERR_FAIL_COND_V(err, err); + } + + int len = f->get_len(); + sourcef.resize(len + 1); + PoolVector<uint8_t>::Write w = sourcef.write(); + int r = f->get_buffer(w.ptr(), len); + f->close(); + memdelete(f); + ERR_FAIL_COND_V(r != len, ERR_CANT_OPEN); + w[len] = 0; + + String s; + if (s.parse_utf8((const char *)w.ptr())) { + ERR_EXPLAIN("Script '" + p_path + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode."); + ERR_FAIL_V(ERR_INVALID_DATA); + } + text = s; + path = p_path; + return OK; +} diff --git a/scene/resources/text_file.h b/scene/resources/text_file.h new file mode 100644 index 0000000000..40b648eebb --- /dev/null +++ b/scene/resources/text_file.h @@ -0,0 +1,55 @@ +/*************************************************************************/ +/* text_file.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEXTFILE_H +#define TEXTFILE_H + +#include "io/resource_loader.h" +#include "io/resource_saver.h" + +class TextFile : public Resource { + + GDCLASS(TextFile, Resource) + +private: + String text; + String path; + +public: + virtual bool has_text() const; + virtual String get_text() const; + virtual void set_text(const String &p_code); + virtual void reload_from_file(); + + void set_file_path(const String &p_path) { path = p_path; } + Error load_text(const String &p_path); +}; + +#endif // TEXTFILE_H |