mirror of
https://github.com/godotengine/godot.git
synced 2025-12-08 06:09:55 +00:00
Merge pull request #99680 from YeldhamDev/multi_remote_selection
Allow to select multiple remote nodes at runtime
This commit is contained in:
commit
20651f1162
22 changed files with 1441 additions and 527 deletions
|
|
@ -28,7 +28,7 @@
|
||||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
|
||||||
#include "math_fieldwise.h"
|
#include "math_fieldwise.h"
|
||||||
|
|
||||||
|
|
@ -242,4 +242,4 @@ Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const
|
||||||
/* clang-format on */
|
/* clang-format on */
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // TOOLS_ENABLED
|
#endif // DEBUG_ENABLED
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#ifdef TOOLS_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
|
|
||||||
#include "core/variant/variant.h"
|
#include "core/variant/variant.h"
|
||||||
|
|
||||||
Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const String &p_field);
|
Variant fieldwise_assign(const Variant &p_target, const Variant &p_source, const String &p_field);
|
||||||
|
|
||||||
#endif // TOOLS_ENABLED
|
#endif // DEBUG_ENABLED
|
||||||
|
|
|
||||||
|
|
@ -191,6 +191,10 @@
|
||||||
<member name="debugger/auto_switch_to_stack_trace" type="bool" setter="" getter="">
|
<member name="debugger/auto_switch_to_stack_trace" type="bool" setter="" getter="">
|
||||||
If [code]true[/code], automatically switches to the [b]Stack Trace[/b] panel when the debugger hits a breakpoint or steps.
|
If [code]true[/code], automatically switches to the [b]Stack Trace[/b] panel when the debugger hits a breakpoint or steps.
|
||||||
</member>
|
</member>
|
||||||
|
<member name="debugger/max_node_selection" type="int" setter="" getter="">
|
||||||
|
The limit of how many remote nodes can be selected at once.
|
||||||
|
[b]Warning:[/b] Increasing this value is not recommended, as selecting too many can make the editing and inspection of remote properties unreliable.
|
||||||
|
</member>
|
||||||
<member name="debugger/profile_native_calls" type="bool" setter="" getter="">
|
<member name="debugger/profile_native_calls" type="bool" setter="" getter="">
|
||||||
If [code]true[/code], enables collection of profiling data from non-GDScript Godot functions, such as engine class methods. Enabling this slows execution while profiling further.
|
If [code]true[/code], enables collection of profiling data from non-GDScript Godot functions, such as engine class methods. Enabling this slows execution while profiling further.
|
||||||
</member>
|
</member>
|
||||||
|
|
|
||||||
|
|
@ -843,7 +843,9 @@ bool DebugAdapterProtocol::request_remote_object(const ObjectID &p_object_id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_object(p_object_id);
|
TypedArray<uint64_t> arr;
|
||||||
|
arr.append(p_object_id);
|
||||||
|
EditorDebuggerNode::get_singleton()->get_default_debugger()->request_remote_objects(arr);
|
||||||
object_pending_set.insert(p_object_id);
|
object_pending_set.insert(p_object_id);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
||||||
|
|
@ -33,29 +33,57 @@
|
||||||
#include "core/debugger/debugger_marshalls.h"
|
#include "core/debugger/debugger_marshalls.h"
|
||||||
#include "core/io/marshalls.h"
|
#include "core/io/marshalls.h"
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
|
#include "editor/editor_undo_redo_manager.h"
|
||||||
|
#include "editor/inspector_dock.h"
|
||||||
#include "scene/debugger/scene_debugger.h"
|
#include "scene/debugger/scene_debugger.h"
|
||||||
|
|
||||||
bool EditorDebuggerRemoteObject::_set(const StringName &p_name, const Variant &p_value) {
|
bool EditorDebuggerRemoteObjects::_set(const StringName &p_name, const Variant &p_value) {
|
||||||
if (!prop_values.has(p_name) || String(p_name).begins_with("Constants/")) {
|
return _set_impl(p_name, p_value, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorDebuggerRemoteObjects::_set_impl(const StringName &p_name, const Variant &p_value, const String &p_field) {
|
||||||
|
String name = p_name;
|
||||||
|
|
||||||
|
if (name.begins_with("Metadata/")) {
|
||||||
|
name = name.replace_first("Metadata/", "metadata/");
|
||||||
|
}
|
||||||
|
if (!prop_values.has(name) || String(name).begins_with("Constants/")) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
prop_values[p_name] = p_value;
|
Dictionary &values = prop_values[p_name];
|
||||||
emit_signal(SNAME("value_edited"), remote_object_id, p_name, p_value);
|
Dictionary old_values = values.duplicate();
|
||||||
|
for (const uint64_t key : values.keys()) {
|
||||||
|
values.set(key, p_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
|
||||||
|
const int size = remote_object_ids.size();
|
||||||
|
ur->create_action(size == 1 ? vformat(TTR("Set %s"), name) : vformat(TTR("Set %s on %d objects"), name, size), UndoRedo::MERGE_ENDS);
|
||||||
|
|
||||||
|
ur->add_do_method(this, SNAME("emit_signal"), SNAME("values_edited"), name, values, p_field);
|
||||||
|
ur->add_undo_method(this, SNAME("emit_signal"), SNAME("values_edited"), name, old_values, p_field);
|
||||||
|
ur->commit_action();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EditorDebuggerRemoteObject::_get(const StringName &p_name, Variant &r_ret) const {
|
bool EditorDebuggerRemoteObjects::_get(const StringName &p_name, Variant &r_ret) const {
|
||||||
if (!prop_values.has(p_name)) {
|
String name = p_name;
|
||||||
|
|
||||||
|
if (name.begins_with("Metadata/")) {
|
||||||
|
name = name.replace_first("Metadata/", "metadata/");
|
||||||
|
}
|
||||||
|
if (!prop_values.has(name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
r_ret = prop_values[p_name];
|
r_ret = prop_values[p_name][remote_object_ids[0]];
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerRemoteObject::_get_property_list(List<PropertyInfo> *p_list) const {
|
void EditorDebuggerRemoteObjects::_get_property_list(List<PropertyInfo> *p_list) const {
|
||||||
p_list->clear(); // Sorry, no want category.
|
p_list->clear(); // Sorry, don't want any categories.
|
||||||
for (const PropertyInfo &prop : prop_list) {
|
for (const PropertyInfo &prop : prop_list) {
|
||||||
if (prop.name == "script") {
|
if (prop.name == "script") {
|
||||||
// Skip the script property, it's always added by the non-virtual method.
|
// Skip the script property, it's always added by the non-virtual method.
|
||||||
|
|
@ -66,31 +94,35 @@ void EditorDebuggerRemoteObject::_get_property_list(List<PropertyInfo> *p_list)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String EditorDebuggerRemoteObject::get_title() {
|
void EditorDebuggerRemoteObjects::set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field) {
|
||||||
if (remote_object_id.is_valid()) {
|
_set_impl(p_property, p_value, p_field);
|
||||||
return vformat(TTR("Remote %s:"), String(type_name)) + " " + itos(remote_object_id);
|
|
||||||
} else {
|
|
||||||
return "<null>";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Variant EditorDebuggerRemoteObject::get_variant(const StringName &p_name) {
|
String EditorDebuggerRemoteObjects::get_title() {
|
||||||
|
if (!remote_object_ids.is_empty() && ObjectID(remote_object_ids[0].operator uint64_t()).is_valid()) {
|
||||||
|
const int size = remote_object_ids.size();
|
||||||
|
return size == 1 ? vformat(TTR("Remote %s: %d"), type_name, remote_object_ids[0]) : vformat(TTR("Remote %s (%d Selected)"), type_name, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return "<null>";
|
||||||
|
}
|
||||||
|
|
||||||
|
Variant EditorDebuggerRemoteObjects::get_variant(const StringName &p_name) {
|
||||||
Variant var;
|
Variant var;
|
||||||
_get(p_name, var);
|
_get(p_name, var);
|
||||||
return var;
|
return var;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerRemoteObject::_bind_methods() {
|
void EditorDebuggerRemoteObjects::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_title"), &EditorDebuggerRemoteObject::get_title);
|
ClassDB::bind_method(D_METHOD("get_title"), &EditorDebuggerRemoteObjects::get_title);
|
||||||
ClassDB::bind_method(D_METHOD("get_variant"), &EditorDebuggerRemoteObject::get_variant);
|
|
||||||
ClassDB::bind_method(D_METHOD("clear"), &EditorDebuggerRemoteObject::clear);
|
|
||||||
ClassDB::bind_method(D_METHOD("get_remote_object_id"), &EditorDebuggerRemoteObject::get_remote_object_id);
|
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("value_edited", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value")));
|
ADD_SIGNAL(MethodInfo("values_edited", PropertyInfo(Variant::STRING, "property"), PropertyInfo(Variant::DICTIONARY, "values", PROPERTY_HINT_DICTIONARY_TYPE, "uint64_t:Variant"), PropertyInfo(Variant::STRING, "field")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// EditorDebuggerInspector
|
||||||
|
|
||||||
EditorDebuggerInspector::EditorDebuggerInspector() {
|
EditorDebuggerInspector::EditorDebuggerInspector() {
|
||||||
variables = memnew(EditorDebuggerRemoteObject);
|
variables = memnew(EditorDebuggerRemoteObjects);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorDebuggerInspector::~EditorDebuggerInspector() {
|
EditorDebuggerInspector::~EditorDebuggerInspector() {
|
||||||
|
|
@ -100,7 +132,7 @@ EditorDebuggerInspector::~EditorDebuggerInspector() {
|
||||||
|
|
||||||
void EditorDebuggerInspector::_bind_methods() {
|
void EditorDebuggerInspector::_bind_methods() {
|
||||||
ADD_SIGNAL(MethodInfo("object_selected", PropertyInfo(Variant::INT, "id")));
|
ADD_SIGNAL(MethodInfo("object_selected", PropertyInfo(Variant::INT, "id")));
|
||||||
ADD_SIGNAL(MethodInfo("object_edited", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value")));
|
ADD_SIGNAL(MethodInfo("objects_edited", PropertyInfo(Variant::ARRAY, "ids"), PropertyInfo(Variant::STRING, "property"), PropertyInfo("value"), PropertyInfo(Variant::STRING, "field")));
|
||||||
ADD_SIGNAL(MethodInfo("object_property_updated", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property")));
|
ADD_SIGNAL(MethodInfo("object_property_updated", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,50 +143,143 @@ void EditorDebuggerInspector::_notification(int p_what) {
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case NOTIFICATION_ENTER_TREE: {
|
case NOTIFICATION_ENTER_TREE: {
|
||||||
|
variables->remote_object_ids.append(0);
|
||||||
edit(variables);
|
edit(variables);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerInspector::_object_edited(ObjectID p_id, const String &p_prop, const Variant &p_value) {
|
void EditorDebuggerInspector::_objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field) {
|
||||||
emit_signal(SNAME("object_edited"), p_id, p_prop, p_value);
|
emit_signal(SNAME("objects_edited"), p_prop, p_values, p_field);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerInspector::_object_selected(ObjectID p_object) {
|
void EditorDebuggerInspector::_object_selected(ObjectID p_object) {
|
||||||
emit_signal(SNAME("object_selected"), p_object);
|
emit_signal(SNAME("object_selected"), p_object);
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
|
EditorDebuggerRemoteObjects *EditorDebuggerInspector::set_objects(const Array &p_arr) {
|
||||||
EditorDebuggerRemoteObject *debug_obj = nullptr;
|
ERR_FAIL_COND_V(p_arr.is_empty(), nullptr);
|
||||||
|
|
||||||
SceneDebuggerObject obj;
|
TypedArray<uint64_t> ids;
|
||||||
obj.deserialize(p_arr);
|
LocalVector<SceneDebuggerObject> objects;
|
||||||
ERR_FAIL_COND_V(obj.id.is_null(), ObjectID());
|
for (const Array arr : p_arr) {
|
||||||
|
SceneDebuggerObject obj;
|
||||||
|
obj.deserialize(arr);
|
||||||
|
if (obj.id.is_valid()) {
|
||||||
|
ids.push_back((uint64_t)obj.id);
|
||||||
|
objects.push_back(obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERR_FAIL_COND_V(ids.is_empty(), nullptr);
|
||||||
|
|
||||||
if (remote_objects.has(obj.id)) {
|
// Sorting is necessary, as selected nodes in the remote tree are ordered by index.
|
||||||
debug_obj = remote_objects[obj.id];
|
ids.sort();
|
||||||
} else {
|
|
||||||
debug_obj = memnew(EditorDebuggerRemoteObject);
|
EditorDebuggerRemoteObjects *remote_objects = nullptr;
|
||||||
debug_obj->remote_object_id = obj.id;
|
for (EditorDebuggerRemoteObjects *robjs : remote_objects_list) {
|
||||||
debug_obj->type_name = obj.class_name;
|
if (robjs->remote_object_ids == ids) {
|
||||||
remote_objects[obj.id] = debug_obj;
|
remote_objects = robjs;
|
||||||
debug_obj->connect("value_edited", callable_mp(this, &EditorDebuggerInspector::_object_edited));
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int old_prop_size = debug_obj->prop_list.size();
|
if (!remote_objects) {
|
||||||
|
remote_objects = memnew(EditorDebuggerRemoteObjects);
|
||||||
|
remote_objects->remote_object_ids = ids;
|
||||||
|
remote_objects->remote_object_ids.make_read_only();
|
||||||
|
remote_objects->connect("values_edited", callable_mp(this, &EditorDebuggerInspector::_objects_edited));
|
||||||
|
remote_objects_list.push_back(remote_objects);
|
||||||
|
}
|
||||||
|
|
||||||
debug_obj->prop_list.clear();
|
StringName class_name = objects[0].class_name;
|
||||||
|
if (class_name != SNAME("Object")) {
|
||||||
|
// Search for the common class between all selected objects.
|
||||||
|
bool check_type_again = true;
|
||||||
|
while (check_type_again) {
|
||||||
|
check_type_again = false;
|
||||||
|
|
||||||
|
if (class_name == SNAME("Object") || class_name == StringName()) {
|
||||||
|
// All objects inherit from Object, so no need to continue checking.
|
||||||
|
class_name = SNAME("Object");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that all objects inherit from type_name.
|
||||||
|
for (const SceneDebuggerObject &obj : objects) {
|
||||||
|
if (obj.class_name == class_name || ClassDB::is_parent_class(obj.class_name, class_name)) {
|
||||||
|
continue; // class_name is the same or a parent of the object's class.
|
||||||
|
}
|
||||||
|
|
||||||
|
// class_name is not a parent of the node's class, so check again with the parent class.
|
||||||
|
class_name = ClassDB::get_parent_class(class_name);
|
||||||
|
check_type_again = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
remote_objects->type_name = class_name;
|
||||||
|
|
||||||
|
// Search for properties that are present in all selected objects.
|
||||||
|
struct UsageData {
|
||||||
|
int qty = 0;
|
||||||
|
SceneDebuggerObject::SceneDebuggerProperty prop;
|
||||||
|
TypedDictionary<uint64_t, Variant> values;
|
||||||
|
};
|
||||||
|
HashMap<String, UsageData> usage;
|
||||||
|
int nc = 0;
|
||||||
|
for (const SceneDebuggerObject &obj : objects) {
|
||||||
|
for (const SceneDebuggerObject::SceneDebuggerProperty &prop : obj.properties) {
|
||||||
|
PropertyInfo pinfo = prop.first;
|
||||||
|
if (pinfo.name == "script") {
|
||||||
|
continue; // Added later manually, since this is intercepted before being set (check Variant Object::get()).
|
||||||
|
} else if (pinfo.name.begins_with("metadata/")) {
|
||||||
|
pinfo.name = pinfo.name.replace_first("metadata/", "Metadata/"); // Trick to not get actual metadata edited from EditorDebuggerRemoteObjects.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!usage.has(pinfo.name)) {
|
||||||
|
UsageData usage_dt;
|
||||||
|
usage_dt.prop = prop;
|
||||||
|
usage_dt.prop.first.name = pinfo.name;
|
||||||
|
usage_dt.values[obj.id] = prop.second;
|
||||||
|
usage[pinfo.name] = usage_dt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure only properties with the same exact PropertyInfo data will appear.
|
||||||
|
if (usage[pinfo.name].prop.first == pinfo) {
|
||||||
|
usage[pinfo.name].qty++;
|
||||||
|
usage[pinfo.name].values[obj.id] = prop.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nc++;
|
||||||
|
}
|
||||||
|
for (HashMap<String, UsageData>::Iterator E = usage.begin(); E;) {
|
||||||
|
HashMap<String, UsageData>::Iterator next = E;
|
||||||
|
++next;
|
||||||
|
|
||||||
|
UsageData usage_dt = E->value;
|
||||||
|
if (nc != usage_dt.qty) {
|
||||||
|
// Doesn't appear on all of them, remove it.
|
||||||
|
usage.erase(E->key);
|
||||||
|
}
|
||||||
|
|
||||||
|
E = next;
|
||||||
|
}
|
||||||
|
|
||||||
|
int old_prop_size = remote_objects->prop_list.size();
|
||||||
|
|
||||||
|
remote_objects->prop_list.clear();
|
||||||
int new_props_added = 0;
|
int new_props_added = 0;
|
||||||
HashSet<String> changed;
|
HashSet<String> changed;
|
||||||
for (SceneDebuggerObject::SceneDebuggerProperty &property : obj.properties) {
|
for (const KeyValue<String, UsageData> &KV : usage) {
|
||||||
PropertyInfo &pinfo = property.first;
|
const PropertyInfo &pinfo = KV.value.prop.first;
|
||||||
Variant &var = property.second;
|
Variant var = KV.value.values[remote_objects->remote_object_ids[0]];
|
||||||
|
|
||||||
if (pinfo.type == Variant::OBJECT) {
|
if (pinfo.type == Variant::OBJECT) {
|
||||||
if (var.is_string()) {
|
if (var.is_string()) {
|
||||||
String path = var;
|
String path = var;
|
||||||
if (path.contains("::")) {
|
if (path.contains("::")) {
|
||||||
// built-in resource
|
// Built-in resource.
|
||||||
String base_path = path.get_slice("::", 0);
|
String base_path = path.get_slice("::", 0);
|
||||||
Ref<Resource> dependency = ResourceLoader::load(base_path);
|
Ref<Resource> dependency = ResourceLoader::load(base_path);
|
||||||
if (dependency.is_valid()) {
|
if (dependency.is_valid()) {
|
||||||
|
|
@ -164,13 +289,13 @@ ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
|
||||||
var = ResourceLoader::load(path);
|
var = ResourceLoader::load(path);
|
||||||
|
|
||||||
if (pinfo.hint_string == "Script") {
|
if (pinfo.hint_string == "Script") {
|
||||||
if (debug_obj->get_script() != var) {
|
if (remote_objects->get_script() != var) {
|
||||||
debug_obj->set_script(Ref<RefCounted>());
|
remote_objects->set_script(Ref<RefCounted>());
|
||||||
Ref<Script> scr(var);
|
Ref<Script> scr(var);
|
||||||
if (scr.is_valid()) {
|
if (scr.is_valid()) {
|
||||||
ScriptInstance *scr_instance = scr->placeholder_instance_create(debug_obj);
|
ScriptInstance *scr_instance = scr->placeholder_instance_create(remote_objects);
|
||||||
if (scr_instance) {
|
if (scr_instance) {
|
||||||
debug_obj->set_script_and_instance(var, scr_instance);
|
remote_objects->set_script_and_instance(var, scr_instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -178,49 +303,67 @@ ObjectID EditorDebuggerInspector::add_object(const Array &p_arr) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//always add the property, since props may have been added or removed
|
// Always add the property, since props may have been added or removed.
|
||||||
debug_obj->prop_list.push_back(pinfo);
|
remote_objects->prop_list.push_back(pinfo);
|
||||||
|
|
||||||
if (!debug_obj->prop_values.has(pinfo.name)) {
|
if (!remote_objects->prop_values.has(pinfo.name)) {
|
||||||
new_props_added++;
|
new_props_added++;
|
||||||
debug_obj->prop_values[pinfo.name] = var;
|
} else if (bool(Variant::evaluate(Variant::OP_NOT_EQUAL, remote_objects->prop_values[pinfo.name], var))) {
|
||||||
} else {
|
changed.insert(pinfo.name);
|
||||||
if (bool(Variant::evaluate(Variant::OP_NOT_EQUAL, debug_obj->prop_values[pinfo.name], var))) {
|
|
||||||
debug_obj->prop_values[pinfo.name] = var;
|
|
||||||
changed.insert(pinfo.name);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remote_objects->prop_values[pinfo.name] = KV.value.values;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (old_prop_size == debug_obj->prop_list.size() && new_props_added == 0) {
|
if (old_prop_size == remote_objects->prop_list.size() && new_props_added == 0) {
|
||||||
//only some may have changed, if so, then update those, if exist
|
// Only some may have changed, if so, then update those, if they exist.
|
||||||
for (const String &E : changed) {
|
for (const String &E : changed) {
|
||||||
emit_signal(SNAME("object_property_updated"), debug_obj->remote_object_id, E);
|
emit_signal(SNAME("object_property_updated"), remote_objects->get_instance_id(), E);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
//full update, because props were added or removed
|
// Full update, because props were added or removed.
|
||||||
debug_obj->update();
|
remote_objects->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
return remote_objects;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorDebuggerInspector::clear_remote_inspector() {
|
||||||
|
if (remote_objects_list.is_empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Object *obj = InspectorDock::get_inspector_singleton()->get_edited_object();
|
||||||
|
// Check if the inspector holds remote items, and take it out if so.
|
||||||
|
if (Object::cast_to<EditorDebuggerRemoteObjects>(obj)) {
|
||||||
|
EditorNode::get_singleton()->push_item(nullptr);
|
||||||
}
|
}
|
||||||
return obj.id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerInspector::clear_cache() {
|
void EditorDebuggerInspector::clear_cache() {
|
||||||
for (const KeyValue<ObjectID, EditorDebuggerRemoteObject *> &E : remote_objects) {
|
clear_remote_inspector();
|
||||||
EditorNode *editor = EditorNode::get_singleton();
|
|
||||||
if (editor->get_editor_selection_history()->get_current() == E.value->get_instance_id()) {
|
for (EditorDebuggerRemoteObjects *robjs : remote_objects_list) {
|
||||||
editor->push_item(nullptr);
|
memdelete(robjs);
|
||||||
}
|
|
||||||
memdelete(E.value);
|
|
||||||
}
|
}
|
||||||
remote_objects.clear();
|
remote_objects_list.clear();
|
||||||
|
|
||||||
remote_dependencies.clear();
|
remote_dependencies.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *EditorDebuggerInspector::get_object(ObjectID p_id) {
|
void EditorDebuggerInspector::invalidate_selection_from_cache(const TypedArray<uint64_t> &p_ids) {
|
||||||
if (remote_objects.has(p_id)) {
|
for (EditorDebuggerRemoteObjects *robjs : remote_objects_list) {
|
||||||
return remote_objects[p_id];
|
if (robjs->remote_object_ids == p_ids) {
|
||||||
|
const Object *obj = InspectorDock::get_inspector_singleton()->get_edited_object();
|
||||||
|
if (obj == robjs) {
|
||||||
|
EditorNode::get_singleton()->push_item(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
remote_objects_list.erase(robjs);
|
||||||
|
memdelete(robjs);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerInspector::add_stack_variable(const Array &p_array, int p_offset) {
|
void EditorDebuggerInspector::add_stack_variable(const Array &p_array, int p_offset) {
|
||||||
|
|
@ -270,7 +413,7 @@ void EditorDebuggerInspector::add_stack_variable(const Array &p_array, int p_off
|
||||||
}
|
}
|
||||||
variables->prop_list.insert_before(current, pinfo);
|
variables->prop_list.insert_before(current, pinfo);
|
||||||
}
|
}
|
||||||
variables->prop_values[type + n] = v;
|
variables->prop_values[type + n][0] = v;
|
||||||
variables->update();
|
variables->update();
|
||||||
edit(variables);
|
edit(variables);
|
||||||
|
|
||||||
|
|
@ -288,7 +431,7 @@ void EditorDebuggerInspector::clear_stack_variables() {
|
||||||
}
|
}
|
||||||
|
|
||||||
String EditorDebuggerInspector::get_stack_variable(const String &p_var) {
|
String EditorDebuggerInspector::get_stack_variable(const String &p_var) {
|
||||||
for (KeyValue<StringName, Variant> &E : variables->prop_values) {
|
for (KeyValue<StringName, TypedDictionary<uint64_t, Variant>> &E : variables->prop_values) {
|
||||||
String v = E.key.operator String();
|
String v = E.key.operator String();
|
||||||
if (v.get_slicec('/', 1) == p_var) {
|
if (v.get_slicec('/', 1) == p_var) {
|
||||||
return variables->get_variant(v);
|
return variables->get_variant(v);
|
||||||
|
|
|
||||||
|
|
@ -30,10 +30,16 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core/variant/typed_dictionary.h"
|
||||||
#include "editor/editor_inspector.h"
|
#include "editor/editor_inspector.h"
|
||||||
|
|
||||||
class EditorDebuggerRemoteObject : public Object {
|
class SceneDebuggerObject;
|
||||||
GDCLASS(EditorDebuggerRemoteObject, Object);
|
|
||||||
|
class EditorDebuggerRemoteObjects : public Object {
|
||||||
|
GDCLASS(EditorDebuggerRemoteObjects, Object);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool _set_impl(const StringName &p_name, const Variant &p_value, const String &p_field);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool _set(const StringName &p_name, const Variant &p_value);
|
bool _set(const StringName &p_name, const Variant &p_value);
|
||||||
|
|
@ -42,14 +48,13 @@ protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ObjectID remote_object_id;
|
TypedArray<uint64_t> remote_object_ids;
|
||||||
String type_name;
|
String type_name;
|
||||||
List<PropertyInfo> prop_list;
|
List<PropertyInfo> prop_list;
|
||||||
HashMap<StringName, Variant> prop_values;
|
HashMap<StringName, TypedDictionary<uint64_t, Variant>> prop_values;
|
||||||
|
|
||||||
ObjectID get_remote_object_id() { return remote_object_id; }
|
void set_property_field(const StringName &p_property, const Variant &p_value, const String &p_field);
|
||||||
String get_title();
|
String get_title();
|
||||||
|
|
||||||
Variant get_variant(const StringName &p_name);
|
Variant get_variant(const StringName &p_name);
|
||||||
|
|
||||||
void clear() {
|
void clear() {
|
||||||
|
|
@ -59,20 +64,19 @@ public:
|
||||||
|
|
||||||
void update() { notify_property_list_changed(); }
|
void update() { notify_property_list_changed(); }
|
||||||
|
|
||||||
EditorDebuggerRemoteObject() {}
|
EditorDebuggerRemoteObjects() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class EditorDebuggerInspector : public EditorInspector {
|
class EditorDebuggerInspector : public EditorInspector {
|
||||||
GDCLASS(EditorDebuggerInspector, EditorInspector);
|
GDCLASS(EditorDebuggerInspector, EditorInspector);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ObjectID inspected_object_id;
|
LocalVector<EditorDebuggerRemoteObjects *> remote_objects_list;
|
||||||
HashMap<ObjectID, EditorDebuggerRemoteObject *> remote_objects;
|
|
||||||
HashSet<Ref<Resource>> remote_dependencies;
|
HashSet<Ref<Resource>> remote_dependencies;
|
||||||
EditorDebuggerRemoteObject *variables = nullptr;
|
EditorDebuggerRemoteObjects *variables = nullptr;
|
||||||
|
|
||||||
void _object_selected(ObjectID p_object);
|
void _object_selected(ObjectID p_object);
|
||||||
void _object_edited(ObjectID p_id, const String &p_prop, const Variant &p_value);
|
void _objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
|
|
@ -83,9 +87,10 @@ public:
|
||||||
~EditorDebuggerInspector();
|
~EditorDebuggerInspector();
|
||||||
|
|
||||||
// Remote Object cache
|
// Remote Object cache
|
||||||
ObjectID add_object(const Array &p_arr);
|
EditorDebuggerRemoteObjects *set_objects(const Array &p_array);
|
||||||
Object *get_object(ObjectID p_id);
|
void clear_remote_inspector();
|
||||||
void clear_cache();
|
void clear_cache();
|
||||||
|
void invalidate_selection_from_cache(const TypedArray<uint64_t> &p_ids);
|
||||||
|
|
||||||
// Stack Dump variables
|
// Stack Dump variables
|
||||||
String get_stack_variable(const String &p_var);
|
String get_stack_variable(const String &p_var);
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,8 @@ EditorDebuggerNode::EditorDebuggerNode() {
|
||||||
|
|
||||||
// Remote scene tree
|
// Remote scene tree
|
||||||
remote_scene_tree = memnew(EditorDebuggerTree);
|
remote_scene_tree = memnew(EditorDebuggerTree);
|
||||||
remote_scene_tree->connect("object_selected", callable_mp(this, &EditorDebuggerNode::_remote_object_requested));
|
remote_scene_tree->connect("objects_selected", callable_mp(this, &EditorDebuggerNode::_remote_objects_requested));
|
||||||
|
remote_scene_tree->connect("selection_cleared", callable_mp(this, &EditorDebuggerNode::_remote_selection_cleared));
|
||||||
remote_scene_tree->connect("save_node", callable_mp(this, &EditorDebuggerNode::_save_node_requested));
|
remote_scene_tree->connect("save_node", callable_mp(this, &EditorDebuggerNode::_save_node_requested));
|
||||||
remote_scene_tree->connect("button_clicked", callable_mp(this, &EditorDebuggerNode::_remote_tree_button_pressed));
|
remote_scene_tree->connect("button_clicked", callable_mp(this, &EditorDebuggerNode::_remote_tree_button_pressed));
|
||||||
SceneTreeDock::get_singleton()->add_remote_tree_editor(remote_scene_tree);
|
SceneTreeDock::get_singleton()->add_remote_tree_editor(remote_scene_tree);
|
||||||
|
|
@ -109,11 +110,12 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
|
||||||
node->connect("breakpoint_selected", callable_mp(this, &EditorDebuggerNode::_error_selected).bind(id));
|
node->connect("breakpoint_selected", callable_mp(this, &EditorDebuggerNode::_error_selected).bind(id));
|
||||||
node->connect("clear_execution", callable_mp(this, &EditorDebuggerNode::_clear_execution));
|
node->connect("clear_execution", callable_mp(this, &EditorDebuggerNode::_clear_execution));
|
||||||
node->connect("breaked", callable_mp(this, &EditorDebuggerNode::_breaked).bind(id));
|
node->connect("breaked", callable_mp(this, &EditorDebuggerNode::_breaked).bind(id));
|
||||||
|
node->connect("debug_data", callable_mp(this, &EditorDebuggerNode::_debug_data).bind(id));
|
||||||
node->connect("remote_tree_select_requested", callable_mp(this, &EditorDebuggerNode::_remote_tree_select_requested).bind(id));
|
node->connect("remote_tree_select_requested", callable_mp(this, &EditorDebuggerNode::_remote_tree_select_requested).bind(id));
|
||||||
|
node->connect("remote_tree_clear_selection_requested", callable_mp(this, &EditorDebuggerNode::_remote_tree_clear_selection_requested).bind(id));
|
||||||
node->connect("remote_tree_updated", callable_mp(this, &EditorDebuggerNode::_remote_tree_updated).bind(id));
|
node->connect("remote_tree_updated", callable_mp(this, &EditorDebuggerNode::_remote_tree_updated).bind(id));
|
||||||
node->connect("remote_object_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_updated).bind(id));
|
node->connect("remote_objects_updated", callable_mp(this, &EditorDebuggerNode::_remote_objects_updated).bind(id));
|
||||||
node->connect("remote_object_property_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_property_updated).bind(id));
|
node->connect("remote_object_property_updated", callable_mp(this, &EditorDebuggerNode::_remote_object_property_updated).bind(id));
|
||||||
node->connect("remote_object_requested", callable_mp(this, &EditorDebuggerNode::_remote_object_requested).bind(id));
|
|
||||||
node->connect("set_breakpoint", callable_mp(this, &EditorDebuggerNode::_breakpoint_set_in_tree).bind(id));
|
node->connect("set_breakpoint", callable_mp(this, &EditorDebuggerNode::_breakpoint_set_in_tree).bind(id));
|
||||||
node->connect("clear_breakpoints", callable_mp(this, &EditorDebuggerNode::_breakpoints_cleared_in_tree).bind(id));
|
node->connect("clear_breakpoints", callable_mp(this, &EditorDebuggerNode::_breakpoints_cleared_in_tree).bind(id));
|
||||||
node->connect("errors_cleared", callable_mp(this, &EditorDebuggerNode::_update_errors));
|
node->connect("errors_cleared", callable_mp(this, &EditorDebuggerNode::_update_errors));
|
||||||
|
|
@ -222,10 +224,6 @@ void EditorDebuggerNode::register_undo_redo(UndoRedo *p_undo_redo) {
|
||||||
p_undo_redo->set_property_notify_callback(_properties_changed, this);
|
p_undo_redo->set_property_notify_callback(_properties_changed, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
EditorDebuggerRemoteObject *EditorDebuggerNode::get_inspected_remote_object() {
|
|
||||||
return Object::cast_to<EditorDebuggerRemoteObject>(ObjectDB::get_instance(EditorNode::get_singleton()->get_editor_selection_history()->get_current()));
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptEditorDebugger *EditorDebuggerNode::get_debugger(int p_id) const {
|
ScriptEditorDebugger *EditorDebuggerNode::get_debugger(int p_id) const {
|
||||||
return Object::cast_to<ScriptEditorDebugger>(tabs->get_tab_control(p_id));
|
return Object::cast_to<ScriptEditorDebugger>(tabs->get_tab_control(p_id));
|
||||||
}
|
}
|
||||||
|
|
@ -292,6 +290,10 @@ void EditorDebuggerNode::stop(bool p_force) {
|
||||||
if (keep_open && !p_force) {
|
if (keep_open && !p_force) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
remote_scene_tree_wait = false;
|
||||||
|
inspect_edited_object_wait = false;
|
||||||
|
|
||||||
current_uri.clear();
|
current_uri.clear();
|
||||||
if (server.is_valid()) {
|
if (server.is_valid()) {
|
||||||
server->stop();
|
server->stop();
|
||||||
|
|
@ -304,6 +306,7 @@ void EditorDebuggerNode::stop(bool p_force) {
|
||||||
|
|
||||||
server.unref();
|
server.unref();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also close all debugging sessions.
|
// Also close all debugging sessions.
|
||||||
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
|
_for_all(tabs, [&](ScriptEditorDebugger *dbg) {
|
||||||
if (dbg->is_session_active()) {
|
if (dbg->is_session_active()) {
|
||||||
|
|
@ -351,21 +354,29 @@ void EditorDebuggerNode::_notification(int p_what) {
|
||||||
|
|
||||||
_update_errors();
|
_update_errors();
|
||||||
|
|
||||||
// Remote scene tree update
|
// Remote scene tree update.
|
||||||
remote_scene_tree_timeout -= get_process_delta_time();
|
if (!remote_scene_tree_wait) {
|
||||||
if (remote_scene_tree_timeout < 0) {
|
remote_scene_tree_timeout -= get_process_delta_time();
|
||||||
remote_scene_tree_timeout = EDITOR_GET("debugger/remote_scene_tree_refresh_interval");
|
if (remote_scene_tree_timeout < 0) {
|
||||||
if (remote_scene_tree->is_visible_in_tree()) {
|
remote_scene_tree_timeout = EDITOR_GET("debugger/remote_scene_tree_refresh_interval");
|
||||||
get_current_debugger()->request_remote_tree();
|
|
||||||
|
if (remote_scene_tree->is_visible_in_tree()) {
|
||||||
|
remote_scene_tree_wait = true;
|
||||||
|
get_current_debugger()->request_remote_tree();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remote inspector update
|
// Remote inspector update.
|
||||||
inspect_edited_object_timeout -= get_process_delta_time();
|
if (!inspect_edited_object_wait) {
|
||||||
if (inspect_edited_object_timeout < 0) {
|
inspect_edited_object_timeout -= get_process_delta_time();
|
||||||
inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");
|
if (inspect_edited_object_timeout < 0) {
|
||||||
if (EditorDebuggerRemoteObject *obj = get_inspected_remote_object()) {
|
inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");
|
||||||
get_current_debugger()->request_remote_object(obj->remote_object_id);
|
|
||||||
|
if (EditorDebuggerRemoteObjects *robjs = Object::cast_to<EditorDebuggerRemoteObjects>(InspectorDock::get_inspector_singleton()->get_edited_object())) {
|
||||||
|
inspect_edited_object_wait = true;
|
||||||
|
get_current_debugger()->request_remote_objects(robjs->remote_object_ids, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -467,21 +478,26 @@ void EditorDebuggerNode::_debugger_stopped(int p_id) {
|
||||||
|
|
||||||
void EditorDebuggerNode::_debugger_wants_stop(int p_id) {
|
void EditorDebuggerNode::_debugger_wants_stop(int p_id) {
|
||||||
// Ask editor to kill PID.
|
// Ask editor to kill PID.
|
||||||
int pid = get_debugger(p_id)->get_remote_pid();
|
if (int pid = get_debugger(p_id)->get_remote_pid()) {
|
||||||
if (pid) {
|
|
||||||
callable_mp(EditorNode::get_singleton(), &EditorNode::stop_child_process).call_deferred(pid);
|
callable_mp(EditorNode::get_singleton(), &EditorNode::stop_child_process).call_deferred(pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerNode::_debugger_changed(int p_tab) {
|
void EditorDebuggerNode::_debugger_changed(int p_tab) {
|
||||||
if (get_inspected_remote_object()) {
|
remote_scene_tree_wait = false;
|
||||||
// Clear inspected object, you can only inspect objects in selected debugger.
|
inspect_edited_object_wait = false;
|
||||||
// Hopefully, in the future, we will have one inspector per debugger.
|
|
||||||
EditorNode::get_singleton()->push_item(nullptr);
|
if (Object *robjs = InspectorDock::get_inspector_singleton()->get_edited_object()) {
|
||||||
|
if (Object::cast_to<EditorDebuggerRemoteObjects>(robjs)) {
|
||||||
|
// Clear inspected object, you can only inspect objects in selected debugger.
|
||||||
|
// Hopefully, in the future, we will have one inspector per debugger.
|
||||||
|
EditorNode::get_singleton()->push_item(nullptr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (get_previous_debugger()) {
|
if (ScriptEditorDebugger *prev_debug = get_previous_debugger()) {
|
||||||
_text_editor_stack_clear(get_previous_debugger());
|
prev_debug->clear_inspector();
|
||||||
|
_text_editor_stack_clear(prev_debug);
|
||||||
}
|
}
|
||||||
if (remote_scene_tree->is_visible_in_tree()) {
|
if (remote_scene_tree->is_visible_in_tree()) {
|
||||||
get_current_debugger()->request_remote_tree();
|
get_current_debugger()->request_remote_tree();
|
||||||
|
|
@ -493,6 +509,18 @@ void EditorDebuggerNode::_debugger_changed(int p_tab) {
|
||||||
_break_state_changed();
|
_break_state_changed();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EditorDebuggerNode::_debug_data(const String &p_msg, const Array &p_data, int p_debugger) {
|
||||||
|
if (p_debugger != tabs->get_current_tab()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (p_msg == "scene:scene_tree") {
|
||||||
|
remote_scene_tree_wait = false;
|
||||||
|
} else if (p_msg == "scene:inspect_objects") {
|
||||||
|
inspect_edited_object_wait = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void EditorDebuggerNode::set_script_debug_button(MenuButton *p_button) {
|
void EditorDebuggerNode::set_script_debug_button(MenuButton *p_button) {
|
||||||
script_menu = p_button;
|
script_menu = p_button;
|
||||||
script_menu->set_text(TTR("Debug"));
|
script_menu->set_text(TTR("Debug"));
|
||||||
|
|
@ -646,11 +674,41 @@ void EditorDebuggerNode::request_remote_tree() {
|
||||||
get_current_debugger()->request_remote_tree();
|
get_current_debugger()->request_remote_tree();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerNode::_remote_tree_select_requested(ObjectID p_id, int p_debugger) {
|
void EditorDebuggerNode::set_remote_selection(const TypedArray<int64_t> &p_ids) {
|
||||||
|
remote_scene_tree->select_nodes(p_ids);
|
||||||
|
|
||||||
|
stop_waiting_inspection();
|
||||||
|
get_current_debugger()->request_remote_objects(p_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorDebuggerNode::clear_remote_tree_selection() {
|
||||||
|
remote_scene_tree->clear_selection();
|
||||||
|
get_current_debugger()->clear_inspector(remote_scene_tree_clear_msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorDebuggerNode::stop_waiting_inspection() {
|
||||||
|
inspect_edited_object_timeout = EDITOR_GET("debugger/remote_inspect_refresh_interval");
|
||||||
|
inspect_edited_object_wait = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EditorDebuggerNode::match_remote_selection(const TypedArray<uint64_t> &p_ids) const {
|
||||||
|
return p_ids == remote_scene_tree->get_selection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorDebuggerNode::_remote_tree_select_requested(const TypedArray<int64_t> &p_ids, int p_debugger) {
|
||||||
|
if (p_debugger == tabs->get_current_tab()) {
|
||||||
|
remote_scene_tree->select_nodes(p_ids);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorDebuggerNode::_remote_tree_clear_selection_requested(int p_debugger) {
|
||||||
if (p_debugger != tabs->get_current_tab()) {
|
if (p_debugger != tabs->get_current_tab()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
remote_scene_tree->select_node(p_id);
|
remote_scene_tree->clear_selection();
|
||||||
|
remote_scene_tree_clear_msg = false;
|
||||||
|
get_current_debugger()->clear_inspector(false);
|
||||||
|
remote_scene_tree_clear_msg = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerNode::_remote_tree_updated(int p_debugger) {
|
void EditorDebuggerNode::_remote_tree_updated(int p_debugger) {
|
||||||
|
|
@ -679,37 +737,37 @@ void EditorDebuggerNode::_remote_tree_button_pressed(Object *p_item, int p_colum
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerNode::_remote_object_updated(ObjectID p_id, int p_debugger) {
|
void EditorDebuggerNode::_remote_objects_updated(EditorDebuggerRemoteObjects *p_objs, int p_debugger) {
|
||||||
if (p_debugger != tabs->get_current_tab()) {
|
if (p_debugger == tabs->get_current_tab() && p_objs != InspectorDock::get_inspector_singleton()->get_edited_object()) {
|
||||||
return;
|
EditorNode::get_singleton()->push_item(p_objs);
|
||||||
}
|
}
|
||||||
if (EditorDebuggerRemoteObject *obj = get_inspected_remote_object()) {
|
|
||||||
if (obj->remote_object_id == p_id) {
|
|
||||||
return; // Already being edited
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
EditorNode::get_singleton()->push_item(get_current_debugger()->get_remote_object(p_id));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerNode::_remote_object_property_updated(ObjectID p_id, const String &p_property, int p_debugger) {
|
void EditorDebuggerNode::_remote_object_property_updated(ObjectID p_id, const String &p_property, int p_debugger) {
|
||||||
if (p_debugger != tabs->get_current_tab()) {
|
if (p_debugger != tabs->get_current_tab()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (EditorDebuggerRemoteObject *obj = get_inspected_remote_object()) {
|
|
||||||
if (obj->remote_object_id != p_id) {
|
Object *obj = InspectorDock::get_inspector_singleton()->get_edited_object();
|
||||||
return;
|
if (obj && obj->get_instance_id() == p_id) {
|
||||||
}
|
|
||||||
InspectorDock::get_inspector_singleton()->update_property(p_property);
|
InspectorDock::get_inspector_singleton()->update_property(p_property);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerNode::_remote_object_requested(ObjectID p_id, int p_debugger) {
|
void EditorDebuggerNode::_remote_objects_requested(const TypedArray<uint64_t> &p_ids, int p_debugger) {
|
||||||
if (p_debugger != tabs->get_current_tab()) {
|
if (p_debugger != tabs->get_current_tab()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
inspect_edited_object_timeout = 0.7; // Temporarily disable timeout to avoid multiple requests.
|
stop_waiting_inspection();
|
||||||
get_current_debugger()->request_remote_object(p_id);
|
get_current_debugger()->request_remote_objects(p_ids);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorDebuggerNode::_remote_selection_cleared(int p_debugger) {
|
||||||
|
if (p_debugger != tabs->get_current_tab()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
stop_waiting_inspection();
|
||||||
|
get_current_debugger()->clear_inspector();
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerNode::_save_node_requested(ObjectID p_id, const String &p_file, int p_debugger) {
|
void EditorDebuggerNode::_save_node_requested(ObjectID p_id, const String &p_file, int p_debugger) {
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,7 @@ class Button;
|
||||||
class DebugAdapterParser;
|
class DebugAdapterParser;
|
||||||
class EditorDebuggerPlugin;
|
class EditorDebuggerPlugin;
|
||||||
class EditorDebuggerTree;
|
class EditorDebuggerTree;
|
||||||
class EditorDebuggerRemoteObject;
|
class EditorDebuggerRemoteObjects;
|
||||||
class MenuButton;
|
class MenuButton;
|
||||||
class ScriptEditorDebugger;
|
class ScriptEditorDebugger;
|
||||||
class TabContainer;
|
class TabContainer;
|
||||||
|
|
@ -102,9 +102,12 @@ private:
|
||||||
int last_error_count = 0;
|
int last_error_count = 0;
|
||||||
int last_warning_count = 0;
|
int last_warning_count = 0;
|
||||||
|
|
||||||
|
bool inspect_edited_object_wait = false;
|
||||||
float inspect_edited_object_timeout = 0;
|
float inspect_edited_object_timeout = 0;
|
||||||
EditorDebuggerTree *remote_scene_tree = nullptr;
|
EditorDebuggerTree *remote_scene_tree = nullptr;
|
||||||
|
bool remote_scene_tree_wait = false;
|
||||||
float remote_scene_tree_timeout = 0.0;
|
float remote_scene_tree_timeout = 0.0;
|
||||||
|
bool remote_scene_tree_clear_msg = true;
|
||||||
bool auto_switch_remote_scene_tree = false;
|
bool auto_switch_remote_scene_tree = false;
|
||||||
bool debug_with_external_editor = false;
|
bool debug_with_external_editor = false;
|
||||||
bool keep_open = false;
|
bool keep_open = false;
|
||||||
|
|
@ -116,7 +119,6 @@ private:
|
||||||
HashSet<Ref<EditorDebuggerPlugin>> debugger_plugins;
|
HashSet<Ref<EditorDebuggerPlugin>> debugger_plugins;
|
||||||
|
|
||||||
ScriptEditorDebugger *_add_debugger();
|
ScriptEditorDebugger *_add_debugger();
|
||||||
EditorDebuggerRemoteObject *get_inspected_remote_object();
|
|
||||||
void _update_errors();
|
void _update_errors();
|
||||||
|
|
||||||
friend class DebuggerEditorPlugin;
|
friend class DebuggerEditorPlugin;
|
||||||
|
|
@ -128,12 +130,15 @@ protected:
|
||||||
void _debugger_stopped(int p_id);
|
void _debugger_stopped(int p_id);
|
||||||
void _debugger_wants_stop(int p_id);
|
void _debugger_wants_stop(int p_id);
|
||||||
void _debugger_changed(int p_tab);
|
void _debugger_changed(int p_tab);
|
||||||
void _remote_tree_select_requested(ObjectID p_id, int p_debugger);
|
void _debug_data(const String &p_msg, const Array &p_data, int p_debugger);
|
||||||
|
void _remote_tree_select_requested(const TypedArray<int64_t> &p_ids, int p_debugger);
|
||||||
|
void _remote_tree_clear_selection_requested(int p_debugger);
|
||||||
void _remote_tree_updated(int p_debugger);
|
void _remote_tree_updated(int p_debugger);
|
||||||
void _remote_tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
|
void _remote_tree_button_pressed(Object *p_item, int p_column, int p_id, MouseButton p_button);
|
||||||
void _remote_object_updated(ObjectID p_id, int p_debugger);
|
void _remote_objects_updated(EditorDebuggerRemoteObjects *p_objs, int p_debugger);
|
||||||
void _remote_object_property_updated(ObjectID p_id, const String &p_property, int p_debugger);
|
void _remote_object_property_updated(ObjectID p_id, const String &p_property, int p_debugger);
|
||||||
void _remote_object_requested(ObjectID p_id, int p_debugger);
|
void _remote_objects_requested(const TypedArray<uint64_t> &p_ids, int p_debugger);
|
||||||
|
void _remote_selection_cleared(int p_debugger);
|
||||||
void _save_node_requested(ObjectID p_id, const String &p_file, int p_debugger);
|
void _save_node_requested(ObjectID p_id, const String &p_file, int p_debugger);
|
||||||
|
|
||||||
void _breakpoint_set_in_tree(Ref<RefCounted> p_script, int p_line, bool p_enabled, int p_debugger);
|
void _breakpoint_set_in_tree(Ref<RefCounted> p_script, int p_line, bool p_enabled, int p_debugger);
|
||||||
|
|
@ -190,6 +195,10 @@ public:
|
||||||
|
|
||||||
// Remote inspector/edit.
|
// Remote inspector/edit.
|
||||||
void request_remote_tree();
|
void request_remote_tree();
|
||||||
|
void set_remote_selection(const TypedArray<int64_t> &p_ids);
|
||||||
|
void clear_remote_tree_selection();
|
||||||
|
void stop_waiting_inspection();
|
||||||
|
bool match_remote_selection(const TypedArray<uint64_t> &p_ids) const;
|
||||||
static void _methods_changed(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
|
static void _methods_changed(void *p_ud, Object *p_base, const StringName &p_name, const Variant **p_args, int p_argcount);
|
||||||
static void _properties_changed(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
|
static void _properties_changed(void *p_ud, Object *p_base, const StringName &p_property, const Variant &p_value);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,7 @@
|
||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
#include "editor/editor_string_names.h"
|
#include "editor/editor_string_names.h"
|
||||||
#include "editor/gui/editor_file_dialog.h"
|
#include "editor/gui/editor_file_dialog.h"
|
||||||
|
#include "editor/gui/editor_toaster.h"
|
||||||
#include "editor/scene_tree_dock.h"
|
#include "editor/scene_tree_dock.h"
|
||||||
#include "scene/debugger/scene_debugger.h"
|
#include "scene/debugger/scene_debugger.h"
|
||||||
#include "scene/gui/texture_rect.h"
|
#include "scene/gui/texture_rect.h"
|
||||||
|
|
@ -44,6 +45,7 @@
|
||||||
EditorDebuggerTree::EditorDebuggerTree() {
|
EditorDebuggerTree::EditorDebuggerTree() {
|
||||||
set_v_size_flags(SIZE_EXPAND_FILL);
|
set_v_size_flags(SIZE_EXPAND_FILL);
|
||||||
set_allow_rmb_select(true);
|
set_allow_rmb_select(true);
|
||||||
|
set_select_mode(SELECT_MULTI);
|
||||||
|
|
||||||
// Popup
|
// Popup
|
||||||
item_menu = memnew(PopupMenu);
|
item_menu = memnew(PopupMenu);
|
||||||
|
|
@ -54,6 +56,9 @@ EditorDebuggerTree::EditorDebuggerTree() {
|
||||||
file_dialog = memnew(EditorFileDialog);
|
file_dialog = memnew(EditorFileDialog);
|
||||||
file_dialog->connect("file_selected", callable_mp(this, &EditorDebuggerTree::_file_selected));
|
file_dialog->connect("file_selected", callable_mp(this, &EditorDebuggerTree::_file_selected));
|
||||||
add_child(file_dialog);
|
add_child(file_dialog);
|
||||||
|
|
||||||
|
accept = memnew(AcceptDialog);
|
||||||
|
add_child(accept);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerTree::_notification(int p_what) {
|
void EditorDebuggerTree::_notification(int p_what) {
|
||||||
|
|
@ -61,7 +66,8 @@ void EditorDebuggerTree::_notification(int p_what) {
|
||||||
case NOTIFICATION_POSTINITIALIZE: {
|
case NOTIFICATION_POSTINITIALIZE: {
|
||||||
set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
set_auto_translate_mode(AUTO_TRANSLATE_MODE_DISABLED);
|
||||||
|
|
||||||
connect("cell_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_selected));
|
connect("multi_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_selection_changed));
|
||||||
|
connect("nothing_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_nothing_selected));
|
||||||
connect("item_collapsed", callable_mp(this, &EditorDebuggerTree::_scene_tree_folded));
|
connect("item_collapsed", callable_mp(this, &EditorDebuggerTree::_scene_tree_folded));
|
||||||
connect("item_mouse_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_rmb_selected));
|
connect("item_mouse_selected", callable_mp(this, &EditorDebuggerTree::_scene_tree_rmb_selected));
|
||||||
} break;
|
} break;
|
||||||
|
|
@ -73,24 +79,57 @@ void EditorDebuggerTree::_notification(int p_what) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerTree::_bind_methods() {
|
void EditorDebuggerTree::_bind_methods() {
|
||||||
ADD_SIGNAL(MethodInfo("object_selected", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::INT, "debugger")));
|
ADD_SIGNAL(MethodInfo("objects_selected", PropertyInfo(Variant::ARRAY, "object_ids"), PropertyInfo(Variant::INT, "debugger")));
|
||||||
|
ADD_SIGNAL(MethodInfo("selection_cleared", PropertyInfo(Variant::INT, "debugger")));
|
||||||
ADD_SIGNAL(MethodInfo("save_node", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "filename"), PropertyInfo(Variant::INT, "debugger")));
|
ADD_SIGNAL(MethodInfo("save_node", PropertyInfo(Variant::INT, "object_id"), PropertyInfo(Variant::STRING, "filename"), PropertyInfo(Variant::INT, "debugger")));
|
||||||
ADD_SIGNAL(MethodInfo("open"));
|
ADD_SIGNAL(MethodInfo("open"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerTree::_scene_tree_selected() {
|
void EditorDebuggerTree::_scene_tree_selection_changed(TreeItem *p_item, int p_column, bool p_selected) {
|
||||||
if (updating_scene_tree) {
|
if (updating_scene_tree || !p_item) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
TreeItem *item = get_selected();
|
uint64_t id = uint64_t(p_item->get_metadata(0));
|
||||||
if (!item) {
|
if (p_selected) {
|
||||||
return;
|
if (inspected_object_ids.size() == (int)EDITOR_GET("debugger/max_node_selection")) {
|
||||||
|
selection_surpassed_limit = true;
|
||||||
|
p_item->deselect(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inspected_object_ids.has(id)) {
|
||||||
|
inspected_object_ids.append(id);
|
||||||
|
}
|
||||||
|
} else if (inspected_object_ids.has(id)) {
|
||||||
|
inspected_object_ids.erase(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
inspected_object_id = uint64_t(item->get_metadata(0));
|
if (!notify_selection_queued) {
|
||||||
|
callable_mp(this, &EditorDebuggerTree::_notify_selection_changed).call_deferred();
|
||||||
|
notify_selection_queued = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emit_signal(SNAME("object_selected"), inspected_object_id, debugger_id);
|
void EditorDebuggerTree::_scene_tree_nothing_selected() {
|
||||||
|
deselect_all();
|
||||||
|
inspected_object_ids.clear();
|
||||||
|
emit_signal(SNAME("selection_cleared"), debugger_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorDebuggerTree::_notify_selection_changed() {
|
||||||
|
notify_selection_queued = false;
|
||||||
|
|
||||||
|
if (inspected_object_ids.is_empty()) {
|
||||||
|
emit_signal(SNAME("selection_cleared"), debugger_id);
|
||||||
|
} else {
|
||||||
|
emit_signal(SNAME("objects_selected"), inspected_object_ids.duplicate(), debugger_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selection_surpassed_limit) {
|
||||||
|
selection_surpassed_limit = false;
|
||||||
|
EditorToaster::get_singleton()->popup_str(vformat(TTR("Some remote nodes were not selected, as the configured maximum selection is %d. This can be changed at \"debugger/max_node_selection\" in the Editor Settings."), EDITOR_GET("debugger/max_node_selection")), EditorToaster::SEVERITY_WARNING);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerTree::_scene_tree_folded(Object *p_obj) {
|
void EditorDebuggerTree::_scene_tree_folded(Object *p_obj) {
|
||||||
|
|
@ -124,7 +163,7 @@ void EditorDebuggerTree::_scene_tree_rmb_selected(const Vector2 &p_position, Mou
|
||||||
item->select(0);
|
item->select(0);
|
||||||
|
|
||||||
item_menu->clear();
|
item_menu->clear();
|
||||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("CreateNewSceneFrom")), TTR("Save Branch as Scene"), ITEM_MENU_SAVE_REMOTE_NODE);
|
item_menu->add_icon_item(get_editor_theme_icon(SNAME("CreateNewSceneFrom")), TTR("Save Branch as Scene..."), ITEM_MENU_SAVE_REMOTE_NODE);
|
||||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("CopyNodePath")), TTR("Copy Node Path"), ITEM_MENU_COPY_NODE_PATH);
|
item_menu->add_icon_item(get_editor_theme_icon(SNAME("CopyNodePath")), TTR("Copy Node Path"), ITEM_MENU_COPY_NODE_PATH);
|
||||||
item_menu->add_icon_item(get_editor_theme_icon(SNAME("Collapse")), TTR("Expand/Collapse Branch"), ITEM_MENU_EXPAND_COLLAPSE);
|
item_menu->add_icon_item(get_editor_theme_icon(SNAME("Collapse")), TTR("Expand/Collapse Branch"), ITEM_MENU_EXPAND_COLLAPSE);
|
||||||
item_menu->set_position(get_screen_position() + get_local_mouse_position());
|
item_menu->set_position(get_screen_position() + get_local_mouse_position());
|
||||||
|
|
@ -152,12 +191,13 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
||||||
updating_scene_tree = true;
|
updating_scene_tree = true;
|
||||||
const String last_path = get_selected_path();
|
const String last_path = get_selected_path();
|
||||||
const String filter = SceneTreeDock::get_singleton()->get_filter();
|
const String filter = SceneTreeDock::get_singleton()->get_filter();
|
||||||
TreeItem *select_item = nullptr;
|
LocalVector<TreeItem *> select_items;
|
||||||
bool hide_filtered_out_parents = EDITOR_GET("docks/scene_tree/hide_filtered_out_parents");
|
bool hide_filtered_out_parents = EDITOR_GET("docks/scene_tree/hide_filtered_out_parents");
|
||||||
|
|
||||||
bool should_scroll = scrolling_to_item || filter != last_filter;
|
bool should_scroll = scrolling_to_item || filter != last_filter;
|
||||||
scrolling_to_item = false;
|
scrolling_to_item = false;
|
||||||
TreeItem *scroll_item = nullptr;
|
TreeItem *scroll_item = nullptr;
|
||||||
|
TypedArray<uint64_t> ids_present;
|
||||||
|
|
||||||
// Nodes are in a flatten list, depth first. Use a stack of parents, avoid recursion.
|
// Nodes are in a flatten list, depth first. Use a stack of parents, avoid recursion.
|
||||||
List<ParentItem> parents;
|
List<ParentItem> parents;
|
||||||
|
|
@ -216,9 +256,11 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
||||||
}
|
}
|
||||||
item->set_meta("node_path", current_path + "/" + item->get_text(0));
|
item->set_meta("node_path", current_path + "/" + item->get_text(0));
|
||||||
|
|
||||||
// Select previously selected node.
|
// Select previously selected nodes.
|
||||||
if (debugger_id == p_debugger) { // Can use remote id.
|
if (debugger_id == p_debugger) { // Can use remote id.
|
||||||
if (node.id == inspected_object_id) {
|
if (inspected_object_ids.has(uint64_t(node.id))) {
|
||||||
|
ids_present.append(node.id);
|
||||||
|
|
||||||
if (selection_uncollapse_all) {
|
if (selection_uncollapse_all) {
|
||||||
selection_uncollapse_all = false;
|
selection_uncollapse_all = false;
|
||||||
|
|
||||||
|
|
@ -228,14 +270,14 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
||||||
updating_scene_tree = true;
|
updating_scene_tree = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
select_item = item;
|
select_items.push_back(item);
|
||||||
if (should_scroll) {
|
if (should_scroll) {
|
||||||
scroll_item = item;
|
scroll_item = item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (last_path == (String)item->get_meta("node_path")) { // Must use path.
|
} else if (last_path == (String)item->get_meta("node_path")) { // Must use path.
|
||||||
updating_scene_tree = false; // Force emission of new selection.
|
updating_scene_tree = false; // Force emission of new selections.
|
||||||
select_item = item;
|
select_items.push_back(item);
|
||||||
if (should_scroll) {
|
if (should_scroll) {
|
||||||
scroll_item = item;
|
scroll_item = item;
|
||||||
}
|
}
|
||||||
|
|
@ -280,12 +322,12 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
||||||
break; // Filter matches, must survive.
|
break; // Filter matches, must survive.
|
||||||
}
|
}
|
||||||
|
|
||||||
parent->remove_child(item);
|
if (select_items.has(item) || scroll_item == item) {
|
||||||
memdelete(item);
|
select_items.resize(select_items.size() - 1);
|
||||||
if (select_item == item || scroll_item == item) {
|
|
||||||
select_item = nullptr;
|
|
||||||
scroll_item = nullptr;
|
scroll_item = nullptr;
|
||||||
}
|
}
|
||||||
|
parent->remove_child(item);
|
||||||
|
memdelete(item);
|
||||||
|
|
||||||
if (had_siblings) {
|
if (had_siblings) {
|
||||||
break; // Parent must survive.
|
break; // Parent must survive.
|
||||||
|
|
@ -316,18 +358,20 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
||||||
|
|
||||||
from->get_parent()->remove_child(from);
|
from->get_parent()->remove_child(from);
|
||||||
memdelete(from);
|
memdelete(from);
|
||||||
if (select_item == from || scroll_item == from) {
|
if (select_items.has(from) || scroll_item == from) {
|
||||||
select_item = nullptr;
|
select_items.erase(from);
|
||||||
scroll_item = nullptr;
|
scroll_item = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inspected_object_ids = ids_present;
|
||||||
|
|
||||||
debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree.
|
debugger_id = p_debugger; // Needed by hook, could be avoided if every debugger had its own tree.
|
||||||
|
|
||||||
if (select_item) {
|
for (TreeItem *item : select_items) {
|
||||||
select_item->select(0);
|
item->select(0);
|
||||||
}
|
}
|
||||||
if (scroll_item) {
|
if (scroll_item) {
|
||||||
scroll_to_item(scroll_item, false);
|
scroll_to_item(scroll_item, false);
|
||||||
|
|
@ -337,12 +381,22 @@ void EditorDebuggerTree::update_scene_tree(const SceneDebuggerTree *p_tree, int
|
||||||
updating_scene_tree = false;
|
updating_scene_tree = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerTree::select_node(ObjectID p_id) {
|
void EditorDebuggerTree::select_nodes(const TypedArray<int64_t> &p_ids) {
|
||||||
// Manually select, as the tree control may be out-of-date for some reason (e.g. not shown yet).
|
// Manually select, as the tree control may be out-of-date for some reason (e.g. not shown yet).
|
||||||
selection_uncollapse_all = true;
|
selection_uncollapse_all = true;
|
||||||
inspected_object_id = uint64_t(p_id);
|
inspected_object_ids = p_ids;
|
||||||
scrolling_to_item = true;
|
scrolling_to_item = true;
|
||||||
emit_signal(SNAME("object_selected"), inspected_object_id, debugger_id);
|
|
||||||
|
if (!updating_scene_tree) {
|
||||||
|
// Request a tree refresh.
|
||||||
|
EditorDebuggerNode::get_singleton()->request_remote_tree();
|
||||||
|
}
|
||||||
|
// Set the value immediately, so no update flooding happens and causes a crash.
|
||||||
|
updating_scene_tree = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void EditorDebuggerTree::clear_selection() {
|
||||||
|
inspected_object_ids.clear();
|
||||||
|
|
||||||
if (!updating_scene_tree) {
|
if (!updating_scene_tree) {
|
||||||
// Request a tree refresh.
|
// Request a tree refresh.
|
||||||
|
|
@ -453,8 +507,11 @@ void EditorDebuggerTree::_item_menu_id_pressed(int p_option) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EditorDebuggerTree::_file_selected(const String &p_file) {
|
void EditorDebuggerTree::_file_selected(const String &p_file) {
|
||||||
if (inspected_object_id.is_null()) {
|
if (inspected_object_ids.size() != 1) {
|
||||||
|
accept->set_text(vformat(TTR("Saving the branch as a scene requires selecting only one node, but you have selected %d nodes."), inspected_object_ids.size()));
|
||||||
|
accept->popup_centered();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
emit_signal(SNAME("save_node"), inspected_object_id, p_file, debugger_id);
|
|
||||||
|
emit_signal(SNAME("save_node"), inspected_object_ids[0], p_file, debugger_id);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@
|
||||||
|
|
||||||
#include "scene/gui/tree.h"
|
#include "scene/gui/tree.h"
|
||||||
|
|
||||||
|
class AcceptDialog;
|
||||||
class SceneDebuggerTree;
|
class SceneDebuggerTree;
|
||||||
class EditorFileDialog;
|
class EditorFileDialog;
|
||||||
|
|
||||||
|
|
@ -57,18 +58,23 @@ private:
|
||||||
ITEM_MENU_EXPAND_COLLAPSE,
|
ITEM_MENU_EXPAND_COLLAPSE,
|
||||||
};
|
};
|
||||||
|
|
||||||
ObjectID inspected_object_id;
|
TypedArray<uint64_t> inspected_object_ids;
|
||||||
int debugger_id = 0;
|
int debugger_id = 0;
|
||||||
bool updating_scene_tree = false;
|
bool updating_scene_tree = false;
|
||||||
bool scrolling_to_item = false;
|
bool scrolling_to_item = false;
|
||||||
|
bool notify_selection_queued = false;
|
||||||
|
bool selection_surpassed_limit = false;
|
||||||
bool selection_uncollapse_all = false;
|
bool selection_uncollapse_all = false;
|
||||||
HashSet<ObjectID> unfold_cache;
|
HashSet<ObjectID> unfold_cache;
|
||||||
PopupMenu *item_menu = nullptr;
|
PopupMenu *item_menu = nullptr;
|
||||||
EditorFileDialog *file_dialog = nullptr;
|
EditorFileDialog *file_dialog = nullptr;
|
||||||
|
AcceptDialog *accept = nullptr;
|
||||||
String last_filter;
|
String last_filter;
|
||||||
|
|
||||||
void _scene_tree_folded(Object *p_obj);
|
void _scene_tree_folded(Object *p_obj);
|
||||||
void _scene_tree_selected();
|
void _scene_tree_selection_changed(TreeItem *p_item, int p_column, bool p_selected);
|
||||||
|
void _scene_tree_nothing_selected();
|
||||||
|
void _notify_selection_changed();
|
||||||
void _scene_tree_rmb_selected(const Vector2 &p_position, MouseButton p_button);
|
void _scene_tree_rmb_selected(const Vector2 &p_position, MouseButton p_button);
|
||||||
void _item_menu_id_pressed(int p_option);
|
void _item_menu_id_pressed(int p_option);
|
||||||
void _file_selected(const String &p_file);
|
void _file_selected(const String &p_file);
|
||||||
|
|
@ -89,7 +95,10 @@ public:
|
||||||
String get_selected_path();
|
String get_selected_path();
|
||||||
ObjectID get_selected_object();
|
ObjectID get_selected_object();
|
||||||
int get_current_debugger(); // Would love to have one tree for every debugger.
|
int get_current_debugger(); // Would love to have one tree for every debugger.
|
||||||
|
inline TypedArray<uint64_t> get_selection() const { return inspected_object_ids.duplicate(); }
|
||||||
void update_scene_tree(const SceneDebuggerTree *p_tree, int p_debugger);
|
void update_scene_tree(const SceneDebuggerTree *p_tree, int p_debugger);
|
||||||
void select_node(ObjectID p_id);
|
void select_nodes(const TypedArray<int64_t> &p_ids);
|
||||||
|
void clear_selection();
|
||||||
|
|
||||||
EditorDebuggerTree();
|
EditorDebuggerTree();
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,8 @@
|
||||||
#include "core/config/project_settings.h"
|
#include "core/config/project_settings.h"
|
||||||
#include "core/debugger/debugger_marshalls.h"
|
#include "core/debugger/debugger_marshalls.h"
|
||||||
#include "core/debugger/remote_debugger.h"
|
#include "core/debugger/remote_debugger.h"
|
||||||
#include "core/io/marshalls.h"
|
|
||||||
#include "core/string/ustring.h"
|
#include "core/string/ustring.h"
|
||||||
#include "core/version.h"
|
#include "core/version.h"
|
||||||
#include "editor/debugger/debug_adapter/debug_adapter_protocol.h"
|
|
||||||
#include "editor/debugger/editor_expression_evaluator.h"
|
#include "editor/debugger/editor_expression_evaluator.h"
|
||||||
#include "editor/debugger/editor_performance_profiler.h"
|
#include "editor/debugger/editor_performance_profiler.h"
|
||||||
#include "editor/debugger/editor_profiler.h"
|
#include "editor/debugger/editor_profiler.h"
|
||||||
|
|
@ -48,6 +46,7 @@
|
||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
#include "editor/editor_string_names.h"
|
#include "editor/editor_string_names.h"
|
||||||
#include "editor/gui/editor_file_dialog.h"
|
#include "editor/gui/editor_file_dialog.h"
|
||||||
|
#include "editor/gui/editor_toaster.h"
|
||||||
#include "editor/inspector_dock.h"
|
#include "editor/inspector_dock.h"
|
||||||
#include "editor/plugins/canvas_item_editor_plugin.h"
|
#include "editor/plugins/canvas_item_editor_plugin.h"
|
||||||
#include "editor/plugins/editor_debugger_plugin.h"
|
#include "editor/plugins/editor_debugger_plugin.h"
|
||||||
|
|
@ -77,7 +76,8 @@ void ScriptEditorDebugger::_put_msg(const String &p_message, const Array &p_data
|
||||||
msg.push_back(p_message);
|
msg.push_back(p_message);
|
||||||
msg.push_back(p_thread_id);
|
msg.push_back(p_thread_id);
|
||||||
msg.push_back(p_data);
|
msg.push_back(p_data);
|
||||||
peer->put_message(msg);
|
Error err = peer->put_message(msg);
|
||||||
|
ERR_FAIL_COND_MSG(err != OK, vformat("Failed to send message %d", err));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -257,32 +257,44 @@ void ScriptEditorDebugger::request_remote_evaluate(const String &p_expression, i
|
||||||
_put_msg("evaluate", msg);
|
_put_msg("evaluate", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEditorDebugger::update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value) {
|
void ScriptEditorDebugger::update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value, const String &p_field) {
|
||||||
Array msg;
|
Array msg;
|
||||||
msg.push_back(p_obj_id);
|
msg.push_back(p_obj_id);
|
||||||
msg.push_back(p_prop);
|
msg.push_back(p_prop);
|
||||||
msg.push_back(p_value);
|
msg.push_back(p_value);
|
||||||
_put_msg("scene:set_object_property", msg);
|
if (p_field.is_empty()) {
|
||||||
|
_put_msg("scene:set_object_property", msg);
|
||||||
|
} else {
|
||||||
|
msg.push_back(p_field);
|
||||||
|
_put_msg("scene:set_object_property_field", msg);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEditorDebugger::request_remote_object(ObjectID p_obj_id) {
|
void ScriptEditorDebugger::request_remote_objects(const TypedArray<uint64_t> &p_obj_ids, bool p_update_selection) {
|
||||||
ERR_FAIL_COND(p_obj_id.is_null());
|
ERR_FAIL_COND(p_obj_ids.is_empty());
|
||||||
Array msg;
|
Array msg;
|
||||||
msg.push_back(p_obj_id);
|
msg.push_back(p_obj_ids.duplicate());
|
||||||
_put_msg("scene:inspect_object", msg);
|
msg.push_back(p_update_selection);
|
||||||
|
_put_msg("scene:inspect_objects", msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Object *ScriptEditorDebugger::get_remote_object(ObjectID p_id) {
|
void ScriptEditorDebugger::clear_inspector(bool p_send_msg) {
|
||||||
return inspector->get_object(p_id);
|
inspector->clear_remote_inspector();
|
||||||
|
if (p_send_msg) {
|
||||||
|
_put_msg("scene:clear_selection", Array());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEditorDebugger::_remote_object_selected(ObjectID p_id) {
|
void ScriptEditorDebugger::_remote_object_selected(ObjectID p_id) {
|
||||||
emit_signal(SNAME("remote_object_requested"), p_id);
|
emit_signal(SNAME("remote_object_requested"), p_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEditorDebugger::_remote_object_edited(ObjectID p_id, const String &p_prop, const Variant &p_value) {
|
void ScriptEditorDebugger::_remote_objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field) {
|
||||||
update_remote_object(p_id, p_prop, p_value);
|
const Array &ids = p_values.keys();
|
||||||
request_remote_object(p_id);
|
for (uint64_t id : ids) {
|
||||||
|
update_remote_object(ObjectID(id), p_prop, p_values[id], p_field);
|
||||||
|
}
|
||||||
|
request_remote_objects(p_values.keys(), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptEditorDebugger::_remote_object_property_updated(ObjectID p_id, const String &p_property) {
|
void ScriptEditorDebugger::_remote_object_property_updated(ObjectID p_id, const String &p_property) {
|
||||||
|
|
@ -405,10 +417,19 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread
|
||||||
scene_tree->deserialize(p_data);
|
scene_tree->deserialize(p_data);
|
||||||
emit_signal(SNAME("remote_tree_updated"));
|
emit_signal(SNAME("remote_tree_updated"));
|
||||||
_update_buttons_state();
|
_update_buttons_state();
|
||||||
} else if (p_msg == "scene:inspect_object") {
|
} else if (p_msg == "scene:inspect_objects") {
|
||||||
ObjectID id = inspector->add_object(p_data);
|
ERR_FAIL_COND(p_data.is_empty());
|
||||||
if (id.is_valid()) {
|
|
||||||
emit_signal(SNAME("remote_object_updated"), id);
|
TypedArray<uint64_t> ids;
|
||||||
|
for (const Array arr : p_data) {
|
||||||
|
ERR_FAIL_COND(arr.is_empty());
|
||||||
|
ERR_FAIL_COND(arr[0].get_type() != Variant::INT);
|
||||||
|
ids.append(arr[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (EditorDebuggerNode::get_singleton()->match_remote_selection(ids)) {
|
||||||
|
EditorDebuggerRemoteObjects *objs = inspector->set_objects(p_data);
|
||||||
|
emit_signal(SNAME("remote_objects_updated"), objs);
|
||||||
}
|
}
|
||||||
} else if (p_msg == "servers:memory_usage") {
|
} else if (p_msg == "servers:memory_usage") {
|
||||||
vmem_tree->clear();
|
vmem_tree->clear();
|
||||||
|
|
@ -809,10 +830,24 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread
|
||||||
} else if (p_msg == "request_quit") {
|
} else if (p_msg == "request_quit") {
|
||||||
emit_signal(SNAME("stop_requested"));
|
emit_signal(SNAME("stop_requested"));
|
||||||
_stop_and_notify();
|
_stop_and_notify();
|
||||||
} else if (p_msg == "remote_node_clicked") {
|
} else if (p_msg == "remote_nodes_clicked") {
|
||||||
if (!p_data.is_empty()) {
|
ERR_FAIL_COND(p_data.is_empty());
|
||||||
emit_signal(SNAME("remote_tree_select_requested"), p_data[0]);
|
EditorDebuggerRemoteObjects *objs = inspector->set_objects(p_data);
|
||||||
|
if (objs) {
|
||||||
|
EditorDebuggerNode::get_singleton()->stop_waiting_inspection();
|
||||||
|
|
||||||
|
emit_signal(SNAME("remote_objects_updated"), objs);
|
||||||
|
emit_signal(SNAME("remote_tree_select_requested"), objs->remote_object_ids.duplicate());
|
||||||
}
|
}
|
||||||
|
} else if (p_msg == "remote_nothing_clicked") {
|
||||||
|
EditorDebuggerNode::get_singleton()->stop_waiting_inspection();
|
||||||
|
|
||||||
|
emit_signal(SNAME("remote_tree_clear_selection_requested"));
|
||||||
|
} else if (p_msg == "remote_selection_invalidated") {
|
||||||
|
ERR_FAIL_COND(p_data.is_empty());
|
||||||
|
inspector->invalidate_selection_from_cache(p_data[0]);
|
||||||
|
} else if (p_msg == "show_selection_limit_warning") {
|
||||||
|
EditorToaster::get_singleton()->popup_str(vformat(TTR("Some remote nodes were not selected, as the configured maximum selection is %d. This can be changed at \"debugger/max_node_selection\" in the Editor Settings."), EDITOR_GET("debugger/max_node_selection")), EditorToaster::SEVERITY_WARNING);
|
||||||
} else if (p_msg == "performance:profile_names") {
|
} else if (p_msg == "performance:profile_names") {
|
||||||
Vector<StringName> monitors;
|
Vector<StringName> monitors;
|
||||||
monitors.resize(p_data.size());
|
monitors.resize(p_data.size());
|
||||||
|
|
@ -1772,8 +1807,7 @@ void ScriptEditorDebugger::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("live_debug_restore_node"), &ScriptEditorDebugger::live_debug_restore_node);
|
ClassDB::bind_method(D_METHOD("live_debug_restore_node"), &ScriptEditorDebugger::live_debug_restore_node);
|
||||||
ClassDB::bind_method(D_METHOD("live_debug_duplicate_node"), &ScriptEditorDebugger::live_debug_duplicate_node);
|
ClassDB::bind_method(D_METHOD("live_debug_duplicate_node"), &ScriptEditorDebugger::live_debug_duplicate_node);
|
||||||
ClassDB::bind_method(D_METHOD("live_debug_reparent_node"), &ScriptEditorDebugger::live_debug_reparent_node);
|
ClassDB::bind_method(D_METHOD("live_debug_reparent_node"), &ScriptEditorDebugger::live_debug_reparent_node);
|
||||||
ClassDB::bind_method(D_METHOD("request_remote_object", "id"), &ScriptEditorDebugger::request_remote_object);
|
ClassDB::bind_method(D_METHOD("update_remote_object", "id", "property", "value", "field"), &ScriptEditorDebugger::update_remote_object);
|
||||||
ClassDB::bind_method(D_METHOD("update_remote_object", "id", "property", "value"), &ScriptEditorDebugger::update_remote_object);
|
|
||||||
|
|
||||||
ADD_SIGNAL(MethodInfo("started"));
|
ADD_SIGNAL(MethodInfo("started"));
|
||||||
ADD_SIGNAL(MethodInfo("stopped"));
|
ADD_SIGNAL(MethodInfo("stopped"));
|
||||||
|
|
@ -1784,12 +1818,12 @@ void ScriptEditorDebugger::_bind_methods() {
|
||||||
ADD_SIGNAL(MethodInfo("set_execution", PropertyInfo("script"), PropertyInfo(Variant::INT, "line")));
|
ADD_SIGNAL(MethodInfo("set_execution", PropertyInfo("script"), PropertyInfo(Variant::INT, "line")));
|
||||||
ADD_SIGNAL(MethodInfo("clear_execution", PropertyInfo("script")));
|
ADD_SIGNAL(MethodInfo("clear_execution", PropertyInfo("script")));
|
||||||
ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "reallydid"), PropertyInfo(Variant::BOOL, "can_debug"), PropertyInfo(Variant::STRING, "reason"), PropertyInfo(Variant::BOOL, "has_stackdump")));
|
ADD_SIGNAL(MethodInfo("breaked", PropertyInfo(Variant::BOOL, "reallydid"), PropertyInfo(Variant::BOOL, "can_debug"), PropertyInfo(Variant::STRING, "reason"), PropertyInfo(Variant::BOOL, "has_stackdump")));
|
||||||
ADD_SIGNAL(MethodInfo("remote_object_requested", PropertyInfo(Variant::INT, "id")));
|
ADD_SIGNAL(MethodInfo("remote_objects_updated", PropertyInfo(Variant::OBJECT, "remote_objects")));
|
||||||
ADD_SIGNAL(MethodInfo("remote_object_updated", PropertyInfo(Variant::INT, "id")));
|
|
||||||
ADD_SIGNAL(MethodInfo("remote_object_property_updated", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property")));
|
ADD_SIGNAL(MethodInfo("remote_object_property_updated", PropertyInfo(Variant::INT, "id"), PropertyInfo(Variant::STRING, "property")));
|
||||||
ADD_SIGNAL(MethodInfo("remote_tree_updated"));
|
|
||||||
ADD_SIGNAL(MethodInfo("remote_tree_select_requested", PropertyInfo(Variant::NODE_PATH, "path")));
|
|
||||||
ADD_SIGNAL(MethodInfo("remote_window_title_changed", PropertyInfo(Variant::STRING, "title")));
|
ADD_SIGNAL(MethodInfo("remote_window_title_changed", PropertyInfo(Variant::STRING, "title")));
|
||||||
|
ADD_SIGNAL(MethodInfo("remote_tree_updated"));
|
||||||
|
ADD_SIGNAL(MethodInfo("remote_tree_select_requested", PropertyInfo(Variant::ARRAY, "ids")));
|
||||||
|
ADD_SIGNAL(MethodInfo("remote_tree_clear_selection_requested"));
|
||||||
ADD_SIGNAL(MethodInfo("output", PropertyInfo(Variant::STRING, "msg"), PropertyInfo(Variant::INT, "level")));
|
ADD_SIGNAL(MethodInfo("output", PropertyInfo(Variant::STRING, "msg"), PropertyInfo(Variant::INT, "level")));
|
||||||
ADD_SIGNAL(MethodInfo("stack_dump", PropertyInfo(Variant::ARRAY, "stack_dump")));
|
ADD_SIGNAL(MethodInfo("stack_dump", PropertyInfo(Variant::ARRAY, "stack_dump")));
|
||||||
ADD_SIGNAL(MethodInfo("stack_frame_vars", PropertyInfo(Variant::INT, "num_vars")));
|
ADD_SIGNAL(MethodInfo("stack_frame_vars", PropertyInfo(Variant::INT, "num_vars")));
|
||||||
|
|
@ -1955,7 +1989,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
|
||||||
inspector->set_property_name_style(EditorPropertyNameProcessor::STYLE_RAW);
|
inspector->set_property_name_style(EditorPropertyNameProcessor::STYLE_RAW);
|
||||||
inspector->set_read_only(true);
|
inspector->set_read_only(true);
|
||||||
inspector->connect("object_selected", callable_mp(this, &ScriptEditorDebugger::_remote_object_selected));
|
inspector->connect("object_selected", callable_mp(this, &ScriptEditorDebugger::_remote_object_selected));
|
||||||
inspector->connect("object_edited", callable_mp(this, &ScriptEditorDebugger::_remote_object_edited));
|
inspector->connect("objects_edited", callable_mp(this, &ScriptEditorDebugger::_remote_objects_edited));
|
||||||
inspector->connect("object_property_updated", callable_mp(this, &ScriptEditorDebugger::_remote_object_property_updated));
|
inspector->connect("object_property_updated", callable_mp(this, &ScriptEditorDebugger::_remote_object_property_updated));
|
||||||
inspector->register_text_enter(search);
|
inspector->register_text_enter(search);
|
||||||
inspector->set_use_filter(true);
|
inspector->set_use_filter(true);
|
||||||
|
|
@ -2169,9 +2203,7 @@ ScriptEditorDebugger::ScriptEditorDebugger() {
|
||||||
msgdialog = memnew(AcceptDialog);
|
msgdialog = memnew(AcceptDialog);
|
||||||
add_child(msgdialog);
|
add_child(msgdialog);
|
||||||
|
|
||||||
live_debug = true;
|
|
||||||
camera_override = CameraOverride::OVERRIDE_NONE;
|
camera_override = CameraOverride::OVERRIDE_NONE;
|
||||||
last_path_id = false;
|
|
||||||
error_count = 0;
|
error_count = 0;
|
||||||
warning_count = 0;
|
warning_count = 0;
|
||||||
_update_buttons_state();
|
_update_buttons_state();
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,6 @@
|
||||||
#include "core/os/os.h"
|
#include "core/os/os.h"
|
||||||
#include "editor/debugger/editor_debugger_inspector.h"
|
#include "editor/debugger/editor_debugger_inspector.h"
|
||||||
#include "editor/debugger/editor_debugger_node.h"
|
#include "editor/debugger/editor_debugger_node.h"
|
||||||
#include "editor/debugger/editor_debugger_server.h"
|
|
||||||
#include "scene/gui/button.h"
|
#include "scene/gui/button.h"
|
||||||
#include "scene/gui/margin_container.h"
|
#include "scene/gui/margin_container.h"
|
||||||
|
|
||||||
|
|
@ -146,7 +145,7 @@ private:
|
||||||
Ref<RemoteDebuggerPeer> peer;
|
Ref<RemoteDebuggerPeer> peer;
|
||||||
|
|
||||||
HashMap<NodePath, int> node_path_cache;
|
HashMap<NodePath, int> node_path_cache;
|
||||||
int last_path_id;
|
int last_path_id = 0;
|
||||||
HashMap<String, int> res_path_cache;
|
HashMap<String, int> res_path_cache;
|
||||||
|
|
||||||
EditorProfiler *profiler = nullptr;
|
EditorProfiler *profiler = nullptr;
|
||||||
|
|
@ -158,7 +157,7 @@ private:
|
||||||
bool move_to_foreground = true;
|
bool move_to_foreground = true;
|
||||||
bool can_request_idle_draw = false;
|
bool can_request_idle_draw = false;
|
||||||
|
|
||||||
bool live_debug;
|
bool live_debug = true;
|
||||||
|
|
||||||
uint64_t debugging_thread_id = Thread::UNASSIGNED_ID;
|
uint64_t debugging_thread_id = Thread::UNASSIGNED_ID;
|
||||||
|
|
||||||
|
|
@ -191,7 +190,7 @@ private:
|
||||||
void _set_reason_text(const String &p_reason, MessageType p_type);
|
void _set_reason_text(const String &p_reason, MessageType p_type);
|
||||||
void _update_buttons_state();
|
void _update_buttons_state();
|
||||||
void _remote_object_selected(ObjectID p_object);
|
void _remote_object_selected(ObjectID p_object);
|
||||||
void _remote_object_edited(ObjectID, const String &p_prop, const Variant &p_value);
|
void _remote_objects_edited(const String &p_prop, const TypedDictionary<uint64_t, Variant> &p_values, const String &p_field);
|
||||||
void _remote_object_property_updated(ObjectID p_id, const String &p_property);
|
void _remote_object_property_updated(ObjectID p_id, const String &p_property);
|
||||||
|
|
||||||
void _video_mem_request();
|
void _video_mem_request();
|
||||||
|
|
@ -245,9 +244,10 @@ protected:
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void request_remote_object(ObjectID p_obj_id);
|
void request_remote_objects(const TypedArray<uint64_t> &p_obj_ids, bool p_update_selection = true);
|
||||||
void update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value);
|
void update_remote_object(ObjectID p_obj_id, const String &p_prop, const Variant &p_value, const String &p_field = "");
|
||||||
Object *get_remote_object(ObjectID p_id);
|
|
||||||
|
void clear_inspector(bool p_send_msg = true);
|
||||||
|
|
||||||
// Needed by _live_edit_set, buttons state.
|
// Needed by _live_edit_set, buttons state.
|
||||||
void set_editor_remote_tree(const Tree *p_tree) { editor_remote_tree = p_tree; }
|
void set_editor_remote_tree(const Tree *p_tree) { editor_remote_tree = p_tree; }
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include "core/os/keyboard.h"
|
#include "core/os/keyboard.h"
|
||||||
#include "editor/add_metadata_dialog.h"
|
#include "editor/add_metadata_dialog.h"
|
||||||
|
#include "editor/debugger/editor_debugger_inspector.h"
|
||||||
#include "editor/doc_tools.h"
|
#include "editor/doc_tools.h"
|
||||||
#include "editor/editor_feature_profile.h"
|
#include "editor/editor_feature_profile.h"
|
||||||
#include "editor/editor_main_screen.h"
|
#include "editor/editor_main_screen.h"
|
||||||
|
|
@ -4282,6 +4283,10 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
|
||||||
Object::cast_to<MultiNodeEdit>(object)->set_property_field(p_name, p_value, p_changed_field);
|
Object::cast_to<MultiNodeEdit>(object)->set_property_field(p_name, p_value, p_changed_field);
|
||||||
_edit_request_change(object, p_name);
|
_edit_request_change(object, p_name);
|
||||||
emit_signal(_prop_edited, p_name);
|
emit_signal(_prop_edited, p_name);
|
||||||
|
} else if (Object::cast_to<EditorDebuggerRemoteObjects>(object)) {
|
||||||
|
Object::cast_to<EditorDebuggerRemoteObjects>(object)->set_property_field(p_name, p_value, p_changed_field);
|
||||||
|
_edit_request_change(object, p_name);
|
||||||
|
emit_signal(_prop_edited, p_name);
|
||||||
} else {
|
} else {
|
||||||
undo_redo->create_action(vformat(TTR("Set %s"), p_name), UndoRedo::MERGE_ENDS);
|
undo_redo->create_action(vformat(TTR("Set %s"), p_name), UndoRedo::MERGE_ENDS);
|
||||||
undo_redo->add_do_property(object, p_name, p_value);
|
undo_redo->add_do_property(object, p_name, p_value);
|
||||||
|
|
|
||||||
|
|
@ -2546,12 +2546,13 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
|
||||||
InspectorDock::get_inspector_singleton()->edit(nullptr);
|
InspectorDock::get_inspector_singleton()->edit(nullptr);
|
||||||
NodeDock::get_singleton()->set_node(nullptr);
|
NodeDock::get_singleton()->set_node(nullptr);
|
||||||
InspectorDock::get_singleton()->update(nullptr);
|
InspectorDock::get_singleton()->update(nullptr);
|
||||||
|
EditorDebuggerNode::get_singleton()->clear_remote_tree_selection();
|
||||||
hide_unused_editors();
|
hide_unused_editors();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the use folding setting and state.
|
// Update the use folding setting and state.
|
||||||
bool disable_folding = bool(EDITOR_GET("interface/inspector/disable_folding")) || current_obj->is_class("EditorDebuggerRemoteObject");
|
bool disable_folding = bool(EDITOR_GET("interface/inspector/disable_folding")) || current_obj->is_class("EditorDebuggerRemoteObjects");
|
||||||
if (InspectorDock::get_inspector_singleton()->is_using_folding() == disable_folding) {
|
if (InspectorDock::get_inspector_singleton()->is_using_folding() == disable_folding) {
|
||||||
InspectorDock::get_inspector_singleton()->set_use_folding(!disable_folding, false);
|
InspectorDock::get_inspector_singleton()->set_use_folding(!disable_folding, false);
|
||||||
}
|
}
|
||||||
|
|
@ -2579,6 +2580,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
|
||||||
SceneTreeDock::get_singleton()->set_selected(nullptr);
|
SceneTreeDock::get_singleton()->set_selected(nullptr);
|
||||||
NodeDock::get_singleton()->set_node(nullptr);
|
NodeDock::get_singleton()->set_node(nullptr);
|
||||||
InspectorDock::get_singleton()->update(nullptr);
|
InspectorDock::get_singleton()->update(nullptr);
|
||||||
|
EditorDebuggerNode::get_singleton()->clear_remote_tree_selection();
|
||||||
ImportDock::get_singleton()->set_edit_path(current_res->get_path());
|
ImportDock::get_singleton()->set_edit_path(current_res->get_path());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2618,6 +2620,7 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
|
||||||
SceneTreeDock::get_singleton()->set_selected(nullptr);
|
SceneTreeDock::get_singleton()->set_selected(nullptr);
|
||||||
InspectorDock::get_singleton()->update(nullptr);
|
InspectorDock::get_singleton()->update(nullptr);
|
||||||
}
|
}
|
||||||
|
EditorDebuggerNode::get_singleton()->clear_remote_tree_selection();
|
||||||
|
|
||||||
if (get_edited_scene() && !get_edited_scene()->get_scene_file_path().is_empty()) {
|
if (get_edited_scene() && !get_edited_scene()->get_scene_file_path().is_empty()) {
|
||||||
String source_scene = get_edited_scene()->get_scene_file_path();
|
String source_scene = get_edited_scene()->get_scene_file_path();
|
||||||
|
|
@ -2626,7 +2629,6 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
|
||||||
info_is_warning = true;
|
info_is_warning = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
Node *selected_node = nullptr;
|
Node *selected_node = nullptr;
|
||||||
|
|
||||||
|
|
@ -2652,6 +2654,10 @@ void EditorNode::_edit_current(bool p_skip_foreign, bool p_skip_inspector_update
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!current_obj->is_class("EditorDebuggerRemoteObjects")) {
|
||||||
|
EditorDebuggerNode::get_singleton()->clear_remote_tree_selection();
|
||||||
|
}
|
||||||
|
|
||||||
InspectorDock::get_inspector_singleton()->edit(current_obj);
|
InspectorDock::get_inspector_singleton()->edit(current_obj);
|
||||||
NodeDock::get_singleton()->set_node(nullptr);
|
NodeDock::get_singleton()->set_node(nullptr);
|
||||||
SceneTreeDock::get_singleton()->set_selected(selected_node);
|
SceneTreeDock::get_singleton()->set_selected(selected_node);
|
||||||
|
|
@ -4945,7 +4951,8 @@ Ref<Texture2D> EditorNode::get_object_icon(const Object *p_object, const String
|
||||||
|
|
||||||
Ref<Script> scr = p_object->get_script();
|
Ref<Script> scr = p_object->get_script();
|
||||||
|
|
||||||
if (Object::cast_to<EditorDebuggerRemoteObject>(p_object)) {
|
const EditorDebuggerRemoteObjects *robjs = Object::cast_to<EditorDebuggerRemoteObjects>(p_object);
|
||||||
|
if (robjs) {
|
||||||
String class_name;
|
String class_name;
|
||||||
if (scr.is_valid()) {
|
if (scr.is_valid()) {
|
||||||
class_name = scr->get_global_name();
|
class_name = scr->get_global_name();
|
||||||
|
|
@ -4955,7 +4962,12 @@ Ref<Texture2D> EditorNode::get_object_icon(const Object *p_object, const String
|
||||||
class_name = scr->get_path();
|
class_name = scr->get_path();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return get_class_icon(class_name.is_empty() ? Object::cast_to<EditorDebuggerRemoteObject>(p_object)->type_name : class_name, p_fallback);
|
|
||||||
|
if (class_name.is_empty()) {
|
||||||
|
return get_class_icon(robjs->type_name, p_fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
return get_class_icon(class_name, p_fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scr.is_null() && p_object->is_class("Script")) {
|
if (scr.is_null() && p_object->is_class("Script")) {
|
||||||
|
|
|
||||||
|
|
@ -1007,6 +1007,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
|
||||||
|
|
||||||
EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/auto_switch_to_remote_scene_tree", false, "")
|
EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/auto_switch_to_remote_scene_tree", false, "")
|
||||||
EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/auto_switch_to_stack_trace", true, "")
|
EDITOR_SETTING_BASIC(Variant::BOOL, PROPERTY_HINT_NONE, "debugger/auto_switch_to_stack_trace", true, "")
|
||||||
|
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/max_node_selection", 20, "1,100,1")
|
||||||
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_history_size", 3600, "60,10000,1")
|
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_history_size", 3600, "60,10000,1")
|
||||||
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_max_functions", 64, "16,512,1")
|
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_frame_max_functions", 64, "16,512,1")
|
||||||
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_target_fps", 60, "1,1000,1")
|
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "debugger/profiler_target_fps", 60, "1,1000,1")
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ UndoRedo *EditorUndoRedoManager::get_history_undo_redo(int p_idx) const {
|
||||||
int EditorUndoRedoManager::get_history_id_for_object(Object *p_object) const {
|
int EditorUndoRedoManager::get_history_id_for_object(Object *p_object) const {
|
||||||
int history_id = INVALID_HISTORY;
|
int history_id = INVALID_HISTORY;
|
||||||
|
|
||||||
if (Object::cast_to<EditorDebuggerRemoteObject>(p_object)) {
|
if (Object::cast_to<EditorDebuggerRemoteObjects>(p_object)) {
|
||||||
return REMOTE_HISTORY;
|
return REMOTE_HISTORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -128,7 +128,6 @@ void EditorObjectSelector::update_path() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ref<Texture2D> obj_icon = EditorNode::get_singleton()->get_object_icon(obj);
|
Ref<Texture2D> obj_icon = EditorNode::get_singleton()->get_object_icon(obj);
|
||||||
|
|
||||||
if (obj_icon.is_valid()) {
|
if (obj_icon.is_valid()) {
|
||||||
current_object_icon->set_texture(obj_icon);
|
current_object_icon->set_texture(obj_icon);
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +147,7 @@ void EditorObjectSelector::update_path() {
|
||||||
if (name.is_empty()) {
|
if (name.is_empty()) {
|
||||||
name = r->get_class();
|
name = r->get_class();
|
||||||
}
|
}
|
||||||
} else if (obj->is_class("EditorDebuggerRemoteObject")) {
|
} else if (obj->is_class("EditorDebuggerRemoteObjects")) {
|
||||||
name = obj->call("get_title");
|
name = obj->call("get_title");
|
||||||
} else if (Object::cast_to<Node>(obj)) {
|
} else if (Object::cast_to<Node>(obj)) {
|
||||||
name = Object::cast_to<Node>(obj)->get_name();
|
name = Object::cast_to<Node>(obj)->get_name();
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@
|
||||||
|
|
||||||
#include "inspector_dock.h"
|
#include "inspector_dock.h"
|
||||||
|
|
||||||
|
#include "editor/debugger/editor_debugger_inspector.h"
|
||||||
|
#include "editor/debugger/editor_debugger_node.h"
|
||||||
#include "editor/editor_main_screen.h"
|
#include "editor/editor_main_screen.h"
|
||||||
#include "editor/editor_node.h"
|
#include "editor/editor_node.h"
|
||||||
#include "editor/editor_settings.h"
|
#include "editor/editor_settings.h"
|
||||||
|
|
@ -351,7 +353,7 @@ void InspectorDock::_prepare_history() {
|
||||||
}
|
}
|
||||||
} else if (Object::cast_to<Node>(obj)) {
|
} else if (Object::cast_to<Node>(obj)) {
|
||||||
text = Object::cast_to<Node>(obj)->get_name();
|
text = Object::cast_to<Node>(obj)->get_name();
|
||||||
} else if (obj->is_class("EditorDebuggerRemoteObject")) {
|
} else if (obj->is_class("EditorDebuggerRemoteObjects")) {
|
||||||
text = obj->call("get_title");
|
text = obj->call("get_title");
|
||||||
} else {
|
} else {
|
||||||
text = obj->get_class();
|
text = obj->get_class();
|
||||||
|
|
@ -372,6 +374,10 @@ void InspectorDock::_select_history(int p_idx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EditorNode::get_singleton()->push_item(obj);
|
EditorNode::get_singleton()->push_item(obj);
|
||||||
|
|
||||||
|
if (const EditorDebuggerRemoteObjects *robjs = Object::cast_to<EditorDebuggerRemoteObjects>(obj)) {
|
||||||
|
EditorDebuggerNode::get_singleton()->set_remote_selection(robjs->remote_object_ids.duplicate());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InspectorDock::_resource_created() {
|
void InspectorDock::_resource_created() {
|
||||||
|
|
@ -396,6 +402,10 @@ void InspectorDock::_resource_selected(const Ref<Resource> &p_res, const String
|
||||||
void InspectorDock::_edit_forward() {
|
void InspectorDock::_edit_forward() {
|
||||||
if (EditorNode::get_singleton()->get_editor_selection_history()->next()) {
|
if (EditorNode::get_singleton()->get_editor_selection_history()->next()) {
|
||||||
EditorNode::get_singleton()->edit_current();
|
EditorNode::get_singleton()->edit_current();
|
||||||
|
|
||||||
|
if (const EditorDebuggerRemoteObjects *robjs = Object::cast_to<EditorDebuggerRemoteObjects>(current)) {
|
||||||
|
EditorDebuggerNode::get_singleton()->set_remote_selection(robjs->remote_object_ids.duplicate());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -403,6 +413,10 @@ void InspectorDock::_edit_back() {
|
||||||
EditorSelectionHistory *editor_history = EditorNode::get_singleton()->get_editor_selection_history();
|
EditorSelectionHistory *editor_history = EditorNode::get_singleton()->get_editor_selection_history();
|
||||||
if ((current && editor_history->previous()) || editor_history->get_path_size() == 1) {
|
if ((current && editor_history->previous()) || editor_history->get_path_size() == 1) {
|
||||||
EditorNode::get_singleton()->edit_current();
|
EditorNode::get_singleton()->edit_current();
|
||||||
|
|
||||||
|
if (const EditorDebuggerRemoteObjects *robjs = Object::cast_to<EditorDebuggerRemoteObjects>(current)) {
|
||||||
|
EditorDebuggerNode::get_singleton()->set_remote_selection(robjs->remote_object_ids.duplicate());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,6 @@
|
||||||
#include "core/string/translation_server.h"
|
#include "core/string/translation_server.h"
|
||||||
#include "editor/debugger/editor_debugger_node.h"
|
#include "editor/debugger/editor_debugger_node.h"
|
||||||
#include "editor/debugger/script_editor_debugger.h"
|
#include "editor/debugger/script_editor_debugger.h"
|
||||||
#include "editor/editor_command_palette.h"
|
|
||||||
#include "editor/editor_feature_profile.h"
|
#include "editor/editor_feature_profile.h"
|
||||||
#include "editor/editor_interface.h"
|
#include "editor/editor_interface.h"
|
||||||
#include "editor/editor_main_screen.h"
|
#include "editor/editor_main_screen.h"
|
||||||
|
|
@ -58,13 +57,16 @@ void GameViewDebugger::_session_started(Ref<EditorDebuggerSession> p_session) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Array setup_data;
|
|
||||||
Dictionary settings;
|
Dictionary settings;
|
||||||
|
settings["debugger/max_node_selection"] = EDITOR_GET("debugger/max_node_selection");
|
||||||
settings["editors/panning/2d_editor_panning_scheme"] = EDITOR_GET("editors/panning/2d_editor_panning_scheme");
|
settings["editors/panning/2d_editor_panning_scheme"] = EDITOR_GET("editors/panning/2d_editor_panning_scheme");
|
||||||
settings["editors/panning/simple_panning"] = EDITOR_GET("editors/panning/simple_panning");
|
settings["editors/panning/simple_panning"] = EDITOR_GET("editors/panning/simple_panning");
|
||||||
settings["editors/panning/warped_mouse_panning"] = EDITOR_GET("editors/panning/warped_mouse_panning");
|
settings["editors/panning/warped_mouse_panning"] = EDITOR_GET("editors/panning/warped_mouse_panning");
|
||||||
settings["editors/panning/2d_editor_pan_speed"] = EDITOR_GET("editors/panning/2d_editor_pan_speed");
|
settings["editors/panning/2d_editor_pan_speed"] = EDITOR_GET("editors/panning/2d_editor_pan_speed");
|
||||||
|
settings["editors/polygon_editor/point_grab_radius"] = EDITOR_GET("editors/polygon_editor/point_grab_radius");
|
||||||
settings["canvas_item_editor/pan_view"] = DebuggerMarshalls::serialize_key_shortcut(ED_GET_SHORTCUT("canvas_item_editor/pan_view"));
|
settings["canvas_item_editor/pan_view"] = DebuggerMarshalls::serialize_key_shortcut(ED_GET_SHORTCUT("canvas_item_editor/pan_view"));
|
||||||
|
settings["box_selection_fill_color"] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("box_selection_fill_color"), EditorStringName(Editor));
|
||||||
|
settings["box_selection_stroke_color"] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("box_selection_stroke_color"), EditorStringName(Editor));
|
||||||
#ifndef _3D_DISABLED
|
#ifndef _3D_DISABLED
|
||||||
settings["editors/3d/default_fov"] = EDITOR_GET("editors/3d/default_fov");
|
settings["editors/3d/default_fov"] = EDITOR_GET("editors/3d/default_fov");
|
||||||
settings["editors/3d/default_z_near"] = EDITOR_GET("editors/3d/default_z_near");
|
settings["editors/3d/default_z_near"] = EDITOR_GET("editors/3d/default_z_near");
|
||||||
|
|
@ -76,7 +78,11 @@ void GameViewDebugger::_session_started(Ref<EditorDebuggerSession> p_session) {
|
||||||
settings["editors/3d/freelook/freelook_sensitivity"] = EDITOR_GET("editors/3d/freelook/freelook_sensitivity");
|
settings["editors/3d/freelook/freelook_sensitivity"] = EDITOR_GET("editors/3d/freelook/freelook_sensitivity");
|
||||||
settings["editors/3d/navigation_feel/orbit_sensitivity"] = EDITOR_GET("editors/3d/navigation_feel/orbit_sensitivity");
|
settings["editors/3d/navigation_feel/orbit_sensitivity"] = EDITOR_GET("editors/3d/navigation_feel/orbit_sensitivity");
|
||||||
settings["editors/3d/navigation_feel/translation_sensitivity"] = EDITOR_GET("editors/3d/navigation_feel/translation_sensitivity");
|
settings["editors/3d/navigation_feel/translation_sensitivity"] = EDITOR_GET("editors/3d/navigation_feel/translation_sensitivity");
|
||||||
|
settings["editors/3d/selection_box_color"] = EDITOR_GET("editors/3d/selection_box_color");
|
||||||
|
settings["editors/3d/freelook/freelook_base_speed"] = EDITOR_GET("editors/3d/freelook/freelook_base_speed");
|
||||||
#endif // _3D_DISABLED
|
#endif // _3D_DISABLED
|
||||||
|
|
||||||
|
Array setup_data;
|
||||||
setup_data.append(settings);
|
setup_data.append(settings);
|
||||||
p_session->send_message("scene:runtime_node_select_setup", setup_data);
|
p_session->send_message("scene:runtime_node_select_setup", setup_data);
|
||||||
|
|
||||||
|
|
@ -422,6 +428,8 @@ void GameView::_select_mode_pressed(int p_option) {
|
||||||
}
|
}
|
||||||
|
|
||||||
debugger->set_select_mode(mode);
|
debugger->set_select_mode(mode);
|
||||||
|
|
||||||
|
EditorSettings::get_singleton()->set_project_metadata("game_view", "select_mode", mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameView::_embed_options_menu_menu_id_pressed(int p_id) {
|
void GameView::_embed_options_menu_menu_id_pressed(int p_id) {
|
||||||
|
|
@ -581,6 +589,8 @@ void GameView::_hide_selection_toggled(bool p_pressed) {
|
||||||
hide_selection->set_button_icon(get_editor_theme_icon(p_pressed ? SNAME("GuiVisibilityHidden") : SNAME("GuiVisibilityVisible")));
|
hide_selection->set_button_icon(get_editor_theme_icon(p_pressed ? SNAME("GuiVisibilityHidden") : SNAME("GuiVisibilityVisible")));
|
||||||
|
|
||||||
debugger->set_selection_visible(!p_pressed);
|
debugger->set_selection_visible(!p_pressed);
|
||||||
|
|
||||||
|
EditorSettings::get_singleton()->set_project_metadata("game_view", "hide_selection", p_pressed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameView::_camera_override_button_toggled(bool p_pressed) {
|
void GameView::_camera_override_button_toggled(bool p_pressed) {
|
||||||
|
|
@ -609,12 +619,16 @@ void GameView::_camera_override_menu_id_pressed(int p_id) {
|
||||||
menu->set_item_checked(menu->get_item_index(p_id), true);
|
menu->set_item_checked(menu->get_item_index(p_id), true);
|
||||||
|
|
||||||
_update_debugger_buttons();
|
_update_debugger_buttons();
|
||||||
|
|
||||||
|
EditorSettings::get_singleton()->set_project_metadata("game_view", "camera_override_mode", p_id);
|
||||||
} break;
|
} break;
|
||||||
case CAMERA_MODE_EDITORS: {
|
case CAMERA_MODE_EDITORS: {
|
||||||
debugger->set_camera_manipulate_mode(EditorDebuggerNode::OVERRIDE_EDITORS);
|
debugger->set_camera_manipulate_mode(EditorDebuggerNode::OVERRIDE_EDITORS);
|
||||||
menu->set_item_checked(menu->get_item_index(p_id), true);
|
menu->set_item_checked(menu->get_item_index(p_id), true);
|
||||||
|
|
||||||
_update_debugger_buttons();
|
_update_debugger_buttons();
|
||||||
|
|
||||||
|
EditorSettings::get_singleton()->set_project_metadata("game_view", "camera_override_mode", p_id);
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -700,41 +714,6 @@ void GameView::set_is_feature_enabled(bool p_enabled) {
|
||||||
is_feature_enabled = p_enabled;
|
is_feature_enabled = p_enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameView::set_state(const Dictionary &p_state) {
|
|
||||||
if (p_state.has("hide_selection")) {
|
|
||||||
hide_selection->set_pressed(p_state["hide_selection"]);
|
|
||||||
_hide_selection_toggled(hide_selection->is_pressed());
|
|
||||||
}
|
|
||||||
if (p_state.has("select_mode")) {
|
|
||||||
_select_mode_pressed(p_state["select_mode"]);
|
|
||||||
}
|
|
||||||
if (p_state.has("camera_override_mode")) {
|
|
||||||
_camera_override_menu_id_pressed(p_state["camera_override_mode"]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary GameView::get_state() const {
|
|
||||||
Dictionary d;
|
|
||||||
d["hide_selection"] = hide_selection->is_pressed();
|
|
||||||
|
|
||||||
for (int i = 0; i < RuntimeNodeSelect::SELECT_MODE_MAX; i++) {
|
|
||||||
if (select_mode_button[i]->is_pressed()) {
|
|
||||||
d["select_mode"] = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PopupMenu *menu = camera_override_menu->get_popup();
|
|
||||||
for (int i = CAMERA_MODE_INGAME; i < CAMERA_MODE_EDITORS + 1; i++) {
|
|
||||||
if (menu->is_item_checked(menu->get_item_index(i))) {
|
|
||||||
d["camera_override_mode"] = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameView::set_window_layout(Ref<ConfigFile> p_layout) {
|
void GameView::set_window_layout(Ref<ConfigFile> p_layout) {
|
||||||
floating_window_rect = p_layout->get_value("GameView", "floating_window_rect", Rect2i());
|
floating_window_rect = p_layout->get_value("GameView", "floating_window_rect", Rect2i());
|
||||||
floating_window_screen = p_layout->get_value("GameView", "floating_window_screen", -1);
|
floating_window_screen = p_layout->get_value("GameView", "floating_window_screen", -1);
|
||||||
|
|
@ -959,6 +938,7 @@ GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
|
||||||
hide_selection->set_theme_type_variation(SceneStringName(FlatButton));
|
hide_selection->set_theme_type_variation(SceneStringName(FlatButton));
|
||||||
hide_selection->connect(SceneStringName(toggled), callable_mp(this, &GameView::_hide_selection_toggled));
|
hide_selection->connect(SceneStringName(toggled), callable_mp(this, &GameView::_hide_selection_toggled));
|
||||||
hide_selection->set_tooltip_text(TTR("Toggle Selection Visibility"));
|
hide_selection->set_tooltip_text(TTR("Toggle Selection Visibility"));
|
||||||
|
hide_selection->set_pressed(EditorSettings::get_singleton()->get_project_metadata("game_view", "hide_selection", false));
|
||||||
|
|
||||||
main_menu_hbox->add_child(memnew(VSeparator));
|
main_menu_hbox->add_child(memnew(VSeparator));
|
||||||
|
|
||||||
|
|
@ -979,14 +959,16 @@ GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
|
||||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_select_mode_pressed).bind(RuntimeNodeSelect::SELECT_MODE_LIST));
|
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->connect(SceneStringName(pressed), callable_mp(this, &GameView::_select_mode_pressed).bind(RuntimeNodeSelect::SELECT_MODE_LIST));
|
||||||
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_tooltip_text(TTR("Show list of selectable nodes at position clicked."));
|
select_mode_button[RuntimeNodeSelect::SELECT_MODE_LIST]->set_tooltip_text(TTR("Show list of selectable nodes at position clicked."));
|
||||||
|
|
||||||
|
_select_mode_pressed(EditorSettings::get_singleton()->get_project_metadata("game_view", "select_mode", 0));
|
||||||
|
|
||||||
main_menu_hbox->add_child(memnew(VSeparator));
|
main_menu_hbox->add_child(memnew(VSeparator));
|
||||||
|
|
||||||
camera_override_button = memnew(Button);
|
camera_override_button = memnew(Button);
|
||||||
main_menu_hbox->add_child(camera_override_button);
|
main_menu_hbox->add_child(camera_override_button);
|
||||||
camera_override_button->set_toggle_mode(true);
|
camera_override_button->set_toggle_mode(true);
|
||||||
camera_override_button->set_theme_type_variation(SceneStringName(FlatButton));
|
camera_override_button->set_theme_type_variation(SceneStringName(FlatButton));
|
||||||
camera_override_button->connect(SceneStringName(toggled), callable_mp(this, &GameView::_camera_override_button_toggled));
|
|
||||||
camera_override_button->set_tooltip_text(TTR("Override the in-game camera."));
|
camera_override_button->set_tooltip_text(TTR("Override the in-game camera."));
|
||||||
|
camera_override_button->connect(SceneStringName(toggled), callable_mp(this, &GameView::_camera_override_button_toggled));
|
||||||
|
|
||||||
camera_override_menu = memnew(MenuButton);
|
camera_override_menu = memnew(MenuButton);
|
||||||
main_menu_hbox->add_child(camera_override_menu);
|
main_menu_hbox->add_child(camera_override_menu);
|
||||||
|
|
@ -994,6 +976,7 @@ GameView::GameView(Ref<GameViewDebugger> p_debugger, WindowWrapper *p_wrapper) {
|
||||||
camera_override_menu->set_theme_type_variation("FlatMenuButton");
|
camera_override_menu->set_theme_type_variation("FlatMenuButton");
|
||||||
camera_override_menu->set_h_size_flags(SIZE_SHRINK_END);
|
camera_override_menu->set_h_size_flags(SIZE_SHRINK_END);
|
||||||
camera_override_menu->set_tooltip_text(TTR("Camera Override Options"));
|
camera_override_menu->set_tooltip_text(TTR("Camera Override Options"));
|
||||||
|
_camera_override_menu_id_pressed(EditorSettings::get_singleton()->get_project_metadata("game_view", "camera_override_mode", 0));
|
||||||
|
|
||||||
PopupMenu *menu = camera_override_menu->get_popup();
|
PopupMenu *menu = camera_override_menu->get_popup();
|
||||||
menu->connect(SceneStringName(id_pressed), callable_mp(this, &GameView::_camera_override_menu_id_pressed));
|
menu->connect(SceneStringName(id_pressed), callable_mp(this, &GameView::_camera_override_menu_id_pressed));
|
||||||
|
|
@ -1098,7 +1081,7 @@ void GameViewPlugin::selected_notify() {
|
||||||
notify_main_screen_changed(get_plugin_name());
|
notify_main_screen_changed(get_plugin_name());
|
||||||
#else
|
#else
|
||||||
window_wrapper->grab_window_focus();
|
window_wrapper->grab_window_focus();
|
||||||
#endif
|
#endif // ANDROID_ENABLED
|
||||||
_focus_another_editor();
|
_focus_another_editor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1119,19 +1102,7 @@ void GameViewPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
|
||||||
void GameViewPlugin::get_window_layout(Ref<ConfigFile> p_layout) {
|
void GameViewPlugin::get_window_layout(Ref<ConfigFile> p_layout) {
|
||||||
game_view->get_window_layout(p_layout);
|
game_view->get_window_layout(p_layout);
|
||||||
}
|
}
|
||||||
|
#endif // ANDROID_ENABLED
|
||||||
void GameViewPlugin::set_state(const Dictionary &p_state) {
|
|
||||||
game_view->set_state(p_state);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dictionary GameViewPlugin::get_state() const {
|
|
||||||
return game_view->get_state();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GameViewPlugin::_window_visibility_changed(bool p_visible) {
|
|
||||||
_focus_another_editor();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
void GameViewPlugin::_notification(int p_what) {
|
void GameViewPlugin::_notification(int p_what) {
|
||||||
switch (p_what) {
|
switch (p_what) {
|
||||||
|
|
@ -1161,7 +1132,7 @@ void GameViewPlugin::_feature_profile_changed() {
|
||||||
if (game_view) {
|
if (game_view) {
|
||||||
game_view->set_is_feature_enabled(is_feature_enabled);
|
game_view->set_is_feature_enabled(is_feature_enabled);
|
||||||
}
|
}
|
||||||
#endif
|
#endif // ANDROID_ENABLED
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameViewPlugin::_save_last_editor(const String &p_editor) {
|
void GameViewPlugin::_save_last_editor(const String &p_editor) {
|
||||||
|
|
@ -1185,7 +1156,7 @@ bool GameViewPlugin::_is_window_wrapper_enabled() const {
|
||||||
return true;
|
return true;
|
||||||
#else
|
#else
|
||||||
return window_wrapper->get_window_enabled();
|
return window_wrapper->get_window_enabled();
|
||||||
#endif
|
#endif // ANDROID_ENABLED
|
||||||
}
|
}
|
||||||
|
|
||||||
GameViewPlugin::GameViewPlugin() {
|
GameViewPlugin::GameViewPlugin() {
|
||||||
|
|
@ -1204,8 +1175,8 @@ GameViewPlugin::GameViewPlugin() {
|
||||||
EditorNode::get_singleton()->get_editor_main_screen()->get_control()->add_child(window_wrapper);
|
EditorNode::get_singleton()->get_editor_main_screen()->get_control()->add_child(window_wrapper);
|
||||||
window_wrapper->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
window_wrapper->set_v_size_flags(Control::SIZE_EXPAND_FILL);
|
||||||
window_wrapper->hide();
|
window_wrapper->hide();
|
||||||
window_wrapper->connect("window_visibility_changed", callable_mp(this, &GameViewPlugin::_window_visibility_changed));
|
window_wrapper->connect("window_visibility_changed", callable_mp(this, &GameViewPlugin::_focus_another_editor).unbind(1));
|
||||||
#endif
|
#endif // ANDROID_ENABLED
|
||||||
|
|
||||||
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &GameViewPlugin::_feature_profile_changed));
|
EditorFeatureProfileManager::get_singleton()->connect("current_feature_profile_changed", callable_mp(this, &GameViewPlugin::_feature_profile_changed));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ class GameViewPlugin : public EditorPlugin {
|
||||||
#ifndef ANDROID_ENABLED
|
#ifndef ANDROID_ENABLED
|
||||||
GameView *game_view = nullptr;
|
GameView *game_view = nullptr;
|
||||||
WindowWrapper *window_wrapper = nullptr;
|
WindowWrapper *window_wrapper = nullptr;
|
||||||
#endif
|
#endif // ANDROID_ENABLED
|
||||||
|
|
||||||
Ref<GameViewDebugger> debugger;
|
Ref<GameViewDebugger> debugger;
|
||||||
|
|
||||||
|
|
@ -221,7 +221,7 @@ class GameViewPlugin : public EditorPlugin {
|
||||||
void _feature_profile_changed();
|
void _feature_profile_changed();
|
||||||
#ifndef ANDROID_ENABLED
|
#ifndef ANDROID_ENABLED
|
||||||
void _window_visibility_changed(bool p_visible);
|
void _window_visibility_changed(bool p_visible);
|
||||||
#endif
|
#endif // ANDROID_ENABLED
|
||||||
void _save_last_editor(const String &p_editor);
|
void _save_last_editor(const String &p_editor);
|
||||||
void _focus_another_editor();
|
void _focus_another_editor();
|
||||||
bool _is_window_wrapper_enabled() const;
|
bool _is_window_wrapper_enabled() const;
|
||||||
|
|
@ -243,10 +243,7 @@ public:
|
||||||
|
|
||||||
virtual void set_window_layout(Ref<ConfigFile> p_layout) override;
|
virtual void set_window_layout(Ref<ConfigFile> p_layout) override;
|
||||||
virtual void get_window_layout(Ref<ConfigFile> p_layout) override;
|
virtual void get_window_layout(Ref<ConfigFile> p_layout) override;
|
||||||
|
#endif // ANDROID_ENABLED
|
||||||
virtual void set_state(const Dictionary &p_state) override;
|
|
||||||
virtual Dictionary get_state() const override;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
GameViewPlugin();
|
GameViewPlugin();
|
||||||
~GameViewPlugin();
|
~GameViewPlugin();
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -36,11 +36,16 @@
|
||||||
#include "core/templates/pair.h"
|
#include "core/templates/pair.h"
|
||||||
#include "core/variant/array.h"
|
#include "core/variant/array.h"
|
||||||
#include "scene/gui/view_panner.h"
|
#include "scene/gui/view_panner.h"
|
||||||
|
#ifndef _3D_DISABLED
|
||||||
#include "scene/resources/mesh.h"
|
#include "scene/resources/mesh.h"
|
||||||
|
#endif // _3D_DISABLED
|
||||||
|
|
||||||
|
class CanvasItem;
|
||||||
class PopupMenu;
|
class PopupMenu;
|
||||||
class Script;
|
class Script;
|
||||||
class Node;
|
#ifndef _3D_DISABLED
|
||||||
|
class Node3D;
|
||||||
|
#endif // _3D_DISABLED
|
||||||
|
|
||||||
class SceneDebugger {
|
class SceneDebugger {
|
||||||
private:
|
private:
|
||||||
|
|
@ -60,8 +65,8 @@ private:
|
||||||
|
|
||||||
static void _save_node(ObjectID id, const String &p_path);
|
static void _save_node(ObjectID id, const String &p_path);
|
||||||
static void _set_node_owner_recursive(Node *p_node, Node *p_owner);
|
static void _set_node_owner_recursive(Node *p_node, Node *p_owner);
|
||||||
static void _set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value);
|
static void _set_object_property(ObjectID p_id, const String &p_property, const Variant &p_value, const String &p_field = "");
|
||||||
static void _send_object_id(ObjectID p_id, int p_max_size = 1 << 20);
|
static void _send_object_ids(const Vector<ObjectID> &p_ids, bool p_update_selection);
|
||||||
static void _next_frame();
|
static void _next_frame();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
@ -179,30 +184,49 @@ public:
|
||||||
NODE_TYPE_NONE,
|
NODE_TYPE_NONE,
|
||||||
NODE_TYPE_2D,
|
NODE_TYPE_2D,
|
||||||
NODE_TYPE_3D,
|
NODE_TYPE_3D,
|
||||||
NODE_TYPE_MAX
|
NODE_TYPE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum SelectMode {
|
enum SelectMode {
|
||||||
SELECT_MODE_SINGLE,
|
SELECT_MODE_SINGLE,
|
||||||
SELECT_MODE_LIST,
|
SELECT_MODE_LIST,
|
||||||
SELECT_MODE_MAX
|
SELECT_MODE_MAX,
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class SceneDebugger;
|
friend class SceneDebugger;
|
||||||
|
|
||||||
|
NodeType node_select_type = NODE_TYPE_2D;
|
||||||
|
SelectMode node_select_mode = SELECT_MODE_SINGLE;
|
||||||
|
|
||||||
struct SelectResult {
|
struct SelectResult {
|
||||||
Node *item = nullptr;
|
Node *item = nullptr;
|
||||||
real_t order = 0;
|
real_t order = 0;
|
||||||
_FORCE_INLINE_ bool operator<(const SelectResult &p_rr) const { return p_rr.order < order; }
|
_FORCE_INLINE_ bool operator<(const SelectResult &p_rr) const { return p_rr.order < order; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const int SELECTION_MIN_AREA = 8 * 8;
|
||||||
|
enum SelectionDragState {
|
||||||
|
SELECTION_DRAG_NONE,
|
||||||
|
SELECTION_DRAG_MOVE,
|
||||||
|
SELECTION_DRAG_END,
|
||||||
|
};
|
||||||
|
SelectionDragState selection_drag_state = SELECTION_DRAG_NONE;
|
||||||
|
|
||||||
bool has_selection = false;
|
bool has_selection = false;
|
||||||
Node *selected_node = nullptr;
|
int max_selection = 1;
|
||||||
|
Point2 selection_position = Point2(INFINITY, INFINITY);
|
||||||
|
Rect2 selection_drag_area;
|
||||||
PopupMenu *selection_list = nullptr;
|
PopupMenu *selection_list = nullptr;
|
||||||
|
Color selection_area_fill;
|
||||||
|
Color selection_area_outline;
|
||||||
bool selection_visible = true;
|
bool selection_visible = true;
|
||||||
bool selection_update_queued = false;
|
bool selection_update_queued = false;
|
||||||
bool warped_panning = false;
|
|
||||||
|
bool multi_shortcut_pressed = false;
|
||||||
|
bool list_shortcut_pressed = false;
|
||||||
|
RID draw_canvas;
|
||||||
|
RID sel_drag_ci;
|
||||||
|
|
||||||
bool camera_override = false;
|
bool camera_override = false;
|
||||||
|
|
||||||
|
|
@ -213,11 +237,12 @@ private:
|
||||||
Ref<ViewPanner> panner;
|
Ref<ViewPanner> panner;
|
||||||
Vector2 view_2d_offset;
|
Vector2 view_2d_offset;
|
||||||
real_t view_2d_zoom = 1.0;
|
real_t view_2d_zoom = 1.0;
|
||||||
|
bool warped_panning = false;
|
||||||
|
|
||||||
|
LocalVector<ObjectID> selected_ci_nodes;
|
||||||
|
real_t sel_2d_grab_dist = 0;
|
||||||
|
|
||||||
RID sbox_2d_canvas;
|
|
||||||
RID sbox_2d_ci;
|
RID sbox_2d_ci;
|
||||||
Transform2D sbox_2d_xform;
|
|
||||||
Rect2 sbox_2d_rect;
|
|
||||||
|
|
||||||
#ifndef _3D_DISABLED
|
#ifndef _3D_DISABLED
|
||||||
struct Cursor {
|
struct Cursor {
|
||||||
|
|
@ -264,22 +289,35 @@ private:
|
||||||
|
|
||||||
Vector2 previous_mouse_position;
|
Vector2 previous_mouse_position;
|
||||||
|
|
||||||
|
struct SelectionBox3D : public RefCounted {
|
||||||
|
RID instance;
|
||||||
|
RID instance_ofs;
|
||||||
|
RID instance_xray;
|
||||||
|
RID instance_xray_ofs;
|
||||||
|
|
||||||
|
Transform3D transform;
|
||||||
|
AABB bounds;
|
||||||
|
|
||||||
|
~SelectionBox3D() {
|
||||||
|
if (instance.is_valid()) {
|
||||||
|
RS::get_singleton()->free(instance);
|
||||||
|
RS::get_singleton()->free(instance_ofs);
|
||||||
|
RS::get_singleton()->free(instance_xray);
|
||||||
|
RS::get_singleton()->free(instance_xray_ofs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
HashMap<ObjectID, Ref<SelectionBox3D>> selected_3d_nodes;
|
||||||
|
|
||||||
|
Color sbox_3d_color;
|
||||||
Ref<ArrayMesh> sbox_3d_mesh;
|
Ref<ArrayMesh> sbox_3d_mesh;
|
||||||
Ref<ArrayMesh> sbox_3d_mesh_xray;
|
Ref<ArrayMesh> sbox_3d_mesh_xray;
|
||||||
RID sbox_3d_instance;
|
RID sbox_3d;
|
||||||
RID sbox_3d_instance_ofs;
|
RID sbox_3d_ofs;
|
||||||
RID sbox_3d_instance_xray;
|
RID sbox_3d_xray;
|
||||||
RID sbox_3d_instance_xray_ofs;
|
RID sbox_3d_xray_ofs;
|
||||||
Transform3D sbox_3d_xform;
|
|
||||||
AABB sbox_3d_bounds;
|
|
||||||
#endif // _3D_DISABLED
|
#endif // _3D_DISABLED
|
||||||
|
|
||||||
Point2 selection_position = Point2(INFINITY, INFINITY);
|
|
||||||
bool list_shortcut_pressed = false;
|
|
||||||
|
|
||||||
NodeType node_select_type = NODE_TYPE_2D;
|
|
||||||
SelectMode node_select_mode = SELECT_MODE_SINGLE;
|
|
||||||
|
|
||||||
void _setup(const Dictionary &p_settings);
|
void _setup(const Dictionary &p_settings);
|
||||||
|
|
||||||
void _node_set_type(NodeType p_type);
|
void _node_set_type(NodeType p_type);
|
||||||
|
|
@ -294,17 +332,19 @@ private:
|
||||||
void _process_frame();
|
void _process_frame();
|
||||||
void _physics_frame();
|
void _physics_frame();
|
||||||
|
|
||||||
void _click_point();
|
void _send_ids(const Vector<Node *> &p_picked_nodes, bool p_invert_new_selections = true);
|
||||||
void _select_node(Node *p_node);
|
void _set_selected_nodes(const Vector<Node *> &p_nodes);
|
||||||
void _queue_selection_update();
|
void _queue_selection_update();
|
||||||
void _update_selection();
|
void _update_selection();
|
||||||
void _clear_selection();
|
void _clear_selection();
|
||||||
|
void _update_selection_drag(const Point2 &p_end_pos = Point2());
|
||||||
void _set_selection_visible(bool p_visible);
|
void _set_selection_visible(bool p_visible);
|
||||||
|
|
||||||
void _open_selection_list(const Vector<SelectResult> &p_items, const Point2 &p_pos);
|
void _open_selection_list(const Vector<SelectResult> &p_items, const Point2 &p_pos);
|
||||||
void _close_selection_list();
|
void _close_selection_list();
|
||||||
|
|
||||||
void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
|
void _find_canvas_items_at_pos(const Point2 &p_pos, Node *p_node, Vector<SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
|
||||||
|
void _find_canvas_items_at_rect(const Rect2 &p_rect, Node *p_node, Vector<SelectResult> &r_items, const Transform2D &p_parent_xform = Transform2D(), const Transform2D &p_canvas_xform = Transform2D());
|
||||||
void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
|
void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
|
||||||
void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
|
void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
|
||||||
void _reset_camera_2d();
|
void _reset_camera_2d();
|
||||||
|
|
@ -312,6 +352,9 @@ private:
|
||||||
|
|
||||||
#ifndef _3D_DISABLED
|
#ifndef _3D_DISABLED
|
||||||
void _find_3d_items_at_pos(const Point2 &p_pos, Vector<SelectResult> &r_items);
|
void _find_3d_items_at_pos(const Point2 &p_pos, Vector<SelectResult> &r_items);
|
||||||
|
void _find_3d_items_at_rect(const Rect2 &p_rect, Vector<SelectResult> &r_items);
|
||||||
|
Vector3 _get_screen_to_space(const Vector3 &p_vector3);
|
||||||
|
|
||||||
bool _handle_3d_input(const Ref<InputEvent> &p_event);
|
bool _handle_3d_input(const Ref<InputEvent> &p_event);
|
||||||
void _set_camera_freelook_enabled(bool p_enabled);
|
void _set_camera_freelook_enabled(bool p_enabled);
|
||||||
void _cursor_scale_distance(real_t p_scale);
|
void _cursor_scale_distance(real_t p_scale);
|
||||||
|
|
@ -322,7 +365,7 @@ private:
|
||||||
Point2 _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_event, Rect2 p_border) const;
|
Point2 _get_warped_mouse_motion(const Ref<InputEventMouseMotion> &p_event, Rect2 p_border) const;
|
||||||
Transform3D _get_cursor_transform();
|
Transform3D _get_cursor_transform();
|
||||||
void _reset_camera_3d();
|
void _reset_camera_3d();
|
||||||
#endif
|
#endif // _3D_DISABLED
|
||||||
|
|
||||||
RuntimeNodeSelect() { singleton = this; }
|
RuntimeNodeSelect() { singleton = this; }
|
||||||
|
|
||||||
|
|
@ -333,4 +376,4 @@ public:
|
||||||
|
|
||||||
~RuntimeNodeSelect();
|
~RuntimeNodeSelect();
|
||||||
};
|
};
|
||||||
#endif
|
#endif // DEBUG_ENABLED
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue