summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/io/translation_loader_po.cpp40
-rw-r--r--doc/classes/EditorImportPlugin.xml11
-rw-r--r--editor/code_editor.cpp339
-rw-r--r--editor/code_editor.h23
-rw-r--r--editor/editor_node.cpp2
-rw-r--r--editor/inspector_dock.cpp1
-rw-r--r--editor/plugins/script_editor_plugin.cpp371
-rw-r--r--editor/plugins/script_editor_plugin.h20
-rw-r--r--editor/plugins/script_text_editor.cpp419
-rw-r--r--editor/plugins/script_text_editor.h12
-rw-r--r--editor/plugins/shader_editor_plugin.cpp127
-rw-r--r--editor/plugins/text_editor.cpp607
-rw-r--r--editor/plugins/text_editor.h146
-rw-r--r--editor/plugins/tile_map_editor_plugin.cpp10
-rw-r--r--editor/scene_tree_dock.cpp6
-rw-r--r--editor/scene_tree_dock.h2
-rw-r--r--misc/dist/linux/org.godotengine.Godot.appdata.xml (renamed from misc/dist/linux/godot.appdata.xml)8
-rw-r--r--misc/dist/linux/org.godotengine.Godot.desktop (renamed from misc/dist/linux/godot.desktop)2
-rw-r--r--modules/visual_script/visual_script.cpp13
-rw-r--r--modules/visual_script/visual_script.h1
-rw-r--r--modules/visual_script/visual_script_editor.cpp473
-rw-r--r--modules/visual_script/visual_script_editor.h43
-rw-r--r--modules/visual_script/visual_script_flow_control.cpp2
-rw-r--r--modules/visual_script/visual_script_func_nodes.cpp8
-rw-r--r--modules/visual_script/visual_script_nodes.cpp2
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp705
-rw-r--r--modules/visual_script/visual_script_property_selector.h92
-rw-r--r--platform/windows/context_gl_win.cpp4
-rw-r--r--scene/2d/canvas_item.cpp3
-rw-r--r--scene/animation/tween.cpp67
-rw-r--r--scene/animation/tween.h4
-rw-r--r--scene/gui/graph_edit.cpp26
-rw-r--r--scene/gui/graph_edit.h6
-rw-r--r--scene/gui/texture_progress.cpp29
-rw-r--r--scene/gui/texture_progress.h5
-rw-r--r--scene/register_scene_types.cpp3
-rw-r--r--scene/resources/default_theme/default_theme.cpp4
-rw-r--r--scene/resources/text_file.cpp77
-rw-r--r--scene/resources/text_file.h55
39 files changed, 2894 insertions, 874 deletions
diff --git a/core/io/translation_loader_po.cpp b/core/io/translation_loader_po.cpp
index 16d5e3c282..85c1fc5ddf 100644
--- a/core/io/translation_loader_po.cpp
+++ b/core/io/translation_loader_po.cpp
@@ -54,32 +54,25 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
int line = 1;
bool skip_this = false;
bool skip_next = false;
+ bool is_eof = false;
- while (true) {
+ while (!is_eof) {
- String l = f->get_line();
+ String l = f->get_line().strip_edges();
+ is_eof = f->eof_reached();
- if (f->eof_reached()) {
+ // If we reached last line and it's not a content line, break, otherwise let processing that last loop
+ if (is_eof && l.empty()) {
- if (status == STATUS_READING_STRING) {
-
- if (msg_id != "") {
- if (!skip_this)
- translation->add_message(msg_id, msg_str);
- } else if (config == "")
- config = msg_str;
- break;
-
- } else if (status == STATUS_NONE)
+ if (status == STATUS_READING_ID) {
+ memdelete(f);
+ ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: ");
+ ERR_FAIL_V(RES());
+ } else {
break;
-
- memdelete(f);
- ERR_EXPLAIN(p_path + ":" + itos(line) + " Unexpected EOF while reading 'msgid' at file: ");
- ERR_FAIL_V(RES());
+ }
}
- l = l.strip_edges();
-
if (l.begins_with("msgid")) {
if (status == STATUS_READING_ID) {
@@ -160,6 +153,15 @@ RES TranslationLoaderPO::load_translation(FileAccess *f, Error *r_error, const S
f->close();
memdelete(f);
+ if (status == STATUS_READING_STRING) {
+
+ if (msg_id != "") {
+ if (!skip_this)
+ translation->add_message(msg_id, msg_str);
+ } else if (config == "")
+ config = msg_str;
+ }
+
if (config == "") {
ERR_EXPLAIN("No config found in file: " + p_path);
ERR_FAIL_V(RES());
diff --git a/doc/classes/EditorImportPlugin.xml b/doc/classes/EditorImportPlugin.xml
index e48eb82691..b21d402468 100644
--- a/doc/classes/EditorImportPlugin.xml
+++ b/doc/classes/EditorImportPlugin.xml
@@ -35,19 +35,20 @@
func get_import_options(i):
return [{"name": "my_option", "default_value": false}]
- func load(src, dst, opts, r_platform_variants, r_gen_files):
+ func import(source_file, save_path, options, r_platform_variants, r_gen_files):
var file = File.new()
- if file.open(src, File.READ) != OK:
+ if file.open(source_file, File.READ) != OK:
return FAILED
var mesh = Mesh.new()
- var save = dst + "." + get_save_extension()
- ResourceSaver.save(file, mesh)
+ var filename = save_path + "." + get_save_extension()
+ ResourceSaver.save(filename, mesh)
return OK
[/codeblock]
</description>
<tutorials>
+ <link>http://docs.godotengine.org/en/3.0/tutorials/plugins/editor/import_plugins.html</link>
</tutorials>
<demos>
</demos>
@@ -119,7 +120,7 @@
<return type="String">
</return>
<description>
- Get the godot resource type associated with this loader. e.g. "Mesh" or "Animation".
+ Get the Godot resource type associated with this loader. e.g. "Mesh" or "Animation".
</description>
</method>
<method name="get_save_extension" qualifiers="virtual">
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/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp
index 19646f37b5..484da3b4f3 100644
--- a/editor/plugins/tile_map_editor_plugin.cpp
+++ b/editor/plugins/tile_map_editor_plugin.cpp
@@ -526,7 +526,7 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era
if (!erase) {
ids = get_selected_tiles();
- if (ids.size() == 0 && ids[0] == TileMap::INVALID_CELL)
+ if (ids.size() == 0 || ids[0] == TileMap::INVALID_CELL)
return PoolVector<Vector2>();
} else if (prev_id == TileMap::INVALID_CELL) {
return PoolVector<Vector2>();
@@ -538,9 +538,7 @@ PoolVector<Vector2> TileMapEditor::_bucket_fill(const Point2i &p_start, bool era
}
}
- Rect2i r = node->_edit_get_rect();
- r.position = r.position / node->get_cell_size();
- r.size = r.size / node->get_cell_size();
+ Rect2i r = node->get_used_rect();
int area = r.get_area();
if (preview) {
@@ -1029,7 +1027,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (points.size() == 0)
return false;
- undo_redo->create_action(TTR("Bucket Fill"));
+ _start_undo(TTR("Bucket Fill"));
Dictionary op;
op["id"] = get_selected_tiles();
@@ -1039,7 +1037,7 @@ bool TileMapEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
_fill_points(points, op);
- undo_redo->commit_action();
+ _finish_undo();
// We want to keep the bucket-tool active
return true;
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 2ffaa0ca12..8d38bf39b5 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -724,7 +724,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
}
}
} break;
- case TOOL_SCENE_CLEAR_INSTANCING: {
+ case TOOL_SCENE_MAKE_LOCAL: {
List<Node *> selection = editor_selection->get_selected_node_list();
List<Node *>::Element *e = selection.front();
if (e) {
@@ -736,7 +736,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
ERR_FAIL_COND(node->get_filename() == String());
- undo_redo->create_action(TTR("Discard Instancing"));
+ undo_redo->create_action(TTR("Make Local"));
undo_redo->add_do_method(node, "set_filename", "");
undo_redo->add_undo_method(node, "set_filename", node->get_filename());
_node_replace_owner(node, node, root);
@@ -2028,7 +2028,7 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
bool placeholder = selection[0]->get_scene_instance_load_placeholder();
menu->add_check_item(TTR("Editable Children"), TOOL_SCENE_EDITABLE_CHILDREN);
menu->add_check_item(TTR("Load As Placeholder"), TOOL_SCENE_USE_PLACEHOLDER);
- menu->add_item(TTR("Discard Instancing"), TOOL_SCENE_CLEAR_INSTANCING);
+ menu->add_item(TTR("Make Local"), TOOL_SCENE_MAKE_LOCAL);
menu->add_icon_item(get_icon("Load", "EditorIcons"), TTR("Open in Editor"), TOOL_SCENE_OPEN);
menu->set_item_checked(menu->get_item_idx_from_text(TTR("Editable Children")), editable);
menu->set_item_checked(menu->get_item_idx_from_text(TTR("Load As Placeholder")), placeholder);
diff --git a/editor/scene_tree_dock.h b/editor/scene_tree_dock.h
index fd74611bde..57f4759747 100644
--- a/editor/scene_tree_dock.h
+++ b/editor/scene_tree_dock.h
@@ -77,7 +77,7 @@ class SceneTreeDock : public VBoxContainer {
TOOL_BUTTON_MAX,
TOOL_SCENE_EDITABLE_CHILDREN,
TOOL_SCENE_USE_PLACEHOLDER,
- TOOL_SCENE_CLEAR_INSTANCING,
+ TOOL_SCENE_MAKE_LOCAL,
TOOL_SCENE_OPEN,
TOOL_SCENE_CLEAR_INHERITANCE,
TOOL_SCENE_CLEAR_INHERITANCE_CONFIRM,
diff --git a/misc/dist/linux/godot.appdata.xml b/misc/dist/linux/org.godotengine.Godot.appdata.xml
index a381556025..8278f1f6f5 100644
--- a/misc/dist/linux/godot.appdata.xml
+++ b/misc/dist/linux/org.godotengine.Godot.appdata.xml
@@ -1,11 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2017-2018 Rémi Verschelde <akien@godotengine.org> -->
<component type="desktop">
- <id>godot.desktop</id>
+ <id>org.godotengine.Godot.desktop</id>
<metadata_license>CC0-1.0</metadata_license>
<project_license>MIT</project_license>
<name>Godot Engine</name>
<summary>Multi-platform 2D and 3D game engine with a feature-rich editor</summary>
+ <icon type="remote">https://raw.githubusercontent.com/godotengine/godot/master/icon.png</icon>
+ ​<launchable type="desktop-id">org.godotengine.Godot.desktop</launchable>
<description>
<p>
Godot is an advanced, feature-packed, multi-platform 2D and 3D game
@@ -24,8 +26,12 @@
<image>https://download.tuxfamily.org/godotengine/media/screenshots/editor_3d_fracteed-720p.jpg</image>
</screenshot>
</screenshots>
+ <categories>
+ <category>Development</category>
+ </categories>
<url type="homepage">https://godotengine.org</url>
<url type="bugtracker">https://github.com/godotengine/godot/issues</url>
+ <url type="faq">http://docs.godotengine.org/en/latest/about/faq.html</url>
<url type="help">http://docs.godotengine.org</url>
<url type="donation">https://godotengine.org/donate</url>
<url type="translate">https://hosted.weblate.org/projects/godot-engine/godot</url>
diff --git a/misc/dist/linux/godot.desktop b/misc/dist/linux/org.godotengine.Godot.desktop
index 974352b117..439b1d87b8 100644
--- a/misc/dist/linux/godot.desktop
+++ b/misc/dist/linux/org.godotengine.Godot.desktop
@@ -1,7 +1,7 @@
[Desktop Entry]
Name=Godot Engine
GenericName=Libre game engine
-Comment=Multi-platform 2D and 3D game engine with a feature rich editor
+Comment=Multi-platform 2D and 3D game engine with a feature-rich editor
Exec=godot -p
Icon=godot
Terminal=false
diff --git a/modules/visual_script/visual_script.cpp b/modules/visual_script/visual_script.cpp
index af9fea6681..9dea7a9c9e 100644
--- a/modules/visual_script/visual_script.cpp
+++ b/modules/visual_script/visual_script.cpp
@@ -1333,6 +1333,19 @@ VisualScript::VisualScript() {
base_type = "Object";
}
+Set<int> VisualScript::get_output_sequence_ports_connected(const String &edited_func, int from_node) {
+ List<VisualScript::SequenceConnection> *sc = memnew(List<VisualScript::SequenceConnection>);
+ get_sequence_connection_list(edited_func, sc);
+ Set<int> connected;
+ for (List<VisualScript::SequenceConnection>::Element *E = sc->front(); E; E = E->next()) {
+ if (E->get().from_node == from_node) {
+ connected.insert(E->get().from_output);
+ }
+ }
+ memdelete(sc);
+ return connected;
+}
+
VisualScript::~VisualScript() {
while (!functions.empty()) {
diff --git a/modules/visual_script/visual_script.h b/modules/visual_script/visual_script.h
index b163203a3a..2ad72a40c0 100644
--- a/modules/visual_script/visual_script.h
+++ b/modules/visual_script/visual_script.h
@@ -319,6 +319,7 @@ public:
void custom_signal_swap_argument(const StringName &p_func, int p_argidx, int p_with_argidx);
void remove_custom_signal(const StringName &p_name);
void rename_custom_signal(const StringName &p_name, const StringName &p_new_name);
+ Set<int> get_output_sequence_ports_connected(const String &edited_func, int from_node);
void get_custom_signal_list(List<StringName> *r_custom_signals) const;
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 873cc293c9..ad6d32b567 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -33,8 +33,10 @@
#include "core/script_language.h"
#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
+#include "object.h"
#include "os/input.h"
#include "os/keyboard.h"
+#include "variant.h"
#include "visual_script_expression.h"
#include "visual_script_flow_control.h"
#include "visual_script_func_nodes.h"
@@ -1325,6 +1327,12 @@ void VisualScriptEditor::_input(const Ref<InputEvent> &p_event) {
if (mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) {
revert_on_drag = String(); //so we can still drag functions
}
+
+ Ref<InputEventKey> k = p_event;
+ if (k.is_valid() && k->get_scancode() == KEY_A && k->get_shift() && k->is_pressed()) {
+ new_connect_node_select->select_from_visual_script(String(""));
+ accept_event();
+ }
}
void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
@@ -1780,7 +1788,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
call->set_base_type(node->get_class());
n = call;
- method_select->select_method_from_instance(node);
+ method_select->select_from_instance(node);
selecting_method_id = base_id;
}
@@ -1917,7 +1925,7 @@ void VisualScriptEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
}
}
-void VisualScriptEditor::_selected_method(const String &p_method) {
+void VisualScriptEditor::_selected_method(const String &p_method, const String &p_type) {
Ref<VisualScriptFunctionCall> vsfc = script->get_node(edited_func, selecting_method_id);
if (!vsfc.is_valid())
@@ -1962,22 +1970,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_resource(const RES &p_res) {
-void VisualScriptEditor::set_edited_script(const Ref<Script> &p_script) {
-
- 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 +1988,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() {
}
@@ -2436,33 +2443,19 @@ void VisualScriptEditor::_graph_connect_to_empty(const String &p_from, int p_fro
if (!vsn.is_valid())
return;
- if (p_from_slot < vsn->get_output_sequence_port_count()) {
+ port_action_pos = p_release_pos;
- port_action_popup->clear();
- port_action_popup->add_item(TTR("Condition"), CREATE_COND);
- port_action_popup->add_item(TTR("Sequence"), CREATE_SEQUENCE);
- port_action_popup->add_item(TTR("Switch"), CREATE_SWITCH);
- port_action_popup->add_item(TTR("Iterator"), CREATE_ITERATOR);
- port_action_popup->add_item(TTR("While"), CREATE_WHILE);
- port_action_popup->add_item(TTR("Return"), CREATE_RETURN);
+ if (p_from_slot < vsn->get_output_sequence_port_count()) {
port_action_node = p_from.to_int();
port_action_output = p_from_slot;
-
+ _port_action_menu(CREATE_ACTION);
} else {
- port_action_popup->clear();
- port_action_popup->add_item(TTR("Call"), CREATE_CALL);
- port_action_popup->add_item(TTR("Get"), CREATE_GET);
- port_action_popup->add_item(TTR("Set"), CREATE_SET);
port_action_output = p_from_slot - vsn->get_output_sequence_port_count();
port_action_node = p_from.to_int();
+ _port_action_menu(CREATE_CALL_SET_GET);
}
-
- port_action_pos = p_release_pos;
- port_action_popup->set_size(Size2(1, 1));
- port_action_popup->set_position(graph->get_global_position() + p_release_pos);
- port_action_popup->popup();
}
VisualScriptNode::TypeGuess VisualScriptEditor::_guess_output_type(int p_port_action_node, int p_port_action_output, Set<int> &visited_nodes) {
@@ -2530,168 +2523,202 @@ void VisualScriptEditor::_port_action_menu(int p_option) {
bool seq_connect = false;
- Ref<VisualScriptNode> vnode;
Set<int> vn;
switch (p_option) {
- case CREATE_CALL: {
-
+ case CREATE_CALL_SET_GET: {
Ref<VisualScriptFunctionCall> n;
n.instance();
- vnode = n;
VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
- if (tg.type == Variant::OBJECT) {
- n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
-
- if (tg.gdclass != StringName()) {
- n->set_base_type(tg.gdclass);
- } else {
- n->set_base_type("Object");
- }
+ if (tg.gdclass != StringName()) {
+ n->set_base_type(tg.gdclass);
+ } else {
+ n->set_base_type("Object");
+ }
+ String type_string = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
+ if (tg.type == Variant::OBJECT) {
if (tg.script.is_valid()) {
- n->set_base_script(tg.script->get_path());
- new_connect_node_select->select_method_from_script(tg.script);
+ new_connect_node_select->select_from_script(tg.script, "");
+ } else if (type_string != String()) {
+ new_connect_node_select->select_from_base_type(type_string);
} else {
- new_connect_node_select->select_method_from_base_type(n->get_base_type());
+ new_connect_node_select->select_from_base_type(n->get_base_type());
}
-
+ } else if (tg.type == Variant::NIL) {
+ new_connect_node_select->select_from_base_type("");
} else {
- n->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);
- n->set_basic_type(tg.type);
- new_connect_node_select->select_method_from_basic_type(tg.type);
+ new_connect_node_select->select_from_basic_type(tg.type);
}
-
} break;
- case CREATE_SET: {
-
- Ref<VisualScriptPropertySet> n;
- n.instance();
- vnode = n;
-
+ case CREATE_ACTION: {
+ seq_connect = true;
VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
-
+ PropertyInfo property_info = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output);
if (tg.type == Variant::OBJECT) {
- n->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
-
- if (tg.gdclass != StringName()) {
- n->set_base_type(tg.gdclass);
+ if (property_info.type == Variant::OBJECT && property_info.hint_string != String()) {
+ new_connect_node_select->select_from_action(property_info.hint_string);
} else {
- n->set_base_type("Object");
+ new_connect_node_select->select_from_action("");
}
-
- if (tg.script.is_valid()) {
- n->set_base_script(tg.script->get_path());
- new_connect_node_select->select_property_from_script(tg.script);
- } else {
- new_connect_node_select->select_property_from_base_type(n->get_base_type());
- }
-
+ } else if (tg.type == Variant::NIL) {
+ new_connect_node_select->select_from_action("");
} else {
- n->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE);
- n->set_basic_type(tg.type);
- new_connect_node_select->select_property_from_basic_type(tg.type);
+ new_connect_node_select->select_from_action(Variant::get_type_name(tg.type));
}
} break;
- case CREATE_GET: {
+ }
+}
- Ref<VisualScriptPropertyGet> n;
- n.instance();
- vnode = n;
+void VisualScriptEditor::new_node(Ref<VisualScriptNode> vnode, Vector2 ofs) {
+ Set<int> vn;
+ Ref<VisualScriptNode> vnode_old = script->get_node(edited_func, port_action_node);
+ int new_id = script->get_available_id();
+ undo_redo->create_action(TTR("Add Node"));
+ undo_redo->add_do_method(script.ptr(), "add_node", edited_func, new_id, vnode, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", edited_func, new_id);
+ undo_redo->add_do_method(this, "_update_graph", new_id);
+ undo_redo->add_undo_method(this, "_update_graph", new_id);
+ undo_redo->commit_action();
- VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
+ port_action_new_node = new_id;
+}
- if (tg.type == Variant::OBJECT) {
- n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
+void VisualScriptEditor::connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id) {
+ undo_redo->create_action(TTR("Connect Node Data"));
+ VisualScriptReturn *vnode_return = Object::cast_to<VisualScriptReturn>(vnode.ptr());
+ if (vnode_return != NULL && vnode_old->get_output_value_port_count() > 0) {
+ vnode_return->set_enable_return_value(true);
+ }
+ if (vnode_old->get_output_value_port_count() <= 0) {
+ undo_redo->commit_action();
+ return;
+ }
+ if (vnode->get_input_value_port_count() <= 0) {
+ undo_redo->commit_action();
+ return;
+ }
+ int port = port_action_output;
+ int value_count = vnode_old->get_output_value_port_count();
+ if (port >= value_count) {
+ port = 0;
+ }
+ int count = vnode_old->get_output_value_port_count() + vnode_old->get_output_sequence_port_count();
+ undo_redo->add_do_method(script.ptr(), "data_connect", edited_func, port_action_node, port, new_id, 0);
+ undo_redo->add_undo_method(script.ptr(), "data_disconnect", edited_func, port_action_node, port, new_id, 0);
+ undo_redo->commit_action();
+}
- if (tg.gdclass != StringName()) {
- n->set_base_type(tg.gdclass);
- } else {
- n->set_base_type("Object");
- }
+void VisualScriptEditor::_selected_connect_node(const String &p_text, const String &p_category) {
+ Vector2 ofs = graph->get_scroll_ofs() + port_action_pos;
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap, snap));
+ }
+ ofs /= EDSCALE;
- if (tg.script.is_valid()) {
- n->set_base_script(tg.script->get_path());
- new_connect_node_select->select_property_from_script(tg.script);
- } else {
- new_connect_node_select->select_property_from_base_type(n->get_base_type());
- }
+ Set<int> vn;
+ if (p_category == "visualscript") {
+ Ref<VisualScriptNode> vnode_new = VisualScriptLanguage::singleton->create_node_from_name(p_text);
+ Ref<VisualScriptNode> vnode_old = script->get_node(edited_func, port_action_node);
+ int new_id = script->get_available_id();
+
+ if (Object::cast_to<VisualScriptOperator>(vnode_new.ptr())) {
+ Variant::Type type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).type;
+ Object::cast_to<VisualScriptOperator>(vnode_new.ptr())->set_typed(type);
+ }
+
+ if (Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())) {
+ Variant::Type type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).type;
+ String hint_name = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
+
+ if (type == Variant::OBJECT) {
+ Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(hint_name);
+ } else if (type == Variant::NIL) {
+ Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type("");
} else {
- n->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE);
- n->set_basic_type(tg.type);
- new_connect_node_select->select_property_from_basic_type(tg.type);
+ Object::cast_to<VisualScriptTypeCast>(vnode_new.ptr())->set_base_type(Variant::get_type_name(type));
}
+ }
+ undo_redo->create_action(TTR("Add Node"));
+ undo_redo->add_do_method(script.ptr(), "add_node", edited_func, new_id, vnode_new, ofs);
+ connect_seq(vnode_old, vnode_new, new_id);
+ connect_data(vnode_old, vnode_new, new_id);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", edited_func, new_id);
+ undo_redo->add_do_method(this, "_update_graph");
+ undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->commit_action();
+ return;
+ }
- } break;
- case CREATE_COND: {
+ Ref<VisualScriptNode> vnode;
+
+ seq_connect = false;
+ if (p_category == String("method")) {
+
+ Ref<VisualScriptFunctionCall> n;
+ n.instance();
+ vnode = n;
+ } else if (p_category == String("set")) {
+
+ Ref<VisualScriptPropertySet> n;
+ n.instance();
+ n->set_property(p_text);
+ vnode = n;
+ } else if (p_category == String("get")) {
+
+ Ref<VisualScriptPropertyGet> n;
+ n.instance();
+ n->set_property(p_text);
+ vnode = n;
+ }
+
+ if (p_category == String("action")) {
+ if (p_text == "VisualScriptCondition") {
Ref<VisualScriptCondition> n;
n.instance();
vnode = n;
seq_connect = true;
+ }
+ if (p_text == "VisualScriptSwitch") {
- } break;
- case CREATE_SEQUENCE: {
-
- Ref<VisualScriptSequence> n;
+ Ref<VisualScriptSwitch> n;
n.instance();
vnode = n;
seq_connect = true;
+ } else if (p_text == "VisualScriptSequence") {
- } break;
- case CREATE_SWITCH: {
-
- Ref<VisualScriptSwitch> n;
+ Ref<VisualScriptSequence> n;
n.instance();
vnode = n;
seq_connect = true;
-
- } break;
- case CREATE_ITERATOR: {
+ } else if (p_text == "VisualScriptIterator") {
Ref<VisualScriptIterator> n;
n.instance();
vnode = n;
seq_connect = true;
-
- } break;
- case CREATE_WHILE: {
+ } else if (p_text == "VisualScriptWhile") {
Ref<VisualScriptWhile> n;
n.instance();
vnode = n;
seq_connect = true;
-
- } break;
- case CREATE_RETURN: {
+ } else if (p_text == "VisualScriptReturn") {
Ref<VisualScriptReturn> n;
n.instance();
vnode = n;
seq_connect = true;
-
- } break;
- }
-
- int new_id = script->get_available_id();
- undo_redo->create_action(TTR("Add Node"));
- undo_redo->add_do_method(script.ptr(), "add_node", edited_func, new_id, vnode, ofs);
- if (seq_connect) {
- undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, port_action_node, port_action_output, new_id);
+ }
}
- undo_redo->add_undo_method(script.ptr(), "remove_node", edited_func, new_id);
- undo_redo->add_do_method(this, "_update_graph", new_id);
- undo_redo->add_undo_method(this, "_update_graph", new_id);
- undo_redo->commit_action();
- port_action_new_node = new_id;
-}
-
-void VisualScriptEditor::_selected_connect_node_method_or_setget(const String &p_text) {
+ new_node(vnode, ofs);
Ref<VisualScriptNode> vsn = script->get_node(edited_func, port_action_new_node);
@@ -2699,28 +2726,152 @@ void VisualScriptEditor::_selected_connect_node_method_or_setget(const String &p
Ref<VisualScriptFunctionCall> vsfc = vsn;
vsfc->set_function(p_text);
- script->data_connect(edited_func, port_action_node, port_action_output, port_action_new_node, 0);
+
+ VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
+ if (tg.type == Variant::OBJECT) {
+ vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
+
+ if (tg.gdclass != StringName()) {
+ vsfc->set_base_type(tg.gdclass);
+
+ } else {
+ PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint;
+ String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
+
+ if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {
+ vsfc->set_base_type(base_type);
+ }
+ if (p_text == "call" || p_text == "call_deferred") {
+ vsfc->set_function("");
+ }
+ }
+ if (tg.script.is_valid()) {
+ vsfc->set_base_script(tg.script->get_path());
+ }
+ } else if (tg.type == Variant::NIL) {
+ vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_INSTANCE);
+ vsfc->set_base_type(script->get_instance_base_type());
+ } else {
+ vsfc->set_call_mode(VisualScriptFunctionCall::CALL_MODE_BASIC_TYPE);
+ vsfc->set_basic_type(tg.type);
+ }
}
if (Object::cast_to<VisualScriptPropertySet>(vsn.ptr())) {
Ref<VisualScriptPropertySet> vsp = vsn;
- vsp->set_property(p_text);
- script->data_connect(edited_func, port_action_node, port_action_output, port_action_new_node, 0);
+
+ VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
+ if (tg.type == Variant::OBJECT) {
+ vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
+
+ if (tg.gdclass != StringName()) {
+ vsp->set_base_type(tg.gdclass);
+
+ } else {
+ PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint;
+ String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
+
+ if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {
+ vsp->set_base_type(base_type);
+ }
+ }
+ if (tg.script.is_valid()) {
+ vsp->set_base_script(tg.script->get_path());
+ }
+ } else if (tg.type == Variant::NIL) {
+ vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_INSTANCE);
+ vsp->set_base_type(script->get_instance_base_type());
+ } else {
+ vsp->set_call_mode(VisualScriptPropertySet::CALL_MODE_BASIC_TYPE);
+ vsp->set_basic_type(tg.type);
+ }
}
if (Object::cast_to<VisualScriptPropertyGet>(vsn.ptr())) {
-
Ref<VisualScriptPropertyGet> vsp = vsn;
- vsp->set_property(p_text);
- script->data_connect(edited_func, port_action_node, port_action_output, port_action_new_node, 0);
+
+ VisualScriptNode::TypeGuess tg = _guess_output_type(port_action_node, port_action_output, vn);
+ if (tg.type == Variant::OBJECT) {
+ vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
+
+ if (tg.gdclass != StringName()) {
+ vsp->set_base_type(tg.gdclass);
+
+ } else {
+ PropertyHint hint = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint;
+ String base_type = script->get_node(edited_func, port_action_node)->get_output_value_port_info(port_action_output).hint_string;
+
+ if (base_type != String() && hint == PROPERTY_HINT_TYPE_STRING) {
+ vsp->set_base_type(base_type);
+ }
+ }
+ if (tg.script.is_valid()) {
+ vsp->set_base_script(tg.script->get_path());
+ }
+ } else if (tg.type == Variant::NIL) {
+ vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_INSTANCE);
+ vsp->set_base_type(script->get_instance_base_type());
+ } else {
+ vsp->set_call_mode(VisualScriptPropertyGet::CALL_MODE_BASIC_TYPE);
+ vsp->set_basic_type(tg.type);
+ }
}
+ Ref<VisualScriptNode> vnode_old = script->get_node(edited_func, port_action_node);
+ connect_seq(vnode_old, vnode, port_action_new_node);
+ connect_data(vnode_old, vnode, port_action_new_node);
_update_graph(port_action_new_node);
_update_graph_connections();
}
-void VisualScriptEditor::_selected_new_virtual_method(const String &p_text) {
+void VisualScriptEditor::connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id) {
+ int seq_count = vnode_old->get_output_sequence_port_count();
+ VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(vnode_new.ptr());
+ if (vnode_operator != NULL && vnode_operator->has_input_sequence_port() == false) {
+ return;
+ }
+ VisualScriptConstructor *vnode_constructor = Object::cast_to<VisualScriptConstructor>(vnode_new.ptr());
+ if (vnode_constructor != NULL) {
+ return;
+ }
+ if (vnode_old->get_output_sequence_port_count() <= 0) {
+ return;
+ }
+ if (vnode_new->has_input_sequence_port() == false) {
+ return;
+ }
+ VisualScriptFunction *vnode_function = Object::cast_to<VisualScriptFunction>(vnode_old.ptr());
+ undo_redo->create_action(TTR("Connect Node Sequence"));
+ int pass_port = -vnode_old->get_output_sequence_port_count() + 1;
+ int return_port = port_action_output - 1;
+ if (vnode_old->get_output_value_port_info(port_action_output).name == String("pass") &&
+ !script->get_output_sequence_ports_connected(edited_func, port_action_node).has(pass_port)) {
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, port_action_node, pass_port, new_id);
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", edited_func, port_action_node, pass_port, new_id);
+ } else if (vnode_old->get_output_value_port_info(port_action_output).name == String("return") &&
+ !script->get_output_sequence_ports_connected(edited_func, port_action_node).has(return_port)) {
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, port_action_node, return_port, new_id);
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", edited_func, port_action_node, return_port, new_id);
+ } else {
+ for (int port = 0; port < vnode_old->get_output_sequence_port_count(); port++) {
+ int count = vnode_old->get_output_sequence_port_count();
+ if (port_action_output < count && !script->get_output_sequence_ports_connected(edited_func, port_action_node).has(port_action_output)) {
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, port_action_node, port_action_output, new_id);
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", edited_func, port_action_node, port_action_output, new_id);
+ break;
+ } else if (!script->get_output_sequence_ports_connected(edited_func, port_action_node).has(port)) {
+ undo_redo->add_do_method(script.ptr(), "sequence_connect", edited_func, port_action_node, port, new_id);
+ undo_redo->add_undo_method(script.ptr(), "sequence_disconnect", edited_func, port_action_node, port, new_id);
+ break;
+ }
+ }
+ }
+
+ undo_redo->commit_action();
+}
+
+void VisualScriptEditor::_selected_new_virtual_method(const String &p_text, const String &p_category) {
String name = p_text;
if (script->has_function(name)) {
@@ -2777,12 +2928,29 @@ void VisualScriptEditor::_selected_new_virtual_method(const String &p_text) {
_update_graph();
}
-void VisualScriptEditor::_cancel_connect_node_method_or_setget() {
-
- script->remove_node(edited_func, port_action_new_node);
+void VisualScriptEditor::_cancel_connect_node() {
+ // Causes crashes
+ //script->remove_node(edited_func, port_action_new_node);
_update_graph();
}
+void VisualScriptEditor::_create_new_node(const String &p_text, const String &p_category, const Vector2 &p_point) {
+ Vector2 ofs = graph->get_scroll_ofs() + p_point;
+ if (graph->is_using_snap()) {
+ int snap = graph->get_snap();
+ ofs = ofs.snapped(Vector2(snap, snap));
+ }
+ ofs /= EDSCALE;
+ Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(p_text);
+ int new_id = script->get_available_id();
+ undo_redo->create_action(TTR("Add Node"));
+ undo_redo->add_do_method(script.ptr(), "add_node", edited_func, new_id, vnode, ofs);
+ undo_redo->add_undo_method(script.ptr(), "remove_node", edited_func, new_id);
+ undo_redo->add_do_method(this, "_update_graph");
+ undo_redo->add_undo_method(this, "_update_graph");
+ undo_redo->commit_action();
+}
+
void VisualScriptEditor::_default_value_changed() {
Ref<VisualScriptNode> vsn = script->get_node(edited_func, editing_id);
@@ -3286,10 +3454,11 @@ void VisualScriptEditor::_bind_methods() {
ClassDB::bind_method("_comment_node_resized", &VisualScriptEditor::_comment_node_resized);
ClassDB::bind_method("_button_resource_previewed", &VisualScriptEditor::_button_resource_previewed);
ClassDB::bind_method("_port_action_menu", &VisualScriptEditor::_port_action_menu);
- ClassDB::bind_method("_selected_connect_node_method_or_setget", &VisualScriptEditor::_selected_connect_node_method_or_setget);
+ ClassDB::bind_method("_selected_connect_node", &VisualScriptEditor::_selected_connect_node);
ClassDB::bind_method("_selected_new_virtual_method", &VisualScriptEditor::_selected_new_virtual_method);
- ClassDB::bind_method("_cancel_connect_node_method_or_setget", &VisualScriptEditor::_cancel_connect_node_method_or_setget);
+ ClassDB::bind_method("_cancel_connect_node", &VisualScriptEditor::_cancel_connect_node);
+ ClassDB::bind_method("_create_new_node", &VisualScriptEditor::_create_new_node);
ClassDB::bind_method("_expression_text_changed", &VisualScriptEditor::_expression_text_changed);
ClassDB::bind_method("get_drag_data_fw", &VisualScriptEditor::get_drag_data_fw);
@@ -3480,25 +3649,21 @@ VisualScriptEditor::VisualScriptEditor() {
add_child(default_value_edit);
default_value_edit->connect("variant_changed", this, "_default_value_changed");
- method_select = memnew(PropertySelector);
+ method_select = memnew(VisualScriptPropertySelector);
add_child(method_select);
method_select->connect("selected", this, "_selected_method");
error_line = -1;
- new_connect_node_select = memnew(PropertySelector);
+ new_connect_node_select = memnew(VisualScriptPropertySelector);
add_child(new_connect_node_select);
- new_connect_node_select->connect("selected", this, "_selected_connect_node_method_or_setget");
- new_connect_node_select->get_cancel()->connect("pressed", this, "_cancel_connect_node_method_or_setget");
+ new_connect_node_select->connect("selected", this, "_selected_connect_node");
+ new_connect_node_select->get_cancel()->connect("pressed", this, "_cancel_connect_node");
- new_virtual_method_select = memnew(PropertySelector);
+ new_virtual_method_select = memnew(VisualScriptPropertySelector);
add_child(new_virtual_method_select);
new_virtual_method_select->connect("selected", this, "_selected_new_virtual_method");
new_virtual_method_select->get_cancel()->connect("pressed", this, "_selected_new_virtual_method");
- port_action_popup = memnew(PopupMenu);
- add_child(port_action_popup);
- port_action_popup->connect("id_pressed", this, "_port_action_menu");
-
member_popup = memnew(PopupMenu);
add_child(member_popup);
members->connect("item_rmb_selected", this, "_member_rmb_selected");
@@ -3515,9 +3680,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..0283f7b162 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -34,9 +34,9 @@
#include "editor/create_dialog.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor/property_editor.h"
-#include "editor/property_selector.h"
#include "scene/gui/graph_edit.h"
#include "visual_script.h"
+#include "visual_script_property_selector.h"
class VisualScriptEditorSignalEdit;
class VisualScriptEditorVariableEdit;
@@ -62,15 +62,8 @@ class VisualScriptEditor : public ScriptEditorBase {
enum PortAction {
- CREATE_CALL,
- CREATE_SET,
- CREATE_GET,
- CREATE_COND,
- CREATE_SEQUENCE,
- CREATE_SWITCH,
- CREATE_ITERATOR,
- CREATE_WHILE,
- CREATE_RETURN,
+ CREATE_CALL_SET_GET,
+ CREATE_ACTION,
};
enum MemberAction {
@@ -102,9 +95,9 @@ class VisualScriptEditor : public ScriptEditorBase {
AcceptDialog *edit_signal_dialog;
PropertyEditor *edit_signal_edit;
- PropertySelector *method_select;
- PropertySelector *new_connect_node_select;
- PropertySelector *new_virtual_method_select;
+ VisualScriptPropertySelector *method_select;
+ VisualScriptPropertySelector *new_connect_node_select;
+ VisualScriptPropertySelector *new_virtual_method_select;
VisualScriptEditorVariableEdit *variable_editor;
@@ -162,21 +155,29 @@ class VisualScriptEditor : public ScriptEditorBase {
static Clipboard *clipboard;
- PopupMenu *port_action_popup;
PopupMenu *member_popup;
-
MemberType member_type;
String member_name;
+ bool seq_connect = false;
+
PortAction port_action;
int port_action_node;
int port_action_output;
Vector2 port_action_pos;
int port_action_new_node;
void _port_action_menu(int p_option);
- void _selected_connect_node_method_or_setget(const String &p_text);
- void _cancel_connect_node_method_or_setget();
- void _selected_new_virtual_method(const String &p_text);
+
+ void new_node(Ref<VisualScriptNode> vnode, Vector2 ofs);
+
+ void connect_data(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode, int new_id);
+
+ void _selected_connect_node(const String &p_text, const String &p_category);
+ void connect_seq(Ref<VisualScriptNode> vnode_old, Ref<VisualScriptNode> vnode_new, int new_id);
+
+ void _cancel_connect_node();
+ void _create_new_node(const String &p_text, const String &p_category, const Vector2 &p_point);
+ void _selected_new_virtual_method(const String &p_text, const String &p_category);
int error_line;
@@ -231,7 +232,7 @@ class VisualScriptEditor : public ScriptEditorBase {
void _comment_node_resized(const Vector2 &p_new_size, int p_node);
int selecting_method_id;
- void _selected_method(const String &p_method);
+ void _selected_method(const String &p_method, const String &p_type);
void _draw_color_over_button(Object *obj, Color p_color);
void _button_resource_previewed(const String &p_path, const Ref<Texture> &p_preview, Variant p_ud);
@@ -250,9 +251,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/modules/visual_script/visual_script_flow_control.cpp b/modules/visual_script/visual_script_flow_control.cpp
index ea23ab1b2a..0f58a20c00 100644
--- a/modules/visual_script/visual_script_flow_control.cpp
+++ b/modules/visual_script/visual_script_flow_control.cpp
@@ -767,7 +767,7 @@ PropertyInfo VisualScriptTypeCast::get_input_value_port_info(int p_idx) const {
PropertyInfo VisualScriptTypeCast::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(Variant::OBJECT, "");
+ return PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_TYPE_STRING, get_base_type());
}
String VisualScriptTypeCast::get_caption() const {
diff --git a/modules/visual_script/visual_script_func_nodes.cpp b/modules/visual_script/visual_script_func_nodes.cpp
index bdf5705ecd..ad886bc758 100644
--- a/modules/visual_script/visual_script_func_nodes.cpp
+++ b/modules/visual_script/visual_script_func_nodes.cpp
@@ -43,7 +43,7 @@
int VisualScriptFunctionCall::get_output_sequence_port_count() const {
- if (method_cache.flags & METHOD_FLAG_CONST || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function)))
+ if ((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function)))
return 0;
else
return 1;
@@ -51,7 +51,7 @@ int VisualScriptFunctionCall::get_output_sequence_port_count() const {
bool VisualScriptFunctionCall::has_input_sequence_port() const {
- if (method_cache.flags & METHOD_FLAG_CONST || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function)))
+ if ((method_cache.flags & METHOD_FLAG_CONST && call_mode != CALL_MODE_INSTANCE) || (call_mode == CALL_MODE_BASIC_TYPE && Variant::is_method_const(basic_type, function)))
return false;
else
return true;
@@ -231,7 +231,7 @@ PropertyInfo VisualScriptFunctionCall::get_output_value_port_info(int p_idx) con
if (call_mode == CALL_MODE_INSTANCE) {
if (p_idx == 0) {
- return PropertyInfo(Variant::OBJECT, "pass");
+ return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type());
} else {
p_idx--;
}
@@ -1055,7 +1055,7 @@ PropertyInfo VisualScriptPropertySet::get_output_value_port_info(int p_idx) cons
if (call_mode == CALL_MODE_BASIC_TYPE) {
return PropertyInfo(basic_type, "out");
} else if (call_mode == CALL_MODE_INSTANCE) {
- return PropertyInfo(Variant::OBJECT, "pass");
+ return PropertyInfo(Variant::OBJECT, "pass", PROPERTY_HINT_TYPE_STRING, get_base_type());
} else {
return PropertyInfo();
}
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index 8b7b809ec0..f174300a4c 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -2198,7 +2198,7 @@ PropertyInfo VisualScriptSceneTree::get_input_value_port_info(int p_idx) const {
PropertyInfo VisualScriptSceneTree::get_output_value_port_info(int p_idx) const {
- return PropertyInfo(Variant::OBJECT, "Scene Tree");
+ return PropertyInfo(Variant::OBJECT, "Scene Tree", PROPERTY_HINT_TYPE_STRING, "SceneTree");
}
String VisualScriptSceneTree::get_caption() const {
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
new file mode 100644
index 0000000000..994ea1f791
--- /dev/null
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -0,0 +1,705 @@
+/*************************************************************************/
+/* visual_script_property_selector.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 "visual_script_property_selector.h"
+
+#include "editor_scale.h"
+#include "modules/visual_script/visual_script.h"
+#include "modules/visual_script/visual_script_builtin_funcs.h"
+#include "modules/visual_script/visual_script_flow_control.h"
+#include "modules/visual_script/visual_script_func_nodes.h"
+#include "modules/visual_script/visual_script_nodes.h"
+#include "os/keyboard.h"
+#include "scene/main/node.h"
+#include "scene/main/viewport.h"
+
+void VisualScriptPropertySelector::_text_changed(const String &p_newtext) {
+ _update_search();
+}
+
+void VisualScriptPropertySelector::_sbox_input(const Ref<InputEvent> &p_ie) {
+
+ Ref<InputEventKey> k = p_ie;
+
+ if (k.is_valid()) {
+
+ switch (k->get_scancode()) {
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGEUP:
+ case KEY_PAGEDOWN: {
+
+ search_options->call("_gui_input", k);
+ search_box->accept_event();
+
+ TreeItem *root = search_options->get_root();
+ if (!root->get_children())
+ break;
+
+ TreeItem *current = search_options->get_selected();
+
+ TreeItem *item = search_options->get_next_selected(root);
+ while (item) {
+ item->deselect(0);
+ item = search_options->get_next_selected(item);
+ }
+
+ current->select(0);
+
+ } break;
+ }
+ }
+}
+
+void VisualScriptPropertySelector::_update_search() {
+ set_title(TTR("Search VisualScript"));
+
+ search_options->clear();
+ help_bit->set_text("");
+
+ TreeItem *root = search_options->create_item();
+ bool found = false;
+
+ if (properties) {
+
+ List<PropertyInfo> props;
+
+ if (instance) {
+ instance->get_property_list(&props, true);
+ } else if (type != Variant::NIL) {
+ Variant v;
+ Variant::CallError ce;
+ v = Variant::construct(type, NULL, 0, ce);
+
+ v.get_property_list(&props);
+ } else {
+
+ Object *obj = ObjectDB::get_instance(script);
+ if (Object::cast_to<Script>(obj)) {
+
+ props.push_back(PropertyInfo(Variant::NIL, "Script Variables", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CATEGORY));
+ Object::cast_to<Script>(obj)->get_script_property_list(&props);
+ }
+
+ StringName base = base_type;
+ while (base) {
+ props.push_back(PropertyInfo(Variant::NIL, base, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CATEGORY));
+ ClassDB::get_property_list(base, &props, true);
+ base = ClassDB::get_parent_class_nocheck(base);
+ }
+ }
+
+ TreeItem *category = NULL;
+
+ Ref<Texture> type_icons[Variant::VARIANT_MAX] = {
+ Control::get_icon("Variant", "EditorIcons"),
+ Control::get_icon("bool", "EditorIcons"),
+ Control::get_icon("int", "EditorIcons"),
+ Control::get_icon("float", "EditorIcons"),
+ Control::get_icon("String", "EditorIcons"),
+ Control::get_icon("Vector2", "EditorIcons"),
+ Control::get_icon("Rect2", "EditorIcons"),
+ Control::get_icon("Vector3", "EditorIcons"),
+ Control::get_icon("Transform2D", "EditorIcons"),
+ Control::get_icon("Plane", "EditorIcons"),
+ Control::get_icon("Quat", "EditorIcons"),
+ Control::get_icon("AABB", "EditorIcons"),
+ Control::get_icon("Basis", "EditorIcons"),
+ Control::get_icon("Transform", "EditorIcons"),
+ Control::get_icon("Color", "EditorIcons"),
+ Control::get_icon("Path", "EditorIcons"),
+ Control::get_icon("RID", "EditorIcons"),
+ Control::get_icon("Object", "EditorIcons"),
+ Control::get_icon("Dictionary", "EditorIcons"),
+ Control::get_icon("Array", "EditorIcons"),
+ Control::get_icon("PoolByteArray", "EditorIcons"),
+ Control::get_icon("PoolIntArray", "EditorIcons"),
+ Control::get_icon("PoolRealArray", "EditorIcons"),
+ Control::get_icon("PoolStringArray", "EditorIcons"),
+ Control::get_icon("PoolVector2Array", "EditorIcons"),
+ Control::get_icon("PoolVector3Array", "EditorIcons"),
+ Control::get_icon("PoolColorArray", "EditorIcons")
+ };
+
+ if (!seq_connect && visual_script_generic == false) {
+ get_visual_node_names("flow_control/type_cast", Set<String>(), found, root, search_box);
+ get_visual_node_names("functions/built_in/print", Set<String>(), found, root, search_box);
+ get_visual_node_names("functions/by_type/" + Variant::get_type_name(type), Set<String>(), found, root, search_box);
+ get_visual_node_names("operators/compare/", Set<String>(), found, root, search_box);
+ if (type == Variant::INT) {
+ get_visual_node_names("operators/bitwise/", Set<String>(), found, root, search_box);
+ }
+ if (type == Variant::BOOL) {
+ get_visual_node_names("operators/logic/", Set<String>(), found, root, search_box);
+ }
+ if (type == Variant::BOOL || type == Variant::INT || type == Variant::REAL || type == Variant::VECTOR2 || type == Variant::VECTOR3) {
+ get_visual_node_names("operators/math/", Set<String>(), found, root, search_box);
+ }
+ }
+
+ for (List<PropertyInfo>::Element *E = props.front(); E; E = E->next()) {
+ if (E->get().usage == PROPERTY_USAGE_CATEGORY) {
+ if (category && category->get_children() == NULL) {
+ memdelete(category); //old category was unused
+ }
+ category = search_options->create_item(root);
+ category->set_text(0, E->get().name);
+ category->set_selectable(0, false);
+
+ Ref<Texture> icon;
+ if (E->get().name == "Script Variables") {
+ icon = get_icon("Script", "EditorIcons");
+ } else if (has_icon(E->get().name, "EditorIcons")) {
+ icon = get_icon(E->get().name, "EditorIcons");
+ } else {
+ icon = get_icon("Object", "EditorIcons");
+ }
+ category->set_icon(0, icon);
+ continue;
+ }
+
+ if (!(E->get().usage & PROPERTY_USAGE_EDITOR) && !(E->get().usage & PROPERTY_USAGE_SCRIPT_VARIABLE))
+ continue;
+
+ if (type_filter.size() && type_filter.find(E->get().type) == -1)
+ continue;
+
+ String get_text_raw = String(TTR("Get")) + String(" ") + E->get().name;
+ String get_text = get_text_raw.capitalize();
+
+ String set_text_raw = String(TTR("Set ")) + String(" ") + E->get().name;
+ String set_text = set_text_raw.capitalize();
+ String input = search_box->get_text().capitalize();
+ if (input == String() ||
+ get_text_raw.findn(input) != -1 ||
+ get_text.findn(input) != -1) {
+ TreeItem *item = search_options->create_item(category ? category : root);
+ item->set_text(0, get_text);
+ item->set_metadata(0, E->get().name);
+ item->set_icon(0, type_icons[E->get().type]);
+ item->set_metadata(1, "get");
+ item->set_collapsed(1);
+ item->set_selectable(1, false);
+ item->set_selectable(0, true);
+ }
+
+ if (input == String() ||
+ set_text_raw.findn(input) != -1 &&
+ set_text.findn(input) != -1) {
+ TreeItem *item = search_options->create_item(category ? category : root);
+ item->set_text(0, set_text);
+ item->set_metadata(0, E->get().name);
+ item->set_icon(0, type_icons[E->get().type]);
+ item->set_metadata(1, "set");
+ item->set_selectable(1, false);
+ item->set_selectable(0, true);
+ }
+ }
+ }
+
+ if (seq_connect == true && visual_script_generic == false) {
+ String text = search_box->get_text();
+ create_visualscript_item(String("VisualScriptCondition"), root, text, String("Condition"));
+ create_visualscript_item(String("VisualScriptSwitch"), root, text, String("Switch"));
+ create_visualscript_item(String("VisualScriptSequence"), root, text, String("Sequence"));
+ create_visualscript_item(String("VisualScriptIterator"), root, text, String("Iterator"));
+ create_visualscript_item(String("VisualScriptWhile"), root, text, String("While"));
+ create_visualscript_item(String("VisualScriptReturn"), root, text, String("Return"));
+ get_visual_node_names("flow_control/type_cast", Set<String>(), found, root, search_box);
+ get_visual_node_names("functions/built_in/print", Set<String>(), found, root, search_box);
+ }
+
+ if (visual_script_generic) {
+ get_visual_node_names("", Set<String>(), found, root, search_box);
+ }
+
+ List<MethodInfo> methods;
+
+ if (type != Variant::NIL) {
+ Variant v;
+ Variant::CallError ce;
+ v = Variant::construct(type, NULL, 0, ce);
+ v.get_method_list(&methods);
+ } else {
+
+ Object *obj = ObjectDB::get_instance(script);
+ if (Object::cast_to<Script>(obj)) {
+
+ methods.push_back(MethodInfo("*Script Methods"));
+ Object::cast_to<Script>(obj)->get_script_method_list(&methods);
+ }
+
+ StringName base = base_type;
+ while (base) {
+ methods.push_back(MethodInfo("*" + String(base)));
+ ClassDB::get_method_list(base, &methods, true, true);
+ base = ClassDB::get_parent_class_nocheck(base);
+ }
+ }
+ TreeItem *category = NULL;
+ bool script_methods = false;
+
+ for (List<MethodInfo>::Element *E = methods.front(); E; E = E->next()) {
+ if (E->get().name.begins_with("*")) {
+ if (category && category->get_children() == NULL) {
+ memdelete(category); //old category was unused
+ }
+ category = search_options->create_item(root);
+ category->set_text(0, E->get().name.replace_first("*", ""));
+ category->set_selectable(0, false);
+
+ Ref<Texture> icon;
+ script_methods = false;
+ print_line("name: " + E->get().name);
+ String rep = E->get().name.replace("*", "");
+ if (E->get().name == "*Script Methods") {
+ icon = get_icon("Script", "EditorIcons");
+ script_methods = true;
+ } else if (has_icon(rep, "EditorIcons")) {
+ icon = get_icon(rep, "EditorIcons");
+ } else {
+ icon = get_icon("Object", "EditorIcons");
+ }
+ category->set_icon(0, icon);
+
+ continue;
+ }
+
+ String name = E->get().name.get_slice(":", 0);
+ if (!script_methods && name.begins_with("_") && !(E->get().flags & METHOD_FLAG_VIRTUAL))
+ continue;
+
+ if (virtuals_only && !(E->get().flags & METHOD_FLAG_VIRTUAL))
+ continue;
+
+ if (!virtuals_only && (E->get().flags & METHOD_FLAG_VIRTUAL))
+ continue;
+
+ MethodInfo mi = E->get();
+ String desc = mi.name.capitalize() + " (";
+
+ if (search_box->get_text() != String() &&
+ name.findn(search_box->get_text()) == -1 &&
+ desc.findn(search_box->get_text()) == -1)
+ continue;
+
+ TreeItem *item = search_options->create_item(category ? category : root);
+
+ for (int i = 0; i < mi.arguments.size(); i++) {
+
+ if (i > 0)
+ desc += ", ";
+
+ if (mi.arguments[i].type == Variant::NIL)
+ desc += "var";
+ else if (mi.arguments[i].name.find(":") != -1) {
+ desc += mi.arguments[i].name.get_slice(":", 1);
+ mi.arguments[i].name = mi.arguments[i].name.get_slice(":", 0);
+ } else
+ desc += Variant::get_type_name(mi.arguments[i].type);
+ }
+
+ desc += ")";
+
+ item->set_text(0, desc);
+ item->set_icon(0, get_icon("MemberMethod", "EditorIcons"));
+ item->set_metadata(0, name);
+ item->set_selectable(0, true);
+
+ item->set_metadata(1, "method");
+ item->set_collapsed(1);
+ item->set_selectable(1, false);
+
+ if (category && category->get_children() == NULL) {
+ memdelete(category); //old category was unused
+ }
+ }
+
+ TreeItem *selected_item = search_options->search_item_text(search_box->get_text());
+ if (!found && selected_item != NULL) {
+ selected_item->select(0);
+ found = true;
+ }
+
+ get_ok()->set_disabled(root->get_children() == NULL);
+}
+
+void VisualScriptPropertySelector::create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text) {
+ if (search_input == String() || text.findn(search_input) != -1) {
+ TreeItem *item = search_options->create_item(root);
+ item->set_text(0, text);
+ item->set_icon(0, get_icon("VisualScript", "EditorIcons"));
+ item->set_metadata(0, name);
+ item->set_metadata(1, "action");
+ item->set_selectable(0, true);
+ item->set_collapsed(1);
+ item->set_selectable(1, false);
+ }
+}
+
+void VisualScriptPropertySelector::get_visual_node_names(const String &root_filter, const Set<String> &filter, bool &found, TreeItem *const root, LineEdit *const search_box) {
+ Map<String, TreeItem *> path_cache;
+
+ List<String> fnodes;
+ VisualScriptLanguage::singleton->get_registered_node_names(&fnodes);
+
+ for (List<String>::Element *E = fnodes.front(); E; E = E->next()) {
+ if (!E->get().begins_with(root_filter)) {
+ continue;
+ }
+ Vector<String> path = E->get().split("/");
+ bool is_filter = false;
+ for (Set<String>::Element *E = filter.front(); E; E = E->next()) {
+ if (path.size() >= 2 && path[1].findn(E->get()) != -1) {
+ is_filter = true;
+ break;
+ }
+ }
+ if (is_filter == true) {
+ continue;
+ }
+
+ if (search_box->get_text() != String() && E->get().findn(search_box->get_text()) == -1) {
+ continue;
+ }
+ TreeItem *item = search_options->create_item(root);
+ VisualScriptOperator *vnode_operator = Object::cast_to<VisualScriptOperator>(*VisualScriptLanguage::singleton->create_node_from_name(E->get()));
+ String type_name;
+ if (vnode_operator != NULL) {
+ String type;
+ if (path.size() >= 2) {
+ type = path[1];
+ }
+ type_name = type.capitalize() + " ";
+ }
+ VisualScriptFunctionCall *vnode_function_call = Object::cast_to<VisualScriptFunctionCall>(*VisualScriptLanguage::singleton->create_node_from_name(E->get()));
+ if (vnode_function_call != NULL) {
+ String basic_type = Variant::get_type_name(vnode_function_call->get_basic_type());
+ type_name = basic_type.capitalize() + " ";
+ }
+ VisualScriptBuiltinFunc *vnode_builtin_function_call = Object::cast_to<VisualScriptBuiltinFunc>(*VisualScriptLanguage::singleton->create_node_from_name(E->get()));
+ if (vnode_builtin_function_call != NULL) {
+ type_name = "Builtin ";
+ }
+ item->set_text(0, type_name + path[path.size() - 1].capitalize());
+ item->set_icon(0, get_icon("VisualScript", "EditorIcons"));
+ item->set_selectable(0, true);
+ item->set_metadata(0, E->get());
+ item->set_selectable(0, true);
+ item->set_metadata(1, "visualscript");
+ item->set_selectable(1, false);
+ }
+}
+
+void VisualScriptPropertySelector::_confirmed() {
+
+ TreeItem *ti = search_options->get_selected();
+ if (!ti)
+ return;
+ emit_signal("selected", ti->get_metadata(0), ti->get_metadata(1));
+ hide();
+}
+
+void VisualScriptPropertySelector::_item_selected() {
+
+ help_bit->set_text("");
+
+ TreeItem *item = search_options->get_selected();
+ if (!item)
+ return;
+ String name = item->get_metadata(0);
+
+ String class_type;
+ if (type) {
+ class_type = Variant::get_type_name(type);
+
+ } else {
+ class_type = base_type;
+ }
+
+ DocData *dd = EditorHelp::get_doc_data();
+ String text;
+
+ String at_class = class_type;
+
+ while (at_class != String()) {
+
+ Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(at_class);
+ if (E) {
+ for (int i = 0; i < E->get().properties.size(); i++) {
+ if (E->get().properties[i].name == name) {
+ text = E->get().properties[i].description;
+ }
+ }
+ }
+
+ at_class = ClassDB::get_parent_class_nocheck(at_class);
+ }
+ at_class = class_type;
+
+ while (at_class != String()) {
+
+ Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(at_class);
+ if (E) {
+ for (int i = 0; i < E->get().methods.size(); i++) {
+ if (E->get().methods[i].name == name) {
+ text = E->get().methods[i].description;
+ }
+ }
+ }
+
+ at_class = ClassDB::get_parent_class_nocheck(at_class);
+ }
+ Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(class_type);
+ if (E) {
+ for (int i = 0; i < E->get().methods.size(); i++) {
+ Vector<String> functions = name.rsplit("/", false, 1);
+ if (E->get().methods[i].name == functions[functions.size() - 1]) {
+ text = E->get().methods[i].description;
+ }
+ }
+ }
+
+ List<String> *names = memnew(List<String>);
+ VisualScriptLanguage::singleton->get_registered_node_names(names);
+ if (names->find(name) != NULL) {
+ Ref<VisualScriptOperator> operator_node = VisualScriptLanguage::singleton->create_node_from_name(name);
+ if (operator_node.is_valid()) {
+ Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(operator_node->get_class_name());
+ if (E) {
+ text = Variant::get_operator_name(operator_node->get_operator());
+ }
+ }
+ Ref<VisualScriptTypeCast> typecast_node = VisualScriptLanguage::singleton->create_node_from_name(name);
+ if (typecast_node.is_valid()) {
+ Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(typecast_node->get_class_name());
+ if (E) {
+ text = E->get().description;
+ }
+ }
+
+ Ref<VisualScriptBuiltinFunc> builtin_node = VisualScriptLanguage::singleton->create_node_from_name(name);
+ if (builtin_node.is_valid()) {
+ Map<String, DocData::ClassDoc>::Element *E = dd->class_list.find(builtin_node->get_class_name());
+ if (E) {
+ for (int i = 0; i < E->get().constants.size(); i++) {
+ if (E->get().constants[i].value.to_int() == int(builtin_node->get_func())) {
+ text = E->get().constants[i].description;
+ }
+ }
+ }
+ }
+ }
+
+ memdelete(names);
+
+ if (text == String())
+ return;
+
+ help_bit->set_text(text);
+}
+
+void VisualScriptPropertySelector::_notification(int p_what) {
+
+ if (p_what == NOTIFICATION_ENTER_TREE) {
+
+ connect("confirmed", this, "_confirmed");
+ }
+}
+
+void VisualScriptPropertySelector::select_method_from_base_type(const String &p_base, const String &p_current, bool p_virtuals_only) {
+
+ base_type = p_base;
+ selected = p_current;
+ type = Variant::NIL;
+ script = 0;
+ properties = false;
+ instance = NULL;
+ virtuals_only = p_virtuals_only;
+
+ show_window(.5f);
+ search_box->set_text("");
+ search_box->grab_focus();
+ _update_search();
+}
+
+void VisualScriptPropertySelector::set_type_filter(const Vector<Variant::Type> &p_type_filter) {
+ type_filter = p_type_filter;
+}
+
+void VisualScriptPropertySelector::select_from_base_type(const String &p_base, const String &p_current /*= ""*/, bool p_virtuals_only /*= false*/, bool p_seq_connect /*= false*/) {
+
+ base_type = p_base;
+ selected = p_current;
+ type = Variant::NIL;
+ script = 0;
+ properties = true;
+ instance = NULL;
+ virtuals_only = p_virtuals_only;
+
+ show_window(.5f);
+ search_box->set_text("");
+ search_box->grab_focus();
+ seq_connect = p_seq_connect;
+
+ _update_search();
+}
+
+void VisualScriptPropertySelector::select_from_script(const Ref<Script> &p_script, const String &p_current /*= ""*/) {
+ ERR_FAIL_COND(p_script.is_null());
+
+ base_type = p_script->get_instance_base_type();
+ selected = p_current;
+ type = Variant::NIL;
+ script = p_script->get_instance_id();
+ properties = true;
+ instance = NULL;
+ virtuals_only = false;
+
+ show_window(.5f);
+ search_box->set_text("");
+ search_box->grab_focus();
+ seq_connect = false;
+
+ _update_search();
+}
+
+void VisualScriptPropertySelector::select_from_basic_type(Variant::Type p_type, const String &p_current /*= ""*/) {
+ ERR_FAIL_COND(p_type == Variant::NIL);
+ base_type = "";
+ selected = p_current;
+ type = p_type;
+ script = 0;
+ properties = true;
+ instance = NULL;
+ virtuals_only = false;
+
+ show_window(.5f);
+ search_box->set_text("");
+ search_box->grab_focus();
+ seq_connect = false;
+
+ _update_search();
+}
+
+void VisualScriptPropertySelector::select_from_action(const String &p_type, const String &p_current /*= ""*/) {
+ base_type = p_type;
+ selected = p_current;
+ type = Variant::NIL;
+ script = 0;
+ properties = false;
+ instance = NULL;
+ virtuals_only = false;
+
+ show_window(.5f);
+ search_box->set_text("");
+ search_box->grab_focus();
+ seq_connect = true;
+ _update_search();
+}
+
+void VisualScriptPropertySelector::select_from_instance(Object *p_instance, const String &p_current /*= ""*/) {
+ base_type = "";
+ selected = p_current;
+ type = Variant::NIL;
+ script = 0;
+ properties = true;
+ instance = p_instance;
+ virtuals_only = false;
+
+ show_window(.5f);
+ search_box->set_text("");
+ search_box->grab_focus();
+ seq_connect = false;
+
+ _update_search();
+}
+
+void VisualScriptPropertySelector::select_from_visual_script(const String &p_base) {
+ base_type = p_base;
+ selected = "";
+ type = Variant::NIL;
+ script = 0;
+ properties = true;
+ visual_script_generic = true;
+ instance = NULL;
+ virtuals_only = false;
+ show_window(.5f);
+ search_box->set_text("");
+ search_box->grab_focus();
+
+ _update_search();
+}
+
+void VisualScriptPropertySelector::show_window(float p_screen_ratio) {
+ Rect2 rect;
+ Point2 window_size = get_viewport_rect().size;
+ rect.size = (window_size * p_screen_ratio).floor();
+ rect.size.x = rect.size.x / 1.25f;
+ rect.position = ((window_size - rect.size) / 2.0f).floor();
+ popup(rect);
+}
+
+void VisualScriptPropertySelector::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("_text_changed"), &VisualScriptPropertySelector::_text_changed);
+ ClassDB::bind_method(D_METHOD("_confirmed"), &VisualScriptPropertySelector::_confirmed);
+ ClassDB::bind_method(D_METHOD("_sbox_input"), &VisualScriptPropertySelector::_sbox_input);
+ ClassDB::bind_method(D_METHOD("_item_selected"), &VisualScriptPropertySelector::_item_selected);
+
+ ADD_SIGNAL(MethodInfo("selected", PropertyInfo(Variant::STRING, "name")));
+}
+
+VisualScriptPropertySelector::VisualScriptPropertySelector() {
+
+ VBoxContainer *vbc = memnew(VBoxContainer);
+ add_child(vbc);
+ //set_child_rect(vbc);
+ search_box = memnew(LineEdit);
+ vbc->add_margin_child(TTR("Search:"), search_box);
+ search_box->connect("text_changed", this, "_text_changed");
+ search_box->connect("gui_input", this, "_sbox_input");
+ search_options = memnew(Tree);
+ vbc->add_margin_child(TTR("Matches:"), search_options, true);
+ get_ok()->set_text(TTR("Open"));
+ get_ok()->set_disabled(true);
+ register_text_enter(search_box);
+ set_hide_on_ok(false);
+ search_options->connect("item_activated", this, "_confirmed");
+ search_options->connect("cell_selected", this, "_item_selected");
+ search_options->set_hide_root(true);
+ search_options->set_hide_folding(true);
+ virtuals_only = false;
+ help_bit = memnew(EditorHelpBit);
+ vbc->add_margin_child(TTR("Description:"), help_bit);
+ help_bit->connect("request_hide", this, "_closed");
+ search_options->set_columns(2);
+ search_options->set_column_expand(1, false);
+}
diff --git a/modules/visual_script/visual_script_property_selector.h b/modules/visual_script/visual_script_property_selector.h
new file mode 100644
index 0000000000..ec536f86a8
--- /dev/null
+++ b/modules/visual_script/visual_script_property_selector.h
@@ -0,0 +1,92 @@
+/*************************************************************************/
+/* visual_script_property_selector.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 VISUALSCRIPT_PROPERTYSELECTOR_H
+#define VISUALSCRIPT_PROPERTYSELECTOR_H
+
+#include "editor/property_editor.h"
+#include "editor_help.h"
+#include "scene/gui/rich_text_label.h"
+
+class VisualScriptPropertySelector : public ConfirmationDialog {
+ GDCLASS(VisualScriptPropertySelector, ConfirmationDialog)
+
+ LineEdit *search_box;
+ Tree *search_options;
+
+ void _update_search();
+
+ void create_visualscript_item(const String &name, TreeItem *const root, const String &search_input, const String &text);
+
+ void get_visual_node_names(const String &root_filter, const Set<String> &filter, bool &found, TreeItem *const root, LineEdit *const search_box);
+
+ void _sbox_input(const Ref<InputEvent> &p_ie);
+
+ void _confirmed();
+ void _text_changed(const String &p_newtext);
+
+ EditorHelpBit *help_bit;
+
+ bool properties;
+ bool visual_script_generic;
+ String selected;
+ Variant::Type type;
+ String base_type;
+ ObjectID script;
+ Object *instance;
+ bool virtuals_only;
+
+ bool seq_connect = false;
+
+ void _item_selected();
+
+ Vector<Variant::Type> type_filter;
+
+protected:
+ void _notification(int p_what);
+ static void _bind_methods();
+
+public:
+ void select_method_from_base_type(const String &p_base, const String &p_current = "", bool p_virtuals_only = false);
+ void select_from_base_type(const String &p_base, const String &p_current = "", bool p_virtuals_only = false, bool p_seq_connect = false);
+ void select_from_script(const Ref<Script> &p_script, const String &p_current /*= ""*/);
+ void select_from_basic_type(Variant::Type p_type, const String &p_current = "");
+ void select_from_action(const String &p_type, const String &p_current = "");
+ void select_from_instance(Object *p_instance, const String &p_current = "");
+ void select_from_visual_script(const String &p_base);
+
+ void show_window(float p_screen_ratio);
+
+ void set_type_filter(const Vector<Variant::Type> &p_type_filter);
+
+ VisualScriptPropertySelector();
+};
+
+#endif // VISUALSCRIPT_PROPERTYSELECTOR_H
diff --git a/platform/windows/context_gl_win.cpp b/platform/windows/context_gl_win.cpp
index d312fbcb12..a158237418 100644
--- a/platform/windows/context_gl_win.cpp
+++ b/platform/windows/context_gl_win.cpp
@@ -106,9 +106,9 @@ Error ContextGL_Win::initialize() {
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
- 24,
+ OS::get_singleton()->is_layered_allowed() ? 32 : 24,
0, 0, 0, 0, 0, 0, // Color Bits Ignored
- 0, // No Alpha Buffer
+ OS::get_singleton()->is_layered_allowed() ? 8 : 0, // Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
diff --git a/scene/2d/canvas_item.cpp b/scene/2d/canvas_item.cpp
index 47326b9be2..a035d9021f 100644
--- a/scene/2d/canvas_item.cpp
+++ b/scene/2d/canvas_item.cpp
@@ -411,6 +411,9 @@ void CanvasItem::_enter_canvas() {
if (canvas_layer) {
break;
}
+ if (Object::cast_to<Viewport>(n)) {
+ break;
+ }
n = n->get_parent();
}
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index 9f7503577b..81fdc32788 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -150,7 +150,7 @@ void Tween::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
- if (!processing) {
+ if (!is_active()) {
//make sure that a previous process state was not saved
//only process if "processing" is set
set_physics_process_internal(false);
@@ -164,7 +164,7 @@ void Tween::_notification(int p_what) {
if (tween_process_mode == TWEEN_PROCESS_PHYSICS)
break;
- if (processing)
+ if (is_active())
_tween_process(get_process_delta_time());
} break;
case NOTIFICATION_INTERNAL_PHYSICS_PROCESS: {
@@ -172,7 +172,7 @@ void Tween::_notification(int p_what) {
if (tween_process_mode == TWEEN_PROCESS_IDLE)
break;
- if (processing)
+ if (is_active())
_tween_process(get_physics_process_delta_time());
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -201,7 +201,6 @@ void Tween::_bind_methods() {
ClassDB::bind_method(D_METHOD("reset_all"), &Tween::reset_all);
ClassDB::bind_method(D_METHOD("stop", "object", "key"), &Tween::stop, DEFVAL(""));
ClassDB::bind_method(D_METHOD("stop_all"), &Tween::stop_all);
- ClassDB::bind_method(D_METHOD("is_stopped"), &Tween::is_stopped);
ClassDB::bind_method(D_METHOD("resume", "object", "key"), &Tween::resume, DEFVAL(""));
ClassDB::bind_method(D_METHOD("resume_all"), &Tween::resume_all);
ClassDB::bind_method(D_METHOD("remove", "object", "key"), &Tween::remove, DEFVAL(""));
@@ -522,8 +521,8 @@ void Tween::_tween_process(float p_delta) {
pending_update++;
// if repeat and all interpolates was finished then reset all interpolates
+ bool all_finished = true;
if (repeat) {
- bool all_finished = true;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
@@ -539,9 +538,12 @@ void Tween::_tween_process(float p_delta) {
reset_all();
}
+ all_finished = true;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
InterpolateData &data = E->get();
+ all_finished = all_finished && data.finish;
+
if (!data.active || data.finish)
continue;
@@ -555,8 +557,8 @@ void Tween::_tween_process(float p_delta) {
continue;
else if (prev_delaying) {
- emit_signal("tween_started", object, NodePath(Vector<StringName>(), data.key, false));
_apply_tween_value(data, data.initial_val);
+ emit_signal("tween_started", object, NodePath(Vector<StringName>(), data.key, false));
}
if (data.elapsed > (data.delay + data.duration)) {
@@ -603,32 +605,29 @@ void Tween::_tween_process(float p_delta) {
}
} else {
Variant result = _run_equation(data);
- emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result);
_apply_tween_value(data, result);
+ emit_signal("tween_step", object, NodePath(Vector<StringName>(), data.key, false), data.elapsed, result);
}
if (data.finish) {
_apply_tween_value(data, data.final_val);
+ data.elapsed = 0;
emit_signal("tween_completed", object, NodePath(Vector<StringName>(), data.key, false));
// not repeat mode, remove completed action
if (!repeat)
call_deferred("_remove", object, NodePath(Vector<StringName>(), data.key, false), true);
- }
+ } else if (!repeat)
+ all_finished = all_finished && data.finish;
}
pending_update--;
+
+ if (all_finished)
+ set_active(false);
}
void Tween::set_tween_process_mode(TweenProcessMode p_mode) {
- if (tween_process_mode == p_mode)
- return;
-
- bool pr = processing;
- if (pr)
- _set_process(false);
tween_process_mode = p_mode;
- if (pr)
- _set_process(true);
}
Tween::TweenProcessMode Tween::get_tween_process_mode() const {
@@ -636,32 +635,21 @@ Tween::TweenProcessMode Tween::get_tween_process_mode() const {
return tween_process_mode;
}
-void Tween::_set_process(bool p_process, bool p_force) {
-
- if (processing == p_process && !p_force)
- return;
-
- switch (tween_process_mode) {
-
- case TWEEN_PROCESS_PHYSICS: set_physics_process_internal(p_process && active); break;
- case TWEEN_PROCESS_IDLE: set_process_internal(p_process && active); break;
- }
-
- processing = p_process;
-}
-
bool Tween::is_active() const {
- return active;
+ return is_processing_internal() || is_physics_processing_internal();
}
void Tween::set_active(bool p_active) {
- if (active == p_active)
+ if (is_active() == p_active)
return;
- active = p_active;
- _set_process(processing, true);
+ switch (tween_process_mode) {
+
+ case TWEEN_PROCESS_IDLE: set_process_internal(p_active); break;
+ case TWEEN_PROCESS_PHYSICS: set_physics_process_internal(p_active); break;
+ }
}
bool Tween::is_repeat() const {
@@ -687,7 +675,6 @@ float Tween::get_speed_scale() const {
bool Tween::start() {
set_active(true);
- _set_process(true);
return true;
}
@@ -744,14 +731,9 @@ bool Tween::stop(Object *p_object, StringName p_key) {
return true;
}
-bool Tween::is_stopped() const {
- return tell() >= get_runtime();
-}
-
bool Tween::stop_all() {
set_active(false);
- _set_process(false);
pending_update++;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
@@ -766,7 +748,6 @@ bool Tween::stop_all() {
bool Tween::resume(Object *p_object, StringName p_key) {
set_active(true);
- _set_process(true);
pending_update++;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
@@ -785,7 +766,6 @@ bool Tween::resume(Object *p_object, StringName p_key) {
bool Tween::resume_all() {
set_active(true);
- _set_process(true);
pending_update++;
for (List<InterpolateData>::Element *E = interpolates.front(); E; E = E->next()) {
@@ -834,7 +814,6 @@ bool Tween::remove_all() {
return true;
}
set_active(false);
- _set_process(false);
interpolates.clear();
return true;
}
@@ -1425,8 +1404,6 @@ Tween::Tween() {
//String autoplay;
tween_process_mode = TWEEN_PROCESS_IDLE;
- processing = false;
- active = false;
repeat = false;
speed_scale = 1;
pending_update = 0;
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 36094bf294..9997349c64 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -104,8 +104,6 @@ private:
String autoplay;
TweenProcessMode tween_process_mode;
- bool processing;
- bool active;
bool repeat;
float speed_scale;
mutable int pending_update;
@@ -133,7 +131,6 @@ private:
bool _apply_tween_value(InterpolateData &p_data, Variant &value);
void _tween_process(float p_delta);
- void _set_process(bool p_process, bool p_force = false);
void _remove(Object *p_object, StringName p_key, bool first_only);
protected:
@@ -162,7 +159,6 @@ public:
bool reset_all();
bool stop(Object *p_object, StringName p_key);
bool stop_all();
- bool is_stopped() const;
bool resume(Object *p_object, StringName p_key);
bool resume_all();
bool remove(Object *p_object, StringName p_key);
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index e2c730a56e..d95ec9e495 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -268,6 +268,10 @@ void GraphEdit::remove_child_notify(Node *p_child) {
void GraphEdit::_notification(int p_what) {
+ if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) {
+ port_grab_distance_horizontal = get_constant("port_grab_distance_horizontal");
+ port_grab_distance_vertical = get_constant("port_grab_distance_vertical");
+ }
if (p_what == NOTIFICATION_READY) {
Size2 hmin = h_scroll->get_combined_minimum_size();
Size2 vmin = v_scroll->get_combined_minimum_size();
@@ -343,8 +347,6 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
Ref<Texture> port = get_icon("port", "GraphNode");
- float grab_r_extend = 2.0;
- float grab_r = port->get_width() * 0.5 * grab_r_extend;
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -354,14 +356,14 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
- if (pos.distance_to(p_point) < grab_r)
+ if (create_hot_zone(pos).has_point(p_point))
return true;
}
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
- if (pos.distance_to(p_point) < grab_r) {
+ if (create_hot_zone(pos).has_point(p_point)) {
return true;
}
}
@@ -372,13 +374,11 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
- float grab_r_extend = 2.0;
Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT && mb->is_pressed()) {
Ref<Texture> port = get_icon("port", "GraphNode");
Vector2 mpos(mb->get_position().x, mb->get_position().y);
- float grab_r = port->get_width() * 0.5 * grab_r_extend;
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -388,7 +388,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_output_count(); j++) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
- if (pos.distance_to(mpos) < grab_r) {
+ if (create_hot_zone(pos).has_point(mpos)) {
if (valid_left_disconnect_types.has(gn->get_connection_output_type(j))) {
//check disconnect
@@ -435,8 +435,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
for (int j = 0; j < gn->get_connection_input_count(); j++) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
-
- if (pos.distance_to(mpos) < grab_r) {
+ if (create_hot_zone(pos).has_point(mpos)) {
if (right_disconnects || valid_right_disconnect_types.has(gn->get_connection_input_type(j))) {
//check disconnect
@@ -492,7 +491,6 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Ref<Texture> port = get_icon("port", "GraphNode");
Vector2 mpos = mm->get_position();
- float grab_r = port->get_width() * 0.5 * grab_r_extend;
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *gn = Object::cast_to<GraphNode>(get_child(i));
@@ -504,7 +502,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Vector2 pos = gn->get_connection_output_position(j) + gn->get_position();
int type = gn->get_connection_output_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && pos.distance_to(mpos) < grab_r) {
+ if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && create_hot_zone(pos).has_point(mpos)) {
connecting_target = true;
connecting_to = pos;
@@ -519,7 +517,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Vector2 pos = gn->get_connection_input_position(j) + gn->get_position();
int type = gn->get_connection_input_type(j);
- if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && pos.distance_to(mpos) < grab_r) {
+ if ((type == connecting_type || valid_connection_types.has(ConnType(type, connecting_type))) && create_hot_zone(pos).has_point(mpos)) {
connecting_target = true;
connecting_to = pos;
connecting_target_to = gn->get_name();
@@ -559,6 +557,10 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
}
}
+Rect2 GraphEdit::create_hot_zone(const Vector2 &pos) {
+ return Rect2(pos.x - port_grab_distance_horizontal, pos.y - port_grab_distance_vertical, port_grab_distance_horizontal * 2, port_grab_distance_vertical * 2);
+}
+
template <class Vector2>
static _FORCE_INLINE_ Vector2 _bezier_interp(real_t t, Vector2 start, Vector2 control_1, Vector2 control_2, Vector2 end) {
/* Formula from Wikipedia article on Bezier curves. */
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 14789001e4..64ba18681e 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -81,6 +81,9 @@ private:
HScrollBar *h_scroll;
VScrollBar *v_scroll;
+ float port_grab_distance_horizontal;
+ float port_grab_distance_vertical;
+
bool connecting;
String connecting_from;
bool connecting_out;
@@ -127,6 +130,9 @@ private:
Control *connections_layer;
GraphEditFilter *top_layer;
void _top_layer_input(const Ref<InputEvent> &p_ev);
+
+ Rect2 create_hot_zone(const Vector2 &pos);
+
void _top_layer_draw();
void _connections_layer_draw();
void _update_scroll_offset();
diff --git a/scene/gui/texture_progress.cpp b/scene/gui/texture_progress.cpp
index 82d983184b..6e4fe88dbf 100644
--- a/scene/gui/texture_progress.cpp
+++ b/scene/gui/texture_progress.cpp
@@ -309,15 +309,23 @@ void TextureProgress::_notification(int p_what) {
draw_texture_rect_region(progress, region, region, tint_progress);
} break;
case FILL_CLOCKWISE:
- case FILL_COUNTER_CLOCKWISE: {
+ case FILL_COUNTER_CLOCKWISE:
+ case FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE: {
float val = get_as_ratio() * rad_max_degrees / 360;
if (val == 1) {
Rect2 region = Rect2(Point2(), s);
draw_texture_rect_region(progress, region, region, tint_progress);
} else if (val != 0) {
Array pts;
- float direction = mode == FILL_CLOCKWISE ? 1 : -1;
- float start = rad_init_angle / 360;
+ float direction = mode == FILL_COUNTER_CLOCKWISE ? -1 : 1;
+ float start;
+
+ if (mode == FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE) {
+ start = rad_init_angle / 360 - val / 2;
+ } else {
+ start = rad_init_angle / 360;
+ }
+
float end = start + direction * val;
pts.append(start);
pts.append(end);
@@ -351,6 +359,14 @@ void TextureProgress::_notification(int p_what) {
draw_line(p - Point2(0, 8), p + Point2(0, 8), Color(0.9, 0.5, 0.5), 2);
}
} break;
+ case FILL_BILINEAR_LEFT_AND_RIGHT: {
+ Rect2 region = Rect2(Point2(s.x / 2 - s.x * get_as_ratio() / 2, 0), Size2(s.x * get_as_ratio(), s.y));
+ draw_texture_rect_region(progress, region, region, tint_progress);
+ } break;
+ case FILL_BILINEAR_TOP_AND_BOTTOM: {
+ Rect2 region = Rect2(Point2(0, s.y / 2 - s.y * get_as_ratio() / 2), Size2(s.x, s.y * get_as_ratio()));
+ draw_texture_rect_region(progress, region, region, tint_progress);
+ } break;
default:
draw_texture_rect_region(progress, Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), Rect2(Point2(), Size2(s.x * get_as_ratio(), s.y)), tint_progress);
}
@@ -364,7 +380,7 @@ void TextureProgress::_notification(int p_what) {
}
void TextureProgress::set_fill_mode(int p_fill) {
- ERR_FAIL_INDEX(p_fill, 6);
+ ERR_FAIL_INDEX(p_fill, 9);
mode = (FillMode)p_fill;
update();
}
@@ -446,7 +462,7 @@ void TextureProgress::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_under", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_under_texture", "get_under_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_over", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_over_texture", "get_over_texture");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture_progress", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_progress_texture", "get_progress_texture");
- ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise"), "set_fill_mode", "get_fill_mode");
+ ADD_PROPERTYNZ(PropertyInfo(Variant::INT, "fill_mode", PROPERTY_HINT_ENUM, "Left to Right,Right to Left,Top to Bottom,Bottom to Top,Clockwise,Counter Clockwise,Bilinear (Left and Right),Bilinear (Top and Bottom), Clockwise and Counter Clockwise"), "set_fill_mode", "get_fill_mode");
ADD_GROUP("Tint", "tint_");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_under", PROPERTY_HINT_COLOR_NO_ALPHA), "set_tint_under", "get_tint_under");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "tint_over", PROPERTY_HINT_COLOR_NO_ALPHA), "set_tint_over", "get_tint_over");
@@ -468,6 +484,9 @@ void TextureProgress::_bind_methods() {
BIND_ENUM_CONSTANT(FILL_BOTTOM_TO_TOP);
BIND_ENUM_CONSTANT(FILL_CLOCKWISE);
BIND_ENUM_CONSTANT(FILL_COUNTER_CLOCKWISE);
+ BIND_ENUM_CONSTANT(FILL_BILINEAR_LEFT_AND_RIGHT);
+ BIND_ENUM_CONSTANT(FILL_BILINEAR_TOP_AND_BOTTOM);
+ BIND_ENUM_CONSTANT(FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE);
}
TextureProgress::TextureProgress() {
diff --git a/scene/gui/texture_progress.h b/scene/gui/texture_progress.h
index 34158b5db5..a11e55234a 100644
--- a/scene/gui/texture_progress.h
+++ b/scene/gui/texture_progress.h
@@ -52,7 +52,10 @@ public:
FILL_TOP_TO_BOTTOM,
FILL_BOTTOM_TO_TOP,
FILL_CLOCKWISE,
- FILL_COUNTER_CLOCKWISE
+ FILL_COUNTER_CLOCKWISE,
+ FILL_BILINEAR_LEFT_AND_RIGHT,
+ FILL_BILINEAR_TOP_AND_BOTTOM,
+ FILL_CLOCKWISE_AND_COUNTER_CLOCKWISE
};
void set_fill_mode(int p_fill);
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/default_theme/default_theme.cpp b/scene/resources/default_theme/default_theme.cpp
index fe12e2f5f6..601f6fb558 100644
--- a/scene/resources/default_theme/default_theme.cpp
+++ b/scene/resources/default_theme/default_theme.cpp
@@ -883,6 +883,10 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("logo", "Icons", make_icon(logo_png));
+ // Visual Node Ports
+ theme->set_constant("port_grab_distance_horizontal", "GraphEdit", 48 * scale);
+ theme->set_constant("port_grab_distance_vertical", "GraphEdit", 6 * scale);
+
// Theme
default_icon = make_icon(error_icon_png);
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