summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct5
-rw-r--r--core/bind/core_bind.cpp5
-rw-r--r--core/bind/core_bind.h2
-rw-r--r--core/global_constants.cpp10
-rw-r--r--core/io/translation_loader_po.cpp40
-rw-r--r--core/math/aabb.cpp4
-rw-r--r--core/math/bsp_tree.cpp10
-rw-r--r--core/os/input_event.cpp119
-rw-r--r--core/os/input_event.h56
-rw-r--r--core/os/midi_driver.cpp107
-rw-r--r--core/os/midi_driver.h59
-rw-r--r--core/os/os.cpp10
-rw-r--r--core/os/os.h2
-rw-r--r--core/safe_refcount.cpp48
-rw-r--r--core/safe_refcount.h50
-rw-r--r--core/translation.cpp8
-rw-r--r--core/ustring.cpp21
-rw-r--r--core/ustring.h1
-rw-r--r--doc/classes/EditorImportPlugin.xml11
-rw-r--r--drivers/SCsub5
-rw-r--r--drivers/alsamidi/SCsub8
-rw-r--r--drivers/alsamidi/alsa_midi.cpp201
-rw-r--r--drivers/alsamidi/alsa_midi.h69
-rw-r--r--drivers/coremidi/SCsub8
-rw-r--r--drivers/coremidi/core_midi.cpp105
-rw-r--r--drivers/coremidi/core_midi.h61
-rw-r--r--drivers/dummy/texture_loader_dummy.cpp4
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp1
-rw-r--r--drivers/winmidi/SCsub8
-rw-r--r--drivers/winmidi/win_midi.cpp100
-rw-r--r--drivers/winmidi/win_midi.h61
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.cpp2
-rw-r--r--editor/code_editor.cpp339
-rw-r--r--editor/code_editor.h23
-rw-r--r--editor/editor_node.cpp3
-rw-r--r--editor/editor_settings.cpp12
-rw-r--r--editor/editor_themes.cpp3
-rw-r--r--editor/filesystem_dock.cpp26
-rw-r--r--editor/filesystem_dock.h7
-rw-r--r--editor/import/editor_scene_importer_gltf.cpp32
-rw-r--r--editor/import/editor_scene_importer_gltf.h2
-rw-r--r--editor/inspector_dock.cpp1
-rw-r--r--editor/plugins/script_editor_plugin.cpp373
-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/spatial_editor_plugin.cpp4
-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/property_editor.cpp2
-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/gdnative/nativescript/api_generator.cpp2
-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--modules/websocket/emws_client.cpp1
-rw-r--r--platform/android/audio_driver_opensl.cpp8
-rw-r--r--platform/android/dir_access_jandroid.cpp1
-rw-r--r--platform/android/export/export.cpp2
-rw-r--r--platform/android/java_glue.cpp4
-rw-r--r--platform/android/thread_jandroid.cpp2
-rw-r--r--platform/iphone/export/export.cpp6
-rw-r--r--platform/osx/detect.py4
-rw-r--r--platform/osx/os_osx.h2
-rw-r--r--platform/osx/os_osx.mm2
-rw-r--r--platform/windows/context_gl_win.cpp4
-rw-r--r--platform/windows/detect.py3
-rw-r--r--platform/windows/os_windows.cpp8
-rw-r--r--platform/windows/os_windows.h4
-rw-r--r--platform/x11/detect.py2
-rw-r--r--platform/x11/os_x11.cpp7
-rw-r--r--platform/x11/os_x11.h5
-rw-r--r--scene/2d/canvas_item.cpp3
-rw-r--r--scene/2d/line_builder.cpp2
-rw-r--r--scene/animation/tween.cpp67
-rw-r--r--scene/animation/tween.h4
-rw-r--r--scene/gui/control.cpp1
-rw-r--r--scene/gui/control.h1
-rw-r--r--scene/gui/graph_edit.cpp26
-rw-r--r--scene/gui/graph_edit.h6
-rw-r--r--scene/gui/menu_button.h3
-rw-r--r--scene/gui/text_edit.cpp9
-rw-r--r--scene/gui/texture_progress.cpp29
-rw-r--r--scene/gui/texture_progress.h5
-rw-r--r--scene/gui/tree.cpp19
-rw-r--r--scene/main/viewport.cpp29
-rw-r--r--scene/register_scene_types.cpp3
-rw-r--r--scene/resources/default_theme/default_theme.cpp4
-rw-r--r--scene/resources/dynamic_font.cpp4
-rw-r--r--scene/resources/text_file.cpp77
-rw-r--r--scene/resources/text_file.h55
-rw-r--r--scene/resources/tile_set.cpp2
-rw-r--r--servers/audio/audio_rb_resampler.cpp2
-rw-r--r--servers/physics/collision_solver_sat.cpp3
-rw-r--r--servers/visual_server.cpp18
106 files changed, 4121 insertions, 1044 deletions
diff --git a/SConstruct b/SConstruct
index 08c5b6d34f..1135f7a3bd 100644
--- a/SConstruct
+++ b/SConstruct
@@ -409,6 +409,11 @@ if selected_platform in platform_list:
env["PROGSUFFIX"] = suffix + env.module_version_string + env["PROGSUFFIX"]
env["OBJSUFFIX"] = suffix + env["OBJSUFFIX"]
+ # (SH)LIBSUFFIX will be used for our own built libraries
+ # LIBSUFFIXES contains LIBSUFFIX and SHLIBSUFFIX by default,
+ # so we need to append the default suffixes to keep the ability
+ # to link against thirdparty libraries (.a, .so, .dll, etc.).
+ env["LIBSUFFIXES"] += [env["LIBSUFFIX"], env["SHLIBSUFFIX"]]
env["LIBSUFFIX"] = suffix + env["LIBSUFFIX"]
env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"]
diff --git a/core/bind/core_bind.cpp b/core/bind/core_bind.cpp
index 7a14e85f20..af1d49ae8c 100644
--- a/core/bind/core_bind.cpp
+++ b/core/bind/core_bind.cpp
@@ -221,6 +221,10 @@ String _OS::get_audio_driver_name(int p_driver) const {
return OS::get_singleton()->get_audio_driver_name(p_driver);
}
+PoolStringArray _OS::get_connected_midi_inputs() {
+ return OS::get_singleton()->get_connected_midi_inputs();
+}
+
void _OS::set_video_mode(const Size2 &p_size, bool p_fullscreen, bool p_resizeable, int p_screen) {
OS::VideoMode vm;
@@ -1058,6 +1062,7 @@ void _OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_video_driver_name", "driver"), &_OS::get_video_driver_name);
ClassDB::bind_method(D_METHOD("get_audio_driver_count"), &_OS::get_audio_driver_count);
ClassDB::bind_method(D_METHOD("get_audio_driver_name", "driver"), &_OS::get_audio_driver_name);
+ ClassDB::bind_method(D_METHOD("get_connected_midi_inputs"), &_OS::get_connected_midi_inputs);
ClassDB::bind_method(D_METHOD("get_screen_count"), &_OS::get_screen_count);
ClassDB::bind_method(D_METHOD("get_current_screen"), &_OS::get_current_screen);
diff --git a/core/bind/core_bind.h b/core/bind/core_bind.h
index 48b7b74005..1729c23779 100644
--- a/core/bind/core_bind.h
+++ b/core/bind/core_bind.h
@@ -152,6 +152,8 @@ public:
virtual int get_audio_driver_count() const;
virtual String get_audio_driver_name(int p_driver) const;
+ virtual PoolStringArray get_connected_midi_inputs();
+
virtual int get_screen_count() const;
virtual int get_current_screen() const;
virtual void set_current_screen(int p_screen);
diff --git a/core/global_constants.cpp b/core/global_constants.cpp
index 5b4dd05dbf..187813f9d0 100644
--- a/core/global_constants.cpp
+++ b/core/global_constants.cpp
@@ -89,6 +89,7 @@ VARIANT_ENUM_CAST(KeyList);
VARIANT_ENUM_CAST(KeyModifierMask);
VARIANT_ENUM_CAST(ButtonList);
VARIANT_ENUM_CAST(JoystickList);
+VARIANT_ENUM_CAST(MidiMessageList);
void register_global_constants() {
@@ -458,6 +459,15 @@ void register_global_constants() {
BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_L2);
BIND_GLOBAL_ENUM_CONSTANT(JOY_ANALOG_R2);
+ // midi
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_OFF);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_NOTE_ON);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_AFTERTOUCH);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_CONTROL_CHANGE);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_PROGRAM_CHANGE);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_CHANNEL_PRESSURE);
+ BIND_GLOBAL_ENUM_CONSTANT(MIDI_MESSAGE_PITCH_BEND);
+
// error list
BIND_GLOBAL_ENUM_CONSTANT(OK);
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/core/math/aabb.cpp b/core/math/aabb.cpp
index cff19f990c..e2e71dda92 100644
--- a/core/math/aabb.cpp
+++ b/core/math/aabb.cpp
@@ -245,7 +245,6 @@ Vector3 AABB::get_longest_axis() const {
if (size.z > max_size) {
axis = Vector3(0, 0, 1);
- max_size = size.z;
}
return axis;
@@ -262,7 +261,6 @@ int AABB::get_longest_axis_index() const {
if (size.z > max_size) {
axis = 2;
- max_size = size.z;
}
return axis;
@@ -280,7 +278,6 @@ Vector3 AABB::get_shortest_axis() const {
if (size.z < max_size) {
axis = Vector3(0, 0, 1);
- max_size = size.z;
}
return axis;
@@ -297,7 +294,6 @@ int AABB::get_shortest_axis_index() const {
if (size.z < max_size) {
axis = 2;
- max_size = size.z;
}
return axis;
diff --git a/core/math/bsp_tree.cpp b/core/math/bsp_tree.cpp
index b1424e1d78..2e184f7a88 100644
--- a/core/math/bsp_tree.cpp
+++ b/core/math/bsp_tree.cpp
@@ -244,10 +244,8 @@ bool BSP_Tree::point_is_inside(const Vector3 &p_point) const {
const Node *nodesptr = &nodes[0];
const Plane *planesptr = &planes[0];
- int plane_count = planes.size();
int idx = node_count - 1;
- int steps = 0;
while (true) {
@@ -259,21 +257,19 @@ bool BSP_Tree::point_is_inside(const Vector3 &p_point) const {
return true;
}
- uint16_t plane = nodesptr[idx].plane;
#ifdef DEBUG_ENABLED
-
+ int plane_count = planes.size();
+ uint16_t plane = nodesptr[idx].plane;
ERR_FAIL_INDEX_V(plane, plane_count, false);
#endif
+
bool over = planesptr[nodesptr[idx].plane].is_point_over(p_point);
idx = over ? nodes[idx].over : nodes[idx].under;
#ifdef DEBUG_ENABLED
-
ERR_FAIL_COND_V(idx < MAX_NODES && idx >= node_count, false);
#endif
-
- steps++;
}
return false;
diff --git a/core/os/input_event.cpp b/core/os/input_event.cpp
index ca6446d015..e94ccb4f48 100644
--- a/core/os/input_event.cpp
+++ b/core/os/input_event.cpp
@@ -1080,3 +1080,122 @@ InputEventPanGesture::InputEventPanGesture() {
delta = Vector2(0, 0);
}
+/////////////////////////////
+
+void InputEventMIDI::set_channel(const int p_channel) {
+
+ channel = p_channel;
+}
+
+int InputEventMIDI::get_channel() const {
+ return channel;
+}
+
+void InputEventMIDI::set_message(const int p_message) {
+
+ message = p_message;
+}
+
+int InputEventMIDI::get_message() const {
+ return message;
+}
+
+void InputEventMIDI::set_pitch(const int p_pitch) {
+
+ pitch = p_pitch;
+}
+
+int InputEventMIDI::get_pitch() const {
+ return pitch;
+}
+
+void InputEventMIDI::set_velocity(const int p_velocity) {
+
+ velocity = p_velocity;
+}
+
+int InputEventMIDI::get_velocity() const {
+ return velocity;
+}
+
+void InputEventMIDI::set_instrument(const int p_instrument) {
+
+ instrument = p_instrument;
+}
+
+int InputEventMIDI::get_instrument() const {
+ return instrument;
+}
+
+void InputEventMIDI::set_pressure(const int p_pressure) {
+
+ pressure = p_pressure;
+}
+
+int InputEventMIDI::get_pressure() const {
+ return pressure;
+}
+
+void InputEventMIDI::set_controller_number(const int p_controller_number) {
+
+ controller_number = p_controller_number;
+}
+
+int InputEventMIDI::get_controller_number() const {
+ return controller_number;
+}
+
+void InputEventMIDI::set_controller_value(const int p_controller_value) {
+
+ controller_value = p_controller_value;
+}
+
+int InputEventMIDI::get_controller_value() const {
+ return controller_value;
+}
+
+String InputEventMIDI::as_text() const {
+
+ return "InputEventMIDI : channel=(" + itos(get_channel()) + "), message=(" + itos(get_message()) + ")";
+}
+
+void InputEventMIDI::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_channel", "channel"), &InputEventMIDI::set_channel);
+ ClassDB::bind_method(D_METHOD("get_channel"), &InputEventMIDI::get_channel);
+ ClassDB::bind_method(D_METHOD("set_message", "message"), &InputEventMIDI::set_message);
+ ClassDB::bind_method(D_METHOD("get_message"), &InputEventMIDI::get_message);
+ ClassDB::bind_method(D_METHOD("set_pitch", "pitch"), &InputEventMIDI::set_pitch);
+ ClassDB::bind_method(D_METHOD("get_pitch"), &InputEventMIDI::get_pitch);
+ ClassDB::bind_method(D_METHOD("set_velocity", "velocity"), &InputEventMIDI::set_velocity);
+ ClassDB::bind_method(D_METHOD("get_velocity"), &InputEventMIDI::get_velocity);
+ ClassDB::bind_method(D_METHOD("set_instrument", "instrument"), &InputEventMIDI::set_instrument);
+ ClassDB::bind_method(D_METHOD("get_instrument"), &InputEventMIDI::get_instrument);
+ ClassDB::bind_method(D_METHOD("set_pressure", "pressure"), &InputEventMIDI::set_pressure);
+ ClassDB::bind_method(D_METHOD("get_pressure"), &InputEventMIDI::get_pressure);
+ ClassDB::bind_method(D_METHOD("set_controller_number", "controller_number"), &InputEventMIDI::set_controller_number);
+ ClassDB::bind_method(D_METHOD("get_controller_number"), &InputEventMIDI::get_controller_number);
+ ClassDB::bind_method(D_METHOD("set_controller_value", "controller_value"), &InputEventMIDI::set_controller_value);
+ ClassDB::bind_method(D_METHOD("get_controller_value"), &InputEventMIDI::get_controller_value);
+
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "channel"), "set_channel", "get_channel");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "message"), "set_message", "get_message");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "pitch"), "set_pitch", "get_pitch");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "velocity"), "set_velocity", "get_velocity");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "instrument"), "set_instrument", "get_instrument");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "pressure"), "set_pressure", "get_pressure");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_number"), "set_controller_number", "get_controller_number");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "controller_value"), "set_controller_value", "get_controller_value");
+}
+
+InputEventMIDI::InputEventMIDI() {
+
+ channel = 0;
+ message = 0;
+ pitch = 0;
+ velocity = 0;
+ instrument = 0;
+ pressure = 0;
+ controller_number = 0;
+ controller_value = 0;
+}
diff --git a/core/os/input_event.h b/core/os/input_event.h
index bd1a85ce29..04126fee77 100644
--- a/core/os/input_event.h
+++ b/core/os/input_event.h
@@ -140,6 +140,16 @@ enum JoystickList {
JOY_ANALOG_R2 = JOY_AXIS_7,
};
+enum MidiMessageList {
+ MIDI_MESSAGE_NOTE_OFF = 0x8,
+ MIDI_MESSAGE_NOTE_ON = 0x9,
+ MIDI_MESSAGE_AFTERTOUCH = 0xA,
+ MIDI_MESSAGE_CONTROL_CHANGE = 0xB,
+ MIDI_MESSAGE_PROGRAM_CHANGE = 0xC,
+ MIDI_MESSAGE_CHANNEL_PRESSURE = 0xD,
+ MIDI_MESSAGE_PITCH_BEND = 0xE,
+};
+
/**
* Input Modifier Status
* for keyboard/mouse events.
@@ -525,4 +535,50 @@ public:
InputEventPanGesture();
};
+
+class InputEventMIDI : public InputEvent {
+ GDCLASS(InputEventMIDI, InputEvent)
+
+ int channel;
+ int message;
+ int pitch;
+ int velocity;
+ int instrument;
+ int pressure;
+ int controller_number;
+ int controller_value;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_channel(const int p_channel);
+ int get_channel() const;
+
+ void set_message(const int p_message);
+ int get_message() const;
+
+ void set_pitch(const int p_pitch);
+ int get_pitch() const;
+
+ void set_velocity(const int p_velocity);
+ int get_velocity() const;
+
+ void set_instrument(const int p_instrument);
+ int get_instrument() const;
+
+ void set_pressure(const int p_pressure);
+ int get_pressure() const;
+
+ void set_controller_number(const int p_controller_number);
+ int get_controller_number() const;
+
+ void set_controller_value(const int p_controller_value);
+ int get_controller_value() const;
+
+ virtual String as_text() const;
+
+ InputEventMIDI();
+};
+
#endif
diff --git a/core/os/midi_driver.cpp b/core/os/midi_driver.cpp
new file mode 100644
index 0000000000..7b4f84473c
--- /dev/null
+++ b/core/os/midi_driver.cpp
@@ -0,0 +1,107 @@
+/*************************************************************************/
+/* midi_driver.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 "midi_driver.h"
+
+#include "main/input_default.h"
+#include "os/os.h"
+
+MIDIDriver *MIDIDriver::singleton = NULL;
+MIDIDriver *MIDIDriver::get_singleton() {
+
+ return singleton;
+}
+
+void MIDIDriver::set_singleton() {
+
+ singleton = this;
+}
+
+void MIDIDriver::receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length) {
+
+ Ref<InputEventMIDI> event;
+ event.instance();
+
+ if (length >= 1) {
+ event->set_channel(data[0] & 0xF);
+ event->set_message(data[0] >> 4);
+ }
+
+ switch (event->get_message()) {
+ case MIDI_MESSAGE_AFTERTOUCH:
+ if (length >= 3) {
+ event->set_pitch(data[1]);
+ event->set_pressure(data[2]);
+ }
+ break;
+
+ case MIDI_MESSAGE_CONTROL_CHANGE:
+ if (length >= 3) {
+ event->set_controller_number(data[1]);
+ event->set_controller_value(data[2]);
+ }
+ break;
+
+ case MIDI_MESSAGE_NOTE_ON:
+ case MIDI_MESSAGE_NOTE_OFF:
+ case MIDI_MESSAGE_PITCH_BEND:
+ if (length >= 3) {
+ event->set_pitch(data[1]);
+ event->set_velocity(data[2]);
+ }
+ break;
+
+ case MIDI_MESSAGE_PROGRAM_CHANGE:
+ if (length >= 2) {
+ event->set_instrument(data[1]);
+ }
+ break;
+
+ case MIDI_MESSAGE_CHANNEL_PRESSURE:
+ if (length >= 2) {
+ event->set_pressure(data[1]);
+ }
+ break;
+ }
+
+ InputDefault *id = Object::cast_to<InputDefault>(Input::get_singleton());
+ id->parse_input_event(event);
+}
+
+PoolStringArray MIDIDriver::get_connected_inputs() {
+
+ PoolStringArray list;
+ return list;
+}
+
+MIDIDriver::MIDIDriver() {
+
+ set_singleton();
+}
diff --git a/core/os/midi_driver.h b/core/os/midi_driver.h
new file mode 100644
index 0000000000..1a3a67a411
--- /dev/null
+++ b/core/os/midi_driver.h
@@ -0,0 +1,59 @@
+/*************************************************************************/
+/* midi_driver.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 MIDI_DRIVER_H
+#define MIDI_DRIVER_H
+
+#include "core/variant.h"
+#include "typedefs.h"
+/**
+ * Multi-Platform abstraction for accessing to MIDI.
+ */
+
+class MIDIDriver {
+
+ static MIDIDriver *singleton;
+
+public:
+ static MIDIDriver *get_singleton();
+ void set_singleton();
+
+ virtual Error open() = 0;
+ virtual void close() = 0;
+
+ virtual PoolStringArray get_connected_inputs();
+
+ static void receive_input_packet(uint64_t timestamp, uint8_t *data, uint32_t length);
+
+ MIDIDriver();
+ virtual ~MIDIDriver() {}
+};
+
+#endif
diff --git a/core/os/os.cpp b/core/os/os.cpp
index 89866e4044..8dcf0990fc 100644
--- a/core/os/os.cpp
+++ b/core/os/os.cpp
@@ -33,6 +33,7 @@
#include "dir_access.h"
#include "input.h"
#include "os/file_access.h"
+#include "os/midi_driver.h"
#include "project_settings.h"
#include "servers/audio_server.h"
#include "version_generated.gen.h"
@@ -672,6 +673,15 @@ List<String> OS::get_restart_on_exit_arguments() const {
return restart_commandline;
}
+PoolStringArray OS::get_connected_midi_inputs() {
+
+ if (MIDIDriver::get_singleton())
+ return MIDIDriver::get_singleton()->get_connected_inputs();
+
+ PoolStringArray list;
+ return list;
+}
+
OS::OS() {
void *volatile stack_bottom;
diff --git a/core/os/os.h b/core/os/os.h
index 4e0cb003fb..dd783408e8 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -189,6 +189,8 @@ public:
virtual int get_audio_driver_count() const;
virtual const char *get_audio_driver_name(int p_driver) const;
+ virtual PoolStringArray get_connected_midi_inputs();
+
virtual int get_screen_count() const { return 1; }
virtual int get_current_screen() const { return 0; }
virtual void set_current_screen(int p_screen) {}
diff --git a/core/safe_refcount.cpp b/core/safe_refcount.cpp
index 3b203f6977..692ff722f3 100644
--- a/core/safe_refcount.cpp
+++ b/core/safe_refcount.cpp
@@ -57,113 +57,113 @@
return m_val; \
}
-_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(register uint32_t *pw){
+_ALWAYS_INLINE_ uint32_t _atomic_conditional_increment_impl(volatile uint32_t *pw){
ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONG, InterlockedCompareExchange, uint32_t)
}
-_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(register uint32_t *pw) {
+_ALWAYS_INLINE_ uint32_t _atomic_decrement_impl(volatile uint32_t *pw) {
return InterlockedDecrement((LONG volatile *)pw);
}
-_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(register uint32_t *pw) {
+_ALWAYS_INLINE_ uint32_t _atomic_increment_impl(volatile uint32_t *pw) {
return InterlockedIncrement((LONG volatile *)pw);
}
-_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(register uint32_t *pw, register uint32_t val) {
+_ALWAYS_INLINE_ uint32_t _atomic_sub_impl(volatile uint32_t *pw, volatile uint32_t val) {
return InterlockedExchangeAdd((LONG volatile *)pw, -(int32_t)val) - val;
}
-_ALWAYS_INLINE_ uint32_t _atomic_add_impl(register uint32_t *pw, register uint32_t val) {
+_ALWAYS_INLINE_ uint32_t _atomic_add_impl(volatile uint32_t *pw, volatile uint32_t val) {
return InterlockedAdd((LONG volatile *)pw, val);
}
-_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(register uint32_t *pw, register uint32_t val){
+_ALWAYS_INLINE_ uint32_t _atomic_exchange_if_greater_impl(volatile uint32_t *pw, volatile uint32_t val){
ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONG, InterlockedCompareExchange, uint32_t)
}
-_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(register uint64_t *pw){
+_ALWAYS_INLINE_ uint64_t _atomic_conditional_increment_impl(volatile uint64_t *pw){
ATOMIC_CONDITIONAL_INCREMENT_BODY(pw, LONGLONG, InterlockedCompareExchange64, uint64_t)
}
-_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(register uint64_t *pw) {
+_ALWAYS_INLINE_ uint64_t _atomic_decrement_impl(volatile uint64_t *pw) {
return InterlockedDecrement64((LONGLONG volatile *)pw);
}
-_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(register uint64_t *pw) {
+_ALWAYS_INLINE_ uint64_t _atomic_increment_impl(volatile uint64_t *pw) {
return InterlockedIncrement64((LONGLONG volatile *)pw);
}
-_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(register uint64_t *pw, register uint64_t val) {
+_ALWAYS_INLINE_ uint64_t _atomic_sub_impl(volatile uint64_t *pw, volatile uint64_t val) {
return InterlockedExchangeAdd64((LONGLONG volatile *)pw, -(int64_t)val) - val;
}
-_ALWAYS_INLINE_ uint64_t _atomic_add_impl(register uint64_t *pw, register uint64_t val) {
+_ALWAYS_INLINE_ uint64_t _atomic_add_impl(volatile uint64_t *pw, volatile uint64_t val) {
return InterlockedAdd64((LONGLONG volatile *)pw, val);
}
-_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(register uint64_t *pw, register uint64_t val){
+_ALWAYS_INLINE_ uint64_t _atomic_exchange_if_greater_impl(volatile uint64_t *pw, volatile uint64_t val){
ATOMIC_EXCHANGE_IF_GREATER_BODY(pw, val, LONGLONG, InterlockedCompareExchange64, uint64_t)
}
// The actual advertised functions; they'll call the right implementation
-uint32_t atomic_conditional_increment(register uint32_t *pw) {
+uint32_t atomic_conditional_increment(volatile uint32_t *pw) {
return _atomic_conditional_increment_impl(pw);
}
-uint32_t atomic_decrement(register uint32_t *pw) {
+uint32_t atomic_decrement(volatile uint32_t *pw) {
return _atomic_decrement_impl(pw);
}
-uint32_t atomic_increment(register uint32_t *pw) {
+uint32_t atomic_increment(volatile uint32_t *pw) {
return _atomic_increment_impl(pw);
}
-uint32_t atomic_sub(register uint32_t *pw, register uint32_t val) {
+uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val) {
return _atomic_sub_impl(pw, val);
}
-uint32_t atomic_add(register uint32_t *pw, register uint32_t val) {
+uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val) {
return _atomic_add_impl(pw, val);
}
-uint32_t atomic_exchange_if_greater(register uint32_t *pw, register uint32_t val) {
+uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val) {
return _atomic_exchange_if_greater_impl(pw, val);
}
-uint64_t atomic_conditional_increment(register uint64_t *pw) {
+uint64_t atomic_conditional_increment(volatile uint64_t *pw) {
return _atomic_conditional_increment_impl(pw);
}
-uint64_t atomic_decrement(register uint64_t *pw) {
+uint64_t atomic_decrement(volatile uint64_t *pw) {
return _atomic_decrement_impl(pw);
}
-uint64_t atomic_increment(register uint64_t *pw) {
+uint64_t atomic_increment(volatile uint64_t *pw) {
return _atomic_increment_impl(pw);
}
-uint64_t atomic_sub(register uint64_t *pw, register uint64_t val) {
+uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val) {
return _atomic_sub_impl(pw, val);
}
-uint64_t atomic_add(register uint64_t *pw, register uint64_t val) {
+uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val) {
return _atomic_add_impl(pw, val);
}
-uint64_t atomic_exchange_if_greater(register uint64_t *pw, register uint64_t val) {
+uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val) {
return _atomic_exchange_if_greater_impl(pw, val);
}
#endif
diff --git a/core/safe_refcount.h b/core/safe_refcount.h
index eff209c2db..36bcf5e576 100644
--- a/core/safe_refcount.h
+++ b/core/safe_refcount.h
@@ -44,7 +44,7 @@
/* Bogus implementation unaware of multiprocessing */
template <class T>
-static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
if (*pw == 0)
return 0;
@@ -55,7 +55,7 @@ static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) {
}
template <class T>
-static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
(*pw)--;
@@ -63,7 +63,7 @@ static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) {
}
template <class T>
-static _ALWAYS_INLINE_ T atomic_increment(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
(*pw)++;
@@ -71,7 +71,7 @@ static _ALWAYS_INLINE_ T atomic_increment(register T *pw) {
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
(*pw) -= val;
@@ -79,7 +79,7 @@ static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) {
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
(*pw) += val;
@@ -87,7 +87,7 @@ static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) {
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
if (val > *pw)
*pw = val;
@@ -103,7 +103,7 @@ static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V v
// Clang states it supports GCC atomic builtins.
template <class T>
-static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_conditional_increment(volatile T *pw) {
while (true) {
T tmp = static_cast<T const volatile &>(*pw);
@@ -115,31 +115,31 @@ static _ALWAYS_INLINE_ T atomic_conditional_increment(register T *pw) {
}
template <class T>
-static _ALWAYS_INLINE_ T atomic_decrement(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_decrement(volatile T *pw) {
return __sync_sub_and_fetch(pw, 1);
}
template <class T>
-static _ALWAYS_INLINE_ T atomic_increment(register T *pw) {
+static _ALWAYS_INLINE_ T atomic_increment(volatile T *pw) {
return __sync_add_and_fetch(pw, 1);
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_sub(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_sub(volatile T *pw, volatile V val) {
return __sync_sub_and_fetch(pw, val);
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_add(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_add(volatile T *pw, volatile V val) {
return __sync_add_and_fetch(pw, val);
}
template <class T, class V>
-static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V val) {
+static _ALWAYS_INLINE_ T atomic_exchange_if_greater(volatile T *pw, volatile V val) {
while (true) {
T tmp = static_cast<T const volatile &>(*pw);
@@ -153,19 +153,19 @@ static _ALWAYS_INLINE_ T atomic_exchange_if_greater(register T *pw, register V v
#elif defined(_MSC_VER)
// For MSVC use a separate compilation unit to prevent windows.h from polluting
// the global namespace.
-uint32_t atomic_conditional_increment(register uint32_t *pw);
-uint32_t atomic_decrement(register uint32_t *pw);
-uint32_t atomic_increment(register uint32_t *pw);
-uint32_t atomic_sub(register uint32_t *pw, register uint32_t val);
-uint32_t atomic_add(register uint32_t *pw, register uint32_t val);
-uint32_t atomic_exchange_if_greater(register uint32_t *pw, register uint32_t val);
-
-uint64_t atomic_conditional_increment(register uint64_t *pw);
-uint64_t atomic_decrement(register uint64_t *pw);
-uint64_t atomic_increment(register uint64_t *pw);
-uint64_t atomic_sub(register uint64_t *pw, register uint64_t val);
-uint64_t atomic_add(register uint64_t *pw, register uint64_t val);
-uint64_t atomic_exchange_if_greater(register uint64_t *pw, register uint64_t val);
+uint32_t atomic_conditional_increment(volatile uint32_t *pw);
+uint32_t atomic_decrement(volatile uint32_t *pw);
+uint32_t atomic_increment(volatile uint32_t *pw);
+uint32_t atomic_sub(volatile uint32_t *pw, volatile uint32_t val);
+uint32_t atomic_add(volatile uint32_t *pw, volatile uint32_t val);
+uint32_t atomic_exchange_if_greater(volatile uint32_t *pw, volatile uint32_t val);
+
+uint64_t atomic_conditional_increment(volatile uint64_t *pw);
+uint64_t atomic_decrement(volatile uint64_t *pw);
+uint64_t atomic_increment(volatile uint64_t *pw);
+uint64_t atomic_sub(volatile uint64_t *pw, volatile uint64_t val);
+uint64_t atomic_add(volatile uint64_t *pw, volatile uint64_t val);
+uint64_t atomic_exchange_if_greater(volatile uint64_t *pw, volatile uint64_t val);
#else
//no threads supported?
diff --git a/core/translation.cpp b/core/translation.cpp
index aaa4de5912..78115c3749 100644
--- a/core/translation.cpp
+++ b/core/translation.cpp
@@ -1171,13 +1171,11 @@ void TranslationServer::_bind_methods() {
void TranslationServer::load_translations() {
String locale = get_locale();
- bool found = _load_translations("locale/translations"); //all
+ _load_translations("locale/translations"); //all
+ _load_translations("locale/translations_" + locale.substr(0, 2));
- if (_load_translations("locale/translations_" + locale.substr(0, 2)))
- found = true;
if (locale.substr(0, 2) != locale) {
- if (_load_translations("locale/translations_" + locale))
- found = true;
+ _load_translations("locale/translations_" + locale);
}
}
diff --git a/core/ustring.cpp b/core/ustring.cpp
index bb08dd13c4..f552cb13ac 100644
--- a/core/ustring.cpp
+++ b/core/ustring.cpp
@@ -161,14 +161,21 @@ void String::copy_from(const CharType *p_cstr, int p_clip_to) {
return;
}
- resize(len + 1);
- set(len, 0);
+ copy_from_unchecked(p_cstr, len);
+}
- CharType *dst = &operator[](0);
+// assumes the following have already been validated:
+// p_char != NULL
+// p_length > 0
+// p_length <= p_char strlen
+void String::copy_from_unchecked(const CharType *p_char, int p_length) {
+ resize(p_length + 1);
+ set(p_length, 0);
- for (int i = 0; i < len; i++) {
+ CharType *dst = &operator[](0);
- dst[i] = p_cstr[i];
+ for (int i = 0; i < p_length; i++) {
+ dst[i] = p_char[i];
}
}
@@ -2246,7 +2253,9 @@ String String::substr(int p_from, int p_chars) const {
return String(*this);
}
- return String(&c_str()[p_from], p_chars);
+ String s = String();
+ s.copy_from_unchecked(&c_str()[p_from], p_chars);
+ return s;
}
int String::find_last(const String &p_str) const {
diff --git a/core/ustring.h b/core/ustring.h
index b57e9629d9..001d111d64 100644
--- a/core/ustring.h
+++ b/core/ustring.h
@@ -65,6 +65,7 @@ class String : public Vector<CharType> {
void copy_from(const char *p_cstr);
void copy_from(const CharType *p_cstr, int p_clip_to = -1);
void copy_from(const CharType &p_char);
+ void copy_from_unchecked(const CharType *p_char, int p_length);
bool _base_is_subsequence_of(const String &p_string, bool case_insensitive) const;
public:
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/drivers/SCsub b/drivers/SCsub
index 2c5e9434e8..f9cfa3fb05 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -21,6 +21,11 @@ if (env["platform"] == "windows"):
if env['xaudio2']:
SConscript("xaudio2/SCsub")
+# Midi drivers
+SConscript('alsamidi/SCsub')
+SConscript('coremidi/SCsub')
+SConscript('winmidi/SCsub')
+
# Graphics drivers
if (env["platform"] != "server"):
SConscript('gles3/SCsub')
diff --git a/drivers/alsamidi/SCsub b/drivers/alsamidi/SCsub
new file mode 100644
index 0000000000..233593b0f9
--- /dev/null
+++ b/drivers/alsamidi/SCsub
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+Import('env')
+
+# Driver source files
+env.add_source_files(env.drivers_sources, "*.cpp")
+
+Export('env')
diff --git a/drivers/alsamidi/alsa_midi.cpp b/drivers/alsamidi/alsa_midi.cpp
new file mode 100644
index 0000000000..599470d7e0
--- /dev/null
+++ b/drivers/alsamidi/alsa_midi.cpp
@@ -0,0 +1,201 @@
+/*************************************************************************/
+/* alsa_midi.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. */
+/*************************************************************************/
+
+#ifdef ALSAMIDI_ENABLED
+
+#include <errno.h>
+
+#include "alsa_midi.h"
+#include "os/os.h"
+#include "print_string.h"
+
+static int get_message_size(uint8_t message) {
+ switch (message & 0xF0) {
+ case 0x80: // note off
+ case 0x90: // note on
+ case 0xA0: // aftertouch
+ case 0xB0: // continuous controller
+ return 3;
+
+ case 0xC0: // patch change
+ case 0xD0: // channel pressure
+ case 0xE0: // pitch bend
+ return 2;
+ }
+
+ return 256;
+}
+
+void MIDIDriverALSAMidi::thread_func(void *p_udata) {
+ MIDIDriverALSAMidi *md = (MIDIDriverALSAMidi *)p_udata;
+ uint64_t timestamp = 0;
+ uint8_t buffer[256];
+ int expected_size = 255;
+ int bytes = 0;
+
+ while (!md->exit_thread) {
+ int ret;
+
+ md->lock();
+
+ for (int i = 0; i < md->connected_inputs.size(); i++) {
+ snd_rawmidi_t *midi_in = md->connected_inputs[i];
+ do {
+ uint8_t byte = 0;
+ ret = snd_rawmidi_read(midi_in, &byte, 1);
+ if (ret < 0) {
+ if (ret != -EAGAIN) {
+ ERR_PRINTS("snd_rawmidi_read error: " + String(snd_strerror(ret)));
+ }
+ } else {
+ if (byte & 0x80) {
+ // Flush previous packet if there is any
+ if (bytes) {
+ md->receive_input_packet(timestamp, buffer, bytes);
+ bytes = 0;
+ }
+ expected_size = get_message_size(byte);
+ }
+
+ if (bytes < 256) {
+ buffer[bytes++] = byte;
+ // If we know the size of the current packet receive it if it reached the expected size
+ if (bytes >= expected_size) {
+ md->receive_input_packet(timestamp, buffer, bytes);
+ bytes = 0;
+ }
+ }
+ }
+ } while (ret > 0);
+ }
+
+ md->unlock();
+
+ OS::get_singleton()->delay_usec(1000);
+ }
+}
+
+Error MIDIDriverALSAMidi::open() {
+
+ void **hints;
+
+ if (snd_device_name_hint(-1, "rawmidi", &hints) < 0)
+ return ERR_CANT_OPEN;
+
+ int i = 0;
+ for (void **n = hints; *n != NULL; n++) {
+ char *name = snd_device_name_get_hint(*n, "NAME");
+
+ if (name != NULL) {
+ snd_rawmidi_t *midi_in;
+ int ret = snd_rawmidi_open(&midi_in, NULL, name, SND_RAWMIDI_NONBLOCK);
+ if (ret >= 0) {
+ connected_inputs.insert(i++, midi_in);
+ }
+ }
+
+ if (name != NULL)
+ free(name);
+ }
+ snd_device_name_free_hint(hints);
+
+ mutex = Mutex::create();
+ thread = Thread::create(MIDIDriverALSAMidi::thread_func, this);
+
+ return OK;
+}
+
+void MIDIDriverALSAMidi::close() {
+
+ if (thread) {
+ exit_thread = true;
+ Thread::wait_to_finish(thread);
+
+ memdelete(thread);
+ thread = NULL;
+ }
+
+ if (mutex) {
+ memdelete(mutex);
+ mutex = NULL;
+ }
+
+ for (int i = 0; i < connected_inputs.size(); i++) {
+ snd_rawmidi_t *midi_in = connected_inputs[i];
+ snd_rawmidi_close(midi_in);
+ }
+ connected_inputs.clear();
+}
+
+void MIDIDriverALSAMidi::lock() const {
+
+ if (mutex)
+ mutex->lock();
+}
+
+void MIDIDriverALSAMidi::unlock() const {
+
+ if (mutex)
+ mutex->unlock();
+}
+
+PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() {
+
+ PoolStringArray list;
+
+ lock();
+ for (int i = 0; i < connected_inputs.size(); i++) {
+ snd_rawmidi_t *midi_in = connected_inputs[i];
+ snd_rawmidi_info_t *info;
+
+ snd_rawmidi_info_malloc(&info);
+ snd_rawmidi_info(midi_in, info);
+ list.push_back(snd_rawmidi_info_get_name(info));
+ snd_rawmidi_info_free(info);
+ }
+ unlock();
+
+ return list;
+}
+
+MIDIDriverALSAMidi::MIDIDriverALSAMidi() {
+
+ mutex = NULL;
+ thread = NULL;
+
+ exit_thread = false;
+}
+
+MIDIDriverALSAMidi::~MIDIDriverALSAMidi() {
+
+ close();
+}
+
+#endif
diff --git a/drivers/alsamidi/alsa_midi.h b/drivers/alsamidi/alsa_midi.h
new file mode 100644
index 0000000000..90e458a365
--- /dev/null
+++ b/drivers/alsamidi/alsa_midi.h
@@ -0,0 +1,69 @@
+/*************************************************************************/
+/* alsa_midi.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. */
+/*************************************************************************/
+
+#ifdef ALSAMIDI_ENABLED
+
+#ifndef ALSA_MIDI_H
+#define ALSA_MIDI_H
+
+#include <alsa/asoundlib.h>
+#include <stdio.h>
+
+#include "core/os/mutex.h"
+#include "core/os/thread.h"
+#include "core/vector.h"
+#include "os/midi_driver.h"
+
+class MIDIDriverALSAMidi : public MIDIDriver {
+
+ Thread *thread;
+ Mutex *mutex;
+
+ Vector<snd_rawmidi_t *> connected_inputs;
+
+ bool exit_thread;
+
+ static void thread_func(void *p_udata);
+
+ void lock() const;
+ void unlock() const;
+
+public:
+ virtual Error open();
+ virtual void close();
+
+ virtual PoolStringArray get_connected_inputs();
+
+ MIDIDriverALSAMidi();
+ virtual ~MIDIDriverALSAMidi();
+};
+
+#endif
+#endif
diff --git a/drivers/coremidi/SCsub b/drivers/coremidi/SCsub
new file mode 100644
index 0000000000..233593b0f9
--- /dev/null
+++ b/drivers/coremidi/SCsub
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+Import('env')
+
+# Driver source files
+env.add_source_files(env.drivers_sources, "*.cpp")
+
+Export('env')
diff --git a/drivers/coremidi/core_midi.cpp b/drivers/coremidi/core_midi.cpp
new file mode 100644
index 0000000000..3619be4a8e
--- /dev/null
+++ b/drivers/coremidi/core_midi.cpp
@@ -0,0 +1,105 @@
+/*************************************************************************/
+/* core_midi.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. */
+/*************************************************************************/
+
+#ifdef COREMIDI_ENABLED
+
+#include "core_midi.h"
+#include "print_string.h"
+
+#include <CoreAudio/HostTime.h>
+#include <CoreServices/CoreServices.h>
+
+void MIDIDriverCoreMidi::read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con) {
+ MIDIPacket *packet = const_cast<MIDIPacket *>(packet_list->packet);
+ for (int i = 0; i < packet_list->numPackets; i++) {
+ receive_input_packet(packet->timeStamp, packet->data, packet->length);
+ packet = MIDIPacketNext(packet);
+ }
+}
+
+Error MIDIDriverCoreMidi::open() {
+
+ CFStringRef name = CFStringCreateWithCString(NULL, "Godot", kCFStringEncodingASCII);
+ OSStatus result = MIDIClientCreate(name, NULL, NULL, &client);
+ CFRelease(name);
+ if (result != noErr) {
+ ERR_PRINTS("MIDIClientCreate failed: " + String(GetMacOSStatusErrorString(result)));
+ return ERR_CANT_OPEN;
+ }
+
+ result = MIDIInputPortCreate(client, CFSTR("Godot Input"), MIDIDriverCoreMidi::read, (void *)this, &port_in);
+ if (result != noErr) {
+ ERR_PRINTS("MIDIInputPortCreate failed: " + String(GetMacOSStatusErrorString(result)));
+ return ERR_CANT_OPEN;
+ }
+
+ int sources = MIDIGetNumberOfSources();
+ for (int i = 0; i < sources; i++) {
+
+ MIDIEndpointRef source = MIDIGetSource(i);
+ if (source != NULL) {
+ MIDIPortConnectSource(port_in, source, (void *)this);
+ connected_sources.insert(i, source);
+ }
+ }
+
+ return OK;
+}
+
+void MIDIDriverCoreMidi::close() {
+
+ for (int i = 0; i < connected_sources.size(); i++) {
+ MIDIEndpointRef source = connected_sources[i];
+ MIDIPortDisconnectSource(port_in, source);
+ }
+ connected_sources.clear();
+
+ if (port_in != 0) {
+ MIDIPortDispose(port_in);
+ port_in = 0;
+ }
+
+ if (client != 0) {
+ MIDIClientDispose(client);
+ client = 0;
+ }
+}
+
+MIDIDriverCoreMidi::MIDIDriverCoreMidi() {
+
+ client = 0;
+}
+
+MIDIDriverCoreMidi::~MIDIDriverCoreMidi() {
+
+ close();
+}
+
+#endif
diff --git a/drivers/coremidi/core_midi.h b/drivers/coremidi/core_midi.h
new file mode 100644
index 0000000000..fd35e12f4b
--- /dev/null
+++ b/drivers/coremidi/core_midi.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* core_midi.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. */
+/*************************************************************************/
+
+#ifdef COREMIDI_ENABLED
+
+#ifndef CORE_MIDI_H
+#define CORE_MIDI_H
+
+#include <stdio.h>
+
+#include <CoreMIDI/CoreMIDI.h>
+
+#include "core/vector.h"
+#include "os/midi_driver.h"
+
+class MIDIDriverCoreMidi : public MIDIDriver {
+
+ MIDIClientRef client;
+ MIDIPortRef port_in;
+
+ Vector<MIDIEndpointRef> connected_sources;
+
+ static void read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con);
+
+public:
+ virtual Error open();
+ virtual void close();
+
+ MIDIDriverCoreMidi();
+ virtual ~MIDIDriverCoreMidi();
+};
+
+#endif
+#endif
diff --git a/drivers/dummy/texture_loader_dummy.cpp b/drivers/dummy/texture_loader_dummy.cpp
index 6d3e176bbb..b099019d17 100644
--- a/drivers/dummy/texture_loader_dummy.cpp
+++ b/drivers/dummy/texture_loader_dummy.cpp
@@ -45,10 +45,6 @@ RES ResourceFormatDummyTexture::load(const String &p_path, const String &p_origi
dstbuff.resize(rowsize * height);
- PoolVector<uint8_t>::Write dstbuff_write = dstbuff.write();
-
- uint8_t *data = dstbuff_write.ptr();
-
uint8_t **row_p = memnew_arr(uint8_t *, height);
for (unsigned int i = 0; i < height; i++) {
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 3622e48ecd..864b9714a9 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -403,7 +403,6 @@ AudioDriver::SpeakerMode AudioDriverPulseAudio::get_speaker_mode() const {
void AudioDriverPulseAudio::pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata) {
AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
- int ctr = 0;
// If eol is set to a positive number, you're at the end of the list
if (eol > 0) {
diff --git a/drivers/winmidi/SCsub b/drivers/winmidi/SCsub
new file mode 100644
index 0000000000..233593b0f9
--- /dev/null
+++ b/drivers/winmidi/SCsub
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+Import('env')
+
+# Driver source files
+env.add_source_files(env.drivers_sources, "*.cpp")
+
+Export('env')
diff --git a/drivers/winmidi/win_midi.cpp b/drivers/winmidi/win_midi.cpp
new file mode 100644
index 0000000000..6da6e31b2b
--- /dev/null
+++ b/drivers/winmidi/win_midi.cpp
@@ -0,0 +1,100 @@
+/*************************************************************************/
+/* win_midi.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. */
+/*************************************************************************/
+
+#ifdef WINMIDI_ENABLED
+
+#include "win_midi.h"
+#include "print_string.h"
+
+void MIDIDriverWinMidi::read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
+
+ if (wMsg == MIM_DATA) {
+ receive_input_packet((uint64_t)dwParam2, (uint8_t *)&dwParam1, 3);
+ }
+}
+
+Error MIDIDriverWinMidi::open() {
+
+ for (UINT i = 0; i < midiInGetNumDevs(); i++) {
+ HMIDIIN midi_in;
+
+ MMRESULT res = midiInOpen(&midi_in, i, (DWORD_PTR)read, (DWORD_PTR)this, CALLBACK_FUNCTION);
+ if (res == MMSYSERR_NOERROR) {
+ midiInStart(midi_in);
+ connected_sources.insert(i, midi_in);
+ } else {
+ char err[256];
+ midiInGetErrorText(res, err, 256);
+ ERR_PRINTS("midiInOpen error: " + String(err));
+ }
+ }
+
+ return OK;
+}
+
+PoolStringArray MIDIDriverWinMidi::get_connected_inputs() {
+
+ PoolStringArray list;
+
+ for (int i = 0; i < connected_sources.size(); i++) {
+ HMIDIIN midi_in = connected_sources[i];
+ UINT id = 0;
+ MMRESULT res = midiInGetID(midi_in, &id);
+ if (res == MMSYSERR_NOERROR) {
+ MIDIINCAPS caps;
+ res = midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS));
+ if (res == MMSYSERR_NOERROR) {
+ list.push_back(caps.szPname);
+ }
+ }
+ }
+
+ return list;
+}
+
+void MIDIDriverWinMidi::close() {
+
+ for (int i = 0; i < connected_sources.size(); i++) {
+ HMIDIIN midi_in = connected_sources[i];
+ midiInStop(midi_in);
+ midiInClose(midi_in);
+ }
+ connected_sources.clear();
+}
+
+MIDIDriverWinMidi::MIDIDriverWinMidi() {
+}
+
+MIDIDriverWinMidi::~MIDIDriverWinMidi() {
+
+ close();
+}
+
+#endif
diff --git a/drivers/winmidi/win_midi.h b/drivers/winmidi/win_midi.h
new file mode 100644
index 0000000000..1cf9b19b5d
--- /dev/null
+++ b/drivers/winmidi/win_midi.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* win_midi.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. */
+/*************************************************************************/
+
+#ifdef WINMIDI_ENABLED
+
+#ifndef WIN_MIDI_H
+#define WIN_MIDI_H
+
+#include <stdio.h>
+#include <windows.h>
+
+#include <mmsystem.h>
+
+#include "core/vector.h"
+#include "os/midi_driver.h"
+
+class MIDIDriverWinMidi : public MIDIDriver {
+
+ Vector<HMIDIIN> connected_sources;
+
+ static void CALLBACK read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
+
+public:
+ virtual Error open();
+ virtual void close();
+
+ virtual PoolStringArray get_connected_inputs();
+
+ MIDIDriverWinMidi();
+ virtual ~MIDIDriverWinMidi();
+};
+
+#endif
+#endif
diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp
index db108f9c6b..a1002ef4f9 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.cpp
+++ b/drivers/xaudio2/audio_driver_xaudio2.cpp
@@ -97,8 +97,6 @@ void AudioDriverXAudio2::thread_func(void *p_udata) {
AudioDriverXAudio2 *ad = (AudioDriverXAudio2 *)p_udata;
- uint64_t usdelay = (ad->buffer_size / float(ad->mix_rate)) * 1000000;
-
while (!ad->exit_thread) {
if (!ad->active) {
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 ff97878e71..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"
@@ -156,7 +157,6 @@ void EditorNode::_update_scene_tabs() {
scene_tabs->set_current_tab(editor_data.get_edited_scene());
- int current = editor_data.get_edited_scene();
if (scene_tabs->get_offset_buttons_visible()) {
// move add button to fixed position on the tabbar
if (scene_tab_add->get_parent() == scene_tabs) {
@@ -5469,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/editor_settings.cpp b/editor/editor_settings.cpp
index 466b12157d..c8e97b071f 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -298,17 +298,17 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
_initial_set("interface/editor/main_font_size", 14);
hints["interface/editor/main_font_size"] = PropertyInfo(Variant::INT, "interface/editor/main_font_size", PROPERTY_HINT_RANGE, "10,40,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
_initial_set("interface/editor/code_font_size", 14);
- hints["interface/editor/code_font_size"] = PropertyInfo(Variant::INT, "interface/editor/code_font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ hints["interface/editor/code_font_size"] = PropertyInfo(Variant::INT, "interface/editor/code_font_size", PROPERTY_HINT_RANGE, "8,96,1", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/editor/main_font_hinting", 2);
- hints["interface/editor/main_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/main_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ hints["interface/editor/main_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/main_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/editor/code_font_hinting", 2);
- hints["interface/editor/code_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/code_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ hints["interface/editor/code_font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/code_font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/editor/main_font", "");
- hints["interface/editor/main_font"] = PropertyInfo(Variant::STRING, "interface/editor/main_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ hints["interface/editor/main_font"] = PropertyInfo(Variant::STRING, "interface/editor/main_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/editor/main_font_bold", "");
- hints["interface/editor/main_font_bold"] = PropertyInfo(Variant::STRING, "interface/editor/main_font_bold", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ hints["interface/editor/main_font_bold"] = PropertyInfo(Variant::STRING, "interface/editor/main_font_bold", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/editor/code_font", "");
- hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED);
+ hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT);
_initial_set("interface/editor/dim_editor_on_dialog_popup", true);
_initial_set("interface/editor/dim_amount", 0.6f);
hints["interface/editor/dim_amount"] = PropertyInfo(Variant::REAL, "interface/editor/dim_amount", PROPERTY_HINT_RANGE, "0,1,0.01", PROPERTY_USAGE_DEFAULT);
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index ea9f6db61a..18cc52a5c6 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -237,8 +237,6 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme =
ImageLoaderSVG::set_convert_colors(NULL);
clock_t end_time = clock();
-
- double time_d = (double)(end_time - begin_time) / CLOCKS_PER_SEC;
#else
print_line("Sorry no icons for you");
#endif
@@ -257,7 +255,6 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
String preset = EDITOR_DEF("interface/theme/preset", "Default");
- int icon_font_color_setting = EDITOR_DEF("interface/theme/icon_and_font_color", 0);
bool highlight_tabs = EDITOR_DEF("interface/theme/highlight_tabs", false);
int border_size = EDITOR_DEF("interface/theme/border_size", 1);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index f65fb5365b..37f86cc912 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1319,6 +1319,9 @@ void FileSystemDock::_file_option(int p_option) {
String fpath = files->get_item_metadata(idx);
OS::get_singleton()->set_clipboard(fpath);
} break;
+ case FILE_NEW_RESOURCE: {
+ new_resource_dialog->popup_create(true);
+ } break;
}
}
@@ -1393,6 +1396,21 @@ void FileSystemDock::_folder_option(int p_option) {
}
}
+void FileSystemDock::_resource_created() const {
+ Object *c = new_resource_dialog->instance_selected();
+
+ ERR_FAIL_COND(!c);
+ Resource *r = Object::cast_to<Resource>(c);
+ ERR_FAIL_COND(!r);
+
+ REF res(r);
+ editor->push_item(c);
+
+ RES current_res = RES(r);
+
+ editor->save_resource_as(current_res);
+}
+
void FileSystemDock::_go_to_file_list() {
if (low_height_mode) {
@@ -1738,6 +1756,7 @@ void FileSystemDock::_files_list_rmb_select(int p_item, const Vector2 &p_pos) {
file_options->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
file_options->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
+ file_options->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER);
file_options->set_position(files->get_global_position() + p_pos);
@@ -1750,6 +1769,7 @@ void FileSystemDock::_rmb_pressed(const Vector2 &p_pos) {
file_options->add_item(TTR("New Folder..."), FILE_NEW_FOLDER);
file_options->add_item(TTR("New Script..."), FILE_NEW_SCRIPT);
+ file_options->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE);
file_options->add_item(TTR("Show In File Manager"), FILE_SHOW_IN_EXPLORER);
file_options->set_position(files->get_global_position() + p_pos);
file_options->popup();
@@ -1862,6 +1882,7 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_file_option"), &FileSystemDock::_file_option);
ClassDB::bind_method(D_METHOD("_folder_option"), &FileSystemDock::_folder_option);
ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm);
+ ClassDB::bind_method(D_METHOD("_resource_created"), &FileSystemDock::_resource_created);
ClassDB::bind_method(D_METHOD("_move_operation_confirm", "to_path", "overwrite"), &FileSystemDock::_move_operation_confirm, DEFVAL(false));
ClassDB::bind_method(D_METHOD("_move_with_overwrite"), &FileSystemDock::_move_with_overwrite);
ClassDB::bind_method(D_METHOD("_rename_operation_confirm"), &FileSystemDock::_rename_operation_confirm);
@@ -2087,6 +2108,11 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) {
make_script_dialog_text->set_title(TTR("Create Script"));
add_child(make_script_dialog_text);
+ new_resource_dialog = memnew(CreateDialog);
+ add_child(new_resource_dialog);
+ new_resource_dialog->set_base_type("Resource");
+ new_resource_dialog->connect("create", this, "_resource_created");
+
updating_tree = false;
initialized = false;
import_dock_needs_update = false;
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index e8ab803cca..6a0c73d52e 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -47,6 +47,8 @@
#include "os/dir_access.h"
#include "os/thread.h"
+#include "create_dialog.h"
+
#include "dependency_editor.h"
#include "editor_dir_dialog.h"
#include "editor_file_system.h"
@@ -78,7 +80,8 @@ private:
FILE_NEW_FOLDER,
FILE_NEW_SCRIPT,
FILE_SHOW_IN_EXPLORER,
- FILE_COPY_PATH
+ FILE_COPY_PATH,
+ FILE_NEW_RESOURCE
};
enum FolderMenu {
@@ -131,6 +134,7 @@ private:
LineEdit *make_dir_dialog_text;
ConfirmationDialog *overwrite_dialog;
ScriptCreateDialog *make_script_dialog_text;
+ CreateDialog *new_resource_dialog;
class FileOrFolder {
public:
@@ -191,6 +195,7 @@ private:
void _update_favorite_dirs_list_after_move(const Map<String, String> &p_renames) const;
void _update_project_settings_after_move(const Map<String, String> &p_renames) const;
+ void _resource_created() const;
void _make_dir_confirm();
void _rename_operation_confirm();
void _duplicate_operation_confirm();
diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp
index eb0bc0f782..f2f4328cd2 100644
--- a/editor/import/editor_scene_importer_gltf.cpp
+++ b/editor/import/editor_scene_importer_gltf.cpp
@@ -1711,14 +1711,14 @@ void EditorSceneImporterGLTF::_generate_node(GLTFState &state, int p_node, Node
#endif
for (int i = 0; i < n->children.size(); i++) {
if (state.nodes[n->children[i]]->joints.size()) {
- _generate_bone(state, n->children[i], skeletons, Vector<int>(), node);
+ _generate_bone(state, n->children[i], skeletons, node);
} else {
_generate_node(state, n->children[i], node, p_owner, skeletons);
}
}
}
-void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, const Vector<int> &p_parent_bones, Node *p_parent_node) {
+void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, Node *p_parent_node) {
ERR_FAIL_INDEX(p_node, state.nodes.size());
if (state.skeleton_nodes.has(p_node)) {
@@ -1733,30 +1733,28 @@ void EditorSceneImporterGLTF::_generate_bone(GLTFState &state, int p_node, Vecto
}
GLTFNode *n = state.nodes[p_node];
- Vector<int> parent_bones;
for (int i = 0; i < n->joints.size(); i++) {
- ERR_FAIL_COND(n->joints[i].skin < 0);
+ const int skin = n->joints[i].skin;
+ ERR_FAIL_COND(skin < 0);
- int bone_index = n->joints[i].bone;
+ Skeleton *s = skeletons[skin];
+ const GLTFNode *gltf_bone_node = state.nodes[state.skins[skin].bones[n->joints[i].bone].node];
+ const String bone_name = gltf_bone_node->name;
+ const int parent = gltf_bone_node->parent;
+ const int parent_index = s->find_bone(state.nodes[parent]->name);
- Skeleton *s = skeletons[n->joints[i].skin];
- while (s->get_bone_count() <= bone_index) {
- s->add_bone("Bone " + itos(s->get_bone_count()));
- }
-
- if (p_parent_bones.size()) {
- s->set_bone_parent(bone_index, p_parent_bones[i]);
- }
- s->set_bone_rest(bone_index, state.skins[n->joints[i].skin].bones[n->joints[i].bone].inverse_bind.affine_inverse());
+ s->add_bone(bone_name);
+ const int bone_index = s->find_bone(bone_name);
+ s->set_bone_parent(bone_index, parent_index);
+ s->set_bone_rest(bone_index, state.skins[skin].bones[n->joints[i].bone].inverse_bind.affine_inverse());
n->godot_nodes.push_back(s);
n->joints[i].godot_bone_index = bone_index;
- parent_bones.push_back(bone_index);
}
for (int i = 0; i < n->children.size(); i++) {
- _generate_bone(state, n->children[i], skeletons, parent_bones, p_parent_node);
+ _generate_bone(state, n->children[i], skeletons, p_parent_node);
}
}
@@ -2070,7 +2068,7 @@ Spatial *EditorSceneImporterGLTF::_generate_scene(GLTFState &state, int p_bake_f
}
for (int i = 0; i < state.root_nodes.size(); i++) {
if (state.nodes[state.root_nodes[i]]->joints.size()) {
- _generate_bone(state, state.root_nodes[i], skeletons, Vector<int>(), root);
+ _generate_bone(state, state.root_nodes[i], skeletons, root);
} else {
_generate_node(state, state.root_nodes[i], root, root, skeletons);
}
diff --git a/editor/import/editor_scene_importer_gltf.h b/editor/import/editor_scene_importer_gltf.h
index 088036ce75..e8f3bdff62 100644
--- a/editor/import/editor_scene_importer_gltf.h
+++ b/editor/import/editor_scene_importer_gltf.h
@@ -311,7 +311,7 @@ class EditorSceneImporterGLTF : public EditorSceneImporter {
Vector<Basis> _decode_accessor_as_basis(GLTFState &state, int p_accessor, bool p_for_vertex);
Vector<Transform> _decode_accessor_as_xform(GLTFState &state, int p_accessor, bool p_for_vertex);
- void _generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, const Vector<int> &p_parent_bones, Node *p_parent_node);
+ void _generate_bone(GLTFState &state, int p_node, Vector<Skeleton *> &skeletons, Node *p_parent_node);
void _generate_node(GLTFState &state, int p_node, Node *p_parent, Node *p_owner, Vector<Skeleton *> &skeletons);
void _import_animation(GLTFState &state, AnimationPlayer *ap, int index, int bake_fps, Vector<Skeleton *> skeletons);
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 876da7f61a..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);
@@ -2239,8 +2420,6 @@ void ScriptEditor::_make_script_list_context_menu() {
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/close_file"), FILE_CLOSE);
}
- EditorHelp *eh = Object::cast_to<EditorHelp>(tab_container->get_child(selected));
-
context_menu->add_separator();
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_up"), WINDOW_MOVE_UP);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_editor/window_move_down"), WINDOW_MOVE_DOWN);
@@ -2268,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;
}
}
@@ -2311,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;
@@ -2436,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)) {
@@ -2473,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;
@@ -2519,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;
}
}
@@ -2552,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();
@@ -2968,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/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp
index 37b8562e96..f0c874a150 100644
--- a/editor/plugins/spatial_editor_plugin.cpp
+++ b/editor/plugins/spatial_editor_plugin.cpp
@@ -4641,9 +4641,7 @@ void SpatialEditor::_init_grid() {
Vector3 p2_dest = p2 * (-axis_n1 + axis_n2);
Color line_color = secondary_grid_color;
- if (j == 0) {
- continue;
- } else if (j % primary_grid_steps == 0) {
+ if (j % primary_grid_steps == 0) {
line_color = primary_grid_color;
}
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/property_editor.cpp b/editor/property_editor.cpp
index 7f46844f6c..576227344b 100644
--- a/editor/property_editor.cpp
+++ b/editor/property_editor.cpp
@@ -4394,7 +4394,7 @@ PropertyEditor::PropertyEditor() {
use_filter = false;
subsection_selectable = false;
property_selectable = false;
- show_type_icons = EDITOR_DEF("interface/editor/show_type_icons", false);
+ show_type_icons = false; // TODO: need to reimplement it to work with the new inspector
}
PropertyEditor::~PropertyEditor() {
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/gdnative/nativescript/api_generator.cpp b/modules/gdnative/nativescript/api_generator.cpp
index 4012e821bb..70ca8d68b8 100644
--- a/modules/gdnative/nativescript/api_generator.cpp
+++ b/modules/gdnative/nativescript/api_generator.cpp
@@ -110,7 +110,6 @@ struct ClassAPI {
bool is_singleton;
bool is_instanciable;
// @Unclear
- bool is_creatable;
bool is_reference;
List<MethodAPI> methods;
@@ -385,7 +384,6 @@ static List<String> generate_c_api_json(const List<ClassAPI> &p_api) {
source.push_back(String("\t\t\"instanciable\": ") + (api.is_instanciable ? "true" : "false") + ",\n");
source.push_back(String("\t\t\"is_reference\": ") + (api.is_reference ? "true" : "false") + ",\n");
// @Unclear
- // source.push_back(String("\t\t\"createable\": ") + (api.is_creatable ? "true" : "false") + ",\n");
source.push_back("\t\t\"constants\": {\n");
for (List<ConstantAPI>::Element *e = api.constants.front(); e; e = e->next()) {
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/modules/websocket/emws_client.cpp b/modules/websocket/emws_client.cpp
index 1405fa98b0..00c36ebb47 100644
--- a/modules/websocket/emws_client.cpp
+++ b/modules/websocket/emws_client.cpp
@@ -64,7 +64,6 @@ Error EMWSClient::connect_to_host(String p_host, String p_path, uint16_t p_port,
String str = "ws://";
String proto_string = "";
- int i = 0;
if (p_ssl)
str = "wss://";
diff --git a/platform/android/audio_driver_opensl.cpp b/platform/android/audio_driver_opensl.cpp
index fd834193dd..28e3ea962f 100644
--- a/platform/android/audio_driver_opensl.cpp
+++ b/platform/android/audio_driver_opensl.cpp
@@ -146,9 +146,6 @@ void AudioDriverOpenSL::start() {
res = (*sl)->GetInterface(sl, SL_IID_ENGINE, (void *)&EngineItf);
ERR_FAIL_COND(res != SL_RESULT_SUCCESS);
- /* Initialize arrays required[] and iidArray[] */
- SLboolean required[MAX_NUMBER_INTERFACES];
- SLInterfaceID iidArray[MAX_NUMBER_INTERFACES];
{
const SLInterfaceID ids[1] = { SL_IID_ENVIRONMENTALREVERB };
@@ -188,10 +185,7 @@ void AudioDriverOpenSL::start() {
//cntxt.pDataBase = (void*)&pcmData;
//cntxt.pData = cntxt.pDataBase;
//cntxt.size = sizeof(pcmData);
- /* Set arrays required[] and iidArray[] for SEEK interface
- (PlayItf is implicit) */
- required[0] = SL_BOOLEAN_TRUE;
- iidArray[0] = SL_IID_BUFFERQUEUE;
+
/* Create the music player */
{
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index 3e40b59de9..ee5ae156b7 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -153,7 +153,6 @@ String DirAccessJAndroid::get_current_dir() {
bool DirAccessJAndroid::file_exists(String p_file) {
- JNIEnv *env = ThreadAndroid::get_env();
String sd;
if (current_dir == "")
sd = p_file;
diff --git a/platform/android/export/export.cpp b/platform/android/export/export.cpp
index c562a47b00..59e35884d1 100644
--- a/platform/android/export/export.cpp
+++ b/platform/android/export/export.cpp
@@ -528,11 +528,9 @@ class EditorExportAndroid : public EditorExportPlatform {
bool exported = false;
for (int i = 0; i < p_so.tags.size(); ++i) {
// shared objects can be fat (compatible with multiple ABIs)
- int start_pos = 0;
int abi_index = abis.find(p_so.tags[i]);
if (abi_index != -1) {
exported = true;
- start_pos = abi_index + 1;
String abi = abis[abi_index];
String dst_path = "lib/" + abi + "/" + p_so.path.get_file();
Vector<uint8_t> array = FileAccess::get_file_as_array(p_so.path);
diff --git a/platform/android/java_glue.cpp b/platform/android/java_glue.cpp
index e6240ad9e9..8bb1c38345 100644
--- a/platform/android/java_glue.cpp
+++ b/platform/android/java_glue.cpp
@@ -880,7 +880,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
const char **cmdline = NULL;
int cmdlen = 0;
- bool use_apk_expansion = false;
if (p_cmdline) {
cmdlen = env->GetArrayLength(p_cmdline);
if (cmdlen) {
@@ -891,9 +890,6 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setup(JNIEnv *env, jo
jstring string = (jstring)env->GetObjectArrayElement(p_cmdline, i);
const char *rawString = env->GetStringUTFChars(string, 0);
- if (rawString && strcmp(rawString, "--main-pack") == 0) {
- use_apk_expansion = true;
- }
cmdline[i] = rawString;
}
diff --git a/platform/android/thread_jandroid.cpp b/platform/android/thread_jandroid.cpp
index e85813605f..b13baf69c2 100644
--- a/platform/android/thread_jandroid.cpp
+++ b/platform/android/thread_jandroid.cpp
@@ -132,7 +132,7 @@ JNIEnv *ThreadAndroid::get_env() {
}
JNIEnv *env = NULL;
- int status = java_vm->AttachCurrentThread(&env, NULL);
+ java_vm->AttachCurrentThread(&env, NULL);
return env;
}
diff --git a/platform/iphone/export/export.cpp b/platform/iphone/export/export.cpp
index 4c1e02baf7..5480d30e7a 100644
--- a/platform/iphone/export/export.cpp
+++ b/platform/iphone/export/export.cpp
@@ -781,7 +781,9 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
int ret = unzGoToFirstFile(src_pkg_zip);
Vector<uint8_t> project_file_data;
while (ret == UNZ_OK) {
+#if defined(OSX_ENABLED) || defined(X11_ENABLED)
bool is_execute = false;
+#endif
//get filename
unz_file_info info;
@@ -812,7 +814,9 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
continue; //ignore!
}
found_library = true;
+#if defined(OSX_ENABLED) || defined(X11_ENABLED)
is_execute = true;
+#endif
file = "godot_ios.a";
}
if (file == project_file) {
@@ -855,7 +859,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
f->close();
memdelete(f);
-#ifdef OSX_ENABLED
+#if defined(OSX_ENABLED) || defined(X11_ENABLED)
if (is_execute) {
// we need execute rights on this file
chmod(file.utf8().get_data(), 0755);
diff --git a/platform/osx/detect.py b/platform/osx/detect.py
index 1cc5c619fe..af96659239 100644
--- a/platform/osx/detect.py
+++ b/platform/osx/detect.py
@@ -115,8 +115,8 @@ def configure(env):
## Flags
env.Append(CPPPATH=['#platform/osx'])
- env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED'])
- env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback'])
+ env.Append(CPPFLAGS=['-DOSX_ENABLED', '-DUNIX_ENABLED', '-DGLES_ENABLED', '-DAPPLE_STYLE_KEYS', '-DCOREAUDIO_ENABLED', '-DCOREMIDI_ENABLED'])
+ env.Append(LINKFLAGS=['-framework', 'Cocoa', '-framework', 'Carbon', '-framework', 'OpenGL', '-framework', 'AGL', '-framework', 'AudioUnit', '-framework', 'CoreAudio', '-framework', 'CoreMidi', '-lz', '-framework', 'IOKit', '-framework', 'ForceFeedback'])
env.Append(LIBS=['pthread'])
env.Append(CPPFLAGS=['-mmacosx-version-min=10.9'])
diff --git a/platform/osx/os_osx.h b/platform/osx/os_osx.h
index 3d14a6d4fb..686e3f8c90 100644
--- a/platform/osx/os_osx.h
+++ b/platform/osx/os_osx.h
@@ -33,6 +33,7 @@
#include "crash_handler_osx.h"
#include "drivers/coreaudio/audio_driver_coreaudio.h"
+#include "drivers/coremidi/core_midi.h"
#include "drivers/unix/os_unix.h"
#include "joypad_osx.h"
#include "main/input_default.h"
@@ -74,6 +75,7 @@ public:
IP_Unix *ip_unix;
AudioDriverCoreAudio audio_driver;
+ MIDIDriverCoreMidi midi_driver;
InputDefault *input;
JoypadOSX *joypad_osx;
diff --git a/platform/osx/os_osx.mm b/platform/osx/os_osx.mm
index 282f5e2d1b..e77f8b3173 100644
--- a/platform/osx/os_osx.mm
+++ b/platform/osx/os_osx.mm
@@ -1351,6 +1351,8 @@ Error OS_OSX::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
AudioDriverManager::initialize(p_audio_driver);
+ midi_driver.open();
+
input = memnew(InputDefault);
joypad_osx = memnew(JoypadOSX);
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/platform/windows/detect.py b/platform/windows/detect.py
index cacb573236..34fc3e09b5 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -206,7 +206,8 @@ def configure_msvc(env, manual_msvc_config):
env.AppendUnique(CPPDEFINES = ['WINDOWS_ENABLED', 'OPENGL_ENABLED',
'RTAUDIO_ENABLED', 'WASAPI_ENABLED',
- 'TYPED_METHOD_BIND', 'WIN32', 'MSVC',
+ 'WINMIDI_ENABLED', 'TYPED_METHOD_BIND',
+ 'WIN32', 'MSVC',
{'WINVER' : '$target_win_version',
'_WIN32_WINNT': '$target_win_version'}])
if env["bits"] == "64":
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index ac37e1246d..e083fd7323 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -1219,6 +1219,10 @@ Error OS_Windows::initialize(const VideoMode &p_desired, int p_video_driver, int
AudioDriverManager::initialize(p_audio_driver);
+#ifdef WINMIDI_ENABLED
+ driver_midi.open();
+#endif
+
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE;
@@ -1347,6 +1351,10 @@ void OS_Windows::set_main_loop(MainLoop *p_main_loop) {
void OS_Windows::finalize() {
+#ifdef WINMIDI_ENABLED
+ driver_midi.close();
+#endif
+
if (main_loop)
memdelete(main_loop);
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index b99d3e3422..69c7d851b8 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -35,6 +35,7 @@
#include "crash_handler_win.h"
#include "drivers/rtaudio/audio_driver_rtaudio.h"
#include "drivers/wasapi/audio_driver_wasapi.h"
+#include "drivers/winmidi/win_midi.h"
#include "os/input.h"
#include "os/os.h"
#include "power_windows.h"
@@ -144,6 +145,9 @@ class OS_Windows : public OS {
#ifdef XAUDIO2_ENABLED
AudioDriverXAudio2 driver_xaudio2;
#endif
+#ifdef WINMIDI_ENABLED
+ MIDIDriverWinMidi driver_midi;
+#endif
CrashHandler crash_handler;
diff --git a/platform/x11/detect.py b/platform/x11/detect.py
index feaa2e598f..6a7a426804 100644
--- a/platform/x11/detect.py
+++ b/platform/x11/detect.py
@@ -249,7 +249,7 @@ def configure(env):
if (os.system("pkg-config --exists alsa") == 0): # 0 means found
print("Enabling ALSA")
- env.Append(CPPFLAGS=["-DALSA_ENABLED"])
+ env.Append(CPPFLAGS=["-DALSA_ENABLED", "-DALSAMIDI_ENABLED"])
env.ParseConfig('pkg-config alsa --cflags --libs')
else:
print("ALSA libraries not found, disabling driver")
diff --git a/platform/x11/os_x11.cpp b/platform/x11/os_x11.cpp
index af0e02173f..260ce57732 100644
--- a/platform/x11/os_x11.cpp
+++ b/platform/x11/os_x11.cpp
@@ -342,6 +342,10 @@ Error OS_X11::initialize(const VideoMode &p_desired, int p_video_driver, int p_a
AudioDriverManager::initialize(p_audio_driver);
+#ifdef ALSAMIDI_ENABLED
+ driver_alsamidi.open();
+#endif
+
ERR_FAIL_COND_V(!visual_server, ERR_UNAVAILABLE);
ERR_FAIL_COND_V(x11_window == 0, ERR_UNAVAILABLE);
@@ -606,6 +610,9 @@ void OS_X11::finalize() {
memdelete(debugger_connection_console);
}
*/
+#ifdef ALSAMIDI_ENABLED
+ driver_alsamidi.close();
+#endif
#ifdef JOYDEV_ENABLED
memdelete(joypad);
diff --git a/platform/x11/os_x11.h b/platform/x11/os_x11.h
index b67bc824be..44455a2d8d 100644
--- a/platform/x11/os_x11.h
+++ b/platform/x11/os_x11.h
@@ -38,6 +38,7 @@
#include "servers/visual_server.h"
//#include "servers/visual/visual_server_wrap_mt.h"
#include "drivers/alsa/audio_driver_alsa.h"
+#include "drivers/alsamidi/alsa_midi.h"
#include "drivers/pulseaudio/audio_driver_pulseaudio.h"
#include "joypad_linux.h"
#include "main/input_default.h"
@@ -168,6 +169,10 @@ class OS_X11 : public OS_Unix {
AudioDriverALSA driver_alsa;
#endif
+#ifdef ALSAMIDI_ENABLED
+ MIDIDriverALSAMidi driver_alsamidi;
+#endif
+
#ifdef PULSEAUDIO_ENABLED
AudioDriverPulseAudio driver_pulseaudio;
#endif
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/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 74ad3e79d0..a3f1b25e05 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -292,7 +292,6 @@ void LineBuilder::build() {
color1 = gradient->get_color_at_offset(current_distance1 / total_distance);
}
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
- uvx0 = current_distance0 / (width * tile_aspect);
uvx1 = current_distance1 / (width * tile_aspect);
} else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
uvx0 = current_distance0 / total_distance;
@@ -306,7 +305,6 @@ void LineBuilder::build() {
u0 = u1;
f0 = f1;
pos0 = pos1;
- current_distance0 = current_distance1;
if (intersection_result == SEGMENT_INTERSECT) {
if (current_joint_mode == Line2D::LINE_JOINT_SHARP) {
pos_up0 = pos_up1;
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/control.cpp b/scene/gui/control.cpp
index 17c349858f..12aeed1520 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2972,7 +2972,6 @@ Control::Control() {
data.SI = NULL;
data.MI = NULL;
data.RI = NULL;
- data.modal = false;
data.theme_owner = NULL;
data.modal_exclusive = false;
data.default_cursor = CURSOR_ARROW;
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 94231867d7..6bea04345b 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -182,7 +182,6 @@ private:
Control *parent;
ObjectID drag_owner;
- bool modal;
bool modal_exclusive;
uint64_t modal_frame; //frame used to put something as modal
Ref<Theme> theme;
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/menu_button.h b/scene/gui/menu_button.h
index 2356444ecb..0636accfee 100644
--- a/scene/gui/menu_button.h
+++ b/scene/gui/menu_button.h
@@ -43,7 +43,6 @@ class MenuButton : public Button {
bool clicked;
bool disable_shortcuts;
PopupMenu *popup;
- virtual void pressed();
void _unhandled_key_input(Ref<InputEvent> p_event);
Array _get_items() const;
@@ -55,6 +54,8 @@ protected:
static void _bind_methods();
public:
+ virtual void pressed();
+
PopupMenu *get_popup() const;
void set_disable_shortcuts(bool p_disabled);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 90cb475a7b..cccd1bd197 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -337,10 +337,6 @@ void TextEdit::_update_scrollbars() {
int hscroll_rows = ((hmin.height - 1) / get_row_height()) + 1;
int visible_rows = get_visible_rows();
- int first_vis_line = get_first_visible_line();
- int wi;
- int num_rows = MAX(visible_rows, num_lines_from_rows(first_vis_line, cursor.wrap_ofs, visible_rows, wi));
-
int total_rows = get_total_visible_rows();
if (scroll_past_end_of_file_enabled) {
total_rows += visible_rows - 1;
@@ -1673,7 +1669,6 @@ void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) co
rows /= get_row_height();
rows += get_v_scroll_offset();
int first_vis_line = get_first_visible_line();
- int last_vis_line = get_last_visible_line();
int row = first_vis_line + Math::floor(rows);
int wrap_index = 0;
@@ -3800,7 +3795,6 @@ Vector<String> TextEdit::get_wrap_rows_text(int p_line) const {
}
// line ends before hit wrap_at; add this word to the substring
wrap_substring += word_str;
- px += word_px;
lines.push_back(wrap_substring);
return lines;
}
@@ -5519,9 +5513,8 @@ int TextEdit::get_last_visible_line() const {
int TextEdit::get_last_visible_line_wrap_index() const {
int first_vis_line = get_first_visible_line();
- int last_vis_line = 0;
int wi;
- last_vis_line = first_vis_line + num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi) - 1;
+ num_lines_from_rows(first_vis_line, cursor.wrap_ofs, get_visible_rows() + 1, wi);
return wi;
}
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/gui/tree.cpp b/scene/gui/tree.cpp
index 1d27612766..6ab1bf3d58 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -2426,14 +2426,23 @@ void Tree::_gui_input(Ref<InputEvent> p_event) {
int col, h, section;
TreeItem *it = _find_item_at_pos(root, mpos, col, h, section);
- if ((drop_mode_flags && it != drop_mode_over) || section != drop_mode_section) {
- drop_mode_over = it;
- drop_mode_section = section;
- update();
+ if (drop_mode_flags) {
+ if (it != drop_mode_over) {
+ drop_mode_over = it;
+ update();
+ }
+ if (it && section != drop_mode_section) {
+ drop_mode_section = section;
+ update();
+ }
}
- if (it != cache.hover_item || col != cache.hover_cell) {
+ if (it != cache.hover_item) {
cache.hover_item = it;
+ update();
+ }
+
+ if (it && col != cache.hover_cell) {
cache.hover_cell = col;
update();
}
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 9013d276c7..573c401290 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -41,7 +41,10 @@
#include "scene/3d/spatial.h"
#include "scene/gui/control.h"
#include "scene/gui/label.h"
+#include "scene/gui/menu_button.h"
+#include "scene/gui/panel.h"
#include "scene/gui/panel_container.h"
+#include "scene/gui/popup_menu.h"
#include "scene/main/timer.h"
#include "scene/resources/mesh.h"
#include "scene/scene_string_names.h"
@@ -1853,8 +1856,32 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (gui.drag_data.get_type() == Variant::NIL && over && !gui.modal_stack.empty()) {
Control *top = gui.modal_stack.back()->get();
+
if (over != top && !top->is_a_parent_of(over)) {
- over = NULL; //nothing can be found outside the modal stack
+
+ PopupMenu *popup_menu = Object::cast_to<PopupMenu>(top);
+ MenuButton *popup_menu_parent;
+ MenuButton *menu_button = Object::cast_to<MenuButton>(over);
+
+ if (popup_menu)
+ popup_menu_parent = Object::cast_to<MenuButton>(popup_menu->get_parent());
+
+ // If the mouse is over a menu button, this menu will open automatically
+ // if there is already a pop-up menu open at the same hierarchical level.
+ if (popup_menu_parent && menu_button &&
+ popup_menu_parent->get_icon().is_null() &&
+ menu_button->get_icon().is_null() &&
+ (popup_menu->get_parent()->get_parent()->is_a_parent_of(menu_button) ||
+ menu_button->get_parent()->is_a_parent_of(popup_menu))) {
+
+ popup_menu->notification(Control::NOTIFICATION_MODAL_CLOSE);
+ popup_menu->_modal_stack_remove();
+ popup_menu->hide();
+
+ menu_button->pressed();
+ } else {
+ over = NULL; //nothing can be found outside the modal stack
+ }
}
}
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/dynamic_font.cpp b/scene/resources/dynamic_font.cpp
index e5d463d391..eb7d517841 100644
--- a/scene/resources/dynamic_font.cpp
+++ b/scene/resources/dynamic_font.cpp
@@ -211,9 +211,9 @@ Error DynamicFontAtSize::_load() {
scale_color_font = float(id.size) / face->available_sizes[i].width;
}
}
- error = FT_Select_Size(face, best_match);
+ FT_Select_Size(face, best_match);
} else {
- error = FT_Set_Pixel_Sizes(face, 0, id.size * oversampling);
+ FT_Set_Pixel_Sizes(face, 0, id.size * oversampling);
}
ascent = (face->size->metrics.ascender / 64.0) / oversampling * scale_color_font;
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
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 58057cda0c..f9df6b4304 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -923,6 +923,8 @@ void TileSet::_bind_methods() {
ClassDB::bind_method(D_METHOD("tile_get_normal_map", "id"), &TileSet::tile_get_normal_map);
ClassDB::bind_method(D_METHOD("tile_set_material", "id", "material"), &TileSet::tile_set_material);
ClassDB::bind_method(D_METHOD("tile_get_material", "id"), &TileSet::tile_get_material);
+ ClassDB::bind_method(D_METHOD("tile_set_modulate", "id", "color"), &TileSet::tile_set_modulate);
+ ClassDB::bind_method(D_METHOD("tile_get_modulate", "id"), &TileSet::tile_get_modulate);
ClassDB::bind_method(D_METHOD("tile_set_texture_offset", "id", "texture_offset"), &TileSet::tile_set_texture_offset);
ClassDB::bind_method(D_METHOD("tile_get_texture_offset", "id"), &TileSet::tile_get_texture_offset);
ClassDB::bind_method(D_METHOD("tile_set_region", "id", "region"), &TileSet::tile_set_region);
diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp
index 9faa4056c3..3414351681 100644
--- a/servers/audio/audio_rb_resampler.cpp
+++ b/servers/audio/audio_rb_resampler.cpp
@@ -100,6 +100,8 @@ uint32_t AudioRBResampler::_resample(AudioFrame *p_dest, int p_todo, int32_t p_i
if (C == 6) {
+ // FIXME: Lot of unused assignments here, but it seems like intermediate calculations
+ // should be done as for C == 2 (C == 4 also has some unused assignments).
float v0 = rb[(pos * 6) + 0];
float v1 = rb[(pos * 6) + 1];
float v2 = rb[(pos * 6) + 2];
diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp
index e587485fcb..44b7c9ac34 100644
--- a/servers/physics/collision_solver_sat.cpp
+++ b/servers/physics/collision_solver_sat.cpp
@@ -217,8 +217,6 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_
// generate contacts
//Plane plane_A(p_points_A[0],p_points_A[1],p_points_A[2]);
- int added = 0;
-
for (int i = 0; i < clipbuf_len; i++) {
real_t d = plane_B.distance_to(clipbuf_src[i]);
@@ -233,7 +231,6 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_
continue;
p_callback->call(clipbuf_src[i], closest_B);
- added++;
}
}
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index 8e21341cee..1f3319dc04 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -187,16 +187,14 @@ RID VisualServer::_make_test_cube() {
PoolVector<float> tangents;
PoolVector<Vector3> uvs;
- int vtx_idx = 0;
-#define ADD_VTX(m_idx) \
- vertices.push_back(face_points[m_idx]); \
- normals.push_back(normal_points[m_idx]); \
- tangents.push_back(normal_points[m_idx][1]); \
- tangents.push_back(normal_points[m_idx][2]); \
- tangents.push_back(normal_points[m_idx][0]); \
- tangents.push_back(1.0); \
- uvs.push_back(Vector3(uv_points[m_idx * 2 + 0], uv_points[m_idx * 2 + 1], 0)); \
- vtx_idx++;
+#define ADD_VTX(m_idx) \
+ vertices.push_back(face_points[m_idx]); \
+ normals.push_back(normal_points[m_idx]); \
+ tangents.push_back(normal_points[m_idx][1]); \
+ tangents.push_back(normal_points[m_idx][2]); \
+ tangents.push_back(normal_points[m_idx][0]); \
+ tangents.push_back(1.0); \
+ uvs.push_back(Vector3(uv_points[m_idx * 2 + 0], uv_points[m_idx * 2 + 1], 0));
for (int i = 0; i < 6; i++) {