diff options
Diffstat (limited to 'editor')
51 files changed, 894 insertions, 463 deletions
diff --git a/editor/animation_editor.cpp b/editor/animation_editor.cpp index 63ed27e60c..1e6562fcf2 100644 --- a/editor/animation_editor.cpp +++ b/editor/animation_editor.cpp @@ -1871,21 +1871,35 @@ void AnimationKeyEditor::_track_editor_gui_input(const InputEvent &p_input) { if (mb.button_index == BUTTON_WHEEL_UP && mb.pressed) { if (mb.mod.command) { + zoom->set_value(zoom->get_value() + zoom->get_step()); } else { - v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() / 8); + + v_scroll->set_value(v_scroll->get_value() - v_scroll->get_page() * mb.factor / 8); } } if (mb.button_index == BUTTON_WHEEL_DOWN && mb.pressed) { if (mb.mod.command) { + zoom->set_value(zoom->get_value() - zoom->get_step()); } else { - v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() / 8); + + v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * mb.factor / 8); } } + if (mb.button_index == BUTTON_WHEEL_RIGHT && mb.pressed) { + + h_scroll->set_value(h_scroll->get_value() - h_scroll->get_page() * mb.factor / 8); + } + + if (mb.button_index == BUTTON_WHEEL_LEFT && mb.pressed) { + + v_scroll->set_value(v_scroll->get_value() + v_scroll->get_page() * mb.factor / 8); + } + if (mb.button_index == BUTTON_RIGHT && mb.pressed) { Point2 mpos = Point2(mb.x, mb.y) - ofs; diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 4796640a3d..3774c8d4c3 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -321,7 +321,7 @@ Error EditorExportPlatform::_save_zip_file(void *p_userdata, const String &p_pat return OK; } -String EditorExportPlatform::find_export_template(String template_file_name) const { +String EditorExportPlatform::find_export_template(String template_file_name, String *err) const { String base_name = itos(VERSION_MAJOR) + "." + itos(VERSION_MINOR) + "-" + _MKSTR(VERSION_STATUS) + "/" + template_file_name; String user_file = EditorSettings::get_singleton()->get_settings_path() + "/templates/" + base_name; @@ -342,9 +342,20 @@ String EditorExportPlatform::find_export_template(String template_file_name) con return system_file; } } - print_line("none,sorry"); - return String(); //not found + // Not found + if (err) { + *err += "No export template found at \"" + user_file + "\""; + if (has_system_path) + *err += "\n or \"" + system_file + "\"."; + else + *err += "."; + } + return String(); // not found +} + +bool EditorExportPlatform::exists_export_template(String template_file_name, String *err) const { + return find_export_template(template_file_name, err) != ""; } Ref<EditorExportPreset> EditorExportPlatform::create_preset() { @@ -925,19 +936,47 @@ Ref<Texture> EditorExportPlatformPC::get_logo() const { bool EditorExportPlatformPC::can_export(const Ref<EditorExportPreset> &p_preset, String &r_error, bool &r_missing_templates) const { - r_missing_templates = false; + String err; + bool valid = true; + + if (use64 && (!exists_export_template(debug_file_64, &err) || !exists_export_template(release_file_64, &err))) { + valid = false; + } + + if (!use64 && (!exists_export_template(debug_file_32, &err) || !exists_export_template(release_file_32, &err))) { + valid = false; + } + + String custom_debug_binary = p_preset->get("custom_template/debug"); + String custom_release_binary = p_preset->get("custom_template/release"); + + if (custom_debug_binary == "" && custom_release_binary == "") { + if (!err.empty()) + r_error = err; + return valid; + } + + bool dvalid = true; + bool rvalid = true; + + if (!FileAccess::exists(custom_debug_binary)) { + dvalid = false; + err = "Custom debug binary not found.\n"; + } - if (find_export_template(release_file_32) == String()) { - r_missing_templates = true; - } else if (find_export_template(debug_file_32) == String()) { - r_missing_templates = true; - } else if (find_export_template(release_file_64) == String()) { - r_missing_templates = true; - } else if (find_export_template(debug_file_64) == String()) { - r_missing_templates = true; + if (!FileAccess::exists(custom_release_binary)) { + rvalid = false; + err += "Custom release binary not found.\n"; } - return !r_missing_templates; + if (dvalid || rvalid) + valid = true; + else + valid = false; + + if (!err.empty()) + r_error = err; + return valid; } String EditorExportPlatformPC::get_binary_extension() const { @@ -1497,40 +1536,6 @@ Vector<StringName> EditorExportPlatform::get_dependencies(bool p_bundles) const } -String EditorExportPlatform::find_export_template(String template_file_name, String *err) const { - String user_file = EditorSettings::get_singleton()->get_settings_path() - +"/templates/"+template_file_name; - String system_file=OS::get_singleton()->get_installed_templates_path(); - bool has_system_path=(system_file!=""); - system_file+=template_file_name; - - // Prefer user file - if (FileAccess::exists(user_file)) { - return user_file; - } - - // Now check system file - if (has_system_path) { - if (FileAccess::exists(system_file)) { - return system_file; - } - } - - // Not found - if (err) { - *err+="No export template found at \""+user_file+"\""; - if (has_system_path) - *err+="\n or \""+system_file+"\"."; - else - *err+="."; - } - return ""; -} - -bool EditorExportPlatform::exists_export_template(String template_file_name, String *err) const { - return find_export_template(template_file_name,err)!=""; -} - /////////////////////////////////////// @@ -2430,50 +2435,6 @@ void EditorExportPlatformPC::set_binary_extension(const String& p_extension) { binary_extension=p_extension; } -bool EditorExportPlatformPC::can_export(String *r_error) const { - - String err; - bool valid=true; - - if (use64 && (!exists_export_template(debug_binary64) || !exists_export_template(release_binary64))) { - valid=false; - err="No 64 bits export templates found.\nDownload and install export templates.\n"; - } - - if (!use64 && (!exists_export_template(debug_binary32) || !exists_export_template(release_binary32))) { - valid=false; - err="No 32 bits export templates found.\nDownload and install export templates.\n"; - } - - if(custom_debug_binary=="" && custom_release_binary=="") { - if (r_error) *r_error=err; - return valid; - } - - bool dvalid = true; - bool rvalid = true; - - if(!FileAccess::exists(custom_debug_binary)) { - dvalid = false; - err = "Custom debug binary not found.\n"; - } - - if(!FileAccess::exists(custom_release_binary)) { - rvalid = false; - err = "Custom release binary not found.\n"; - } - - if (dvalid || rvalid) - valid = true; - else - valid = false; - - if (r_error) - *r_error=err; - return valid; -} - - EditorExportPlatformPC::EditorExportPlatformPC() { export_mode=EXPORT_PACK; diff --git a/editor/editor_export.h b/editor/editor_export.h index a78762ad80..740f05174b 100644 --- a/editor/editor_export.h +++ b/editor/editor_export.h @@ -154,7 +154,8 @@ private: protected: virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features) = 0; - String find_export_template(String template_file_name) const; + bool exists_export_template(String template_file_name, String *err) const; + String find_export_template(String template_file_name, String *err = NULL) const; void gen_export_flags(Vector<String> &r_flags, int p_flags); public: @@ -258,6 +259,8 @@ class EditorExportPlatformPC : public EditorExportPlatform { String debug_file_32; String debug_file_64; + bool use64; + public: virtual void get_preset_features(const Ref<EditorExportPreset> &p_preset, List<String> *r_features); diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 6b23a02275..698066f188 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1651,7 +1651,7 @@ void EditorNode::_run(bool p_current, const String &p_custom) { current_option = -1; //accept->get_cancel()->hide(); - pick_main_scene->set_text(TTR("No main scene has ever been defined, select one?\nYou can change it later in later in \"Project Settings\" under the 'application' category.")); + pick_main_scene->set_text(TTR("No main scene has ever been defined, select one?\nYou can change it later in \"Project Settings\" under the 'application' category.")); pick_main_scene->popup_centered_minsize(); return; } @@ -2689,6 +2689,14 @@ void EditorNode::_editor_select(int p_which) { editor_plugin_screen = new_editor; editor_plugin_screen->make_visible(true); editor_plugin_screen->selected_notify(); + + if (EditorSettings::get_singleton()->get("interface/separate_distraction_mode")) { + if (p_which == EDITOR_SCRIPT) { + set_distraction_free_mode(script_distraction); + } else { + set_distraction_free_mode(scene_distraction); + } + } } void EditorNode::add_editor_plugin(EditorPlugin *p_editor) { @@ -4382,7 +4390,25 @@ bool EditorNode::get_docks_visible() const { void EditorNode::_toggle_distraction_free_mode() { - set_distraction_free_mode(distraction_free->is_pressed()); + if (EditorSettings::get_singleton()->get("interface/separate_distraction_mode")) { + int screen = -1; + for (int i = 0; i < editor_table.size(); i++) { + if (editor_plugin_screen == editor_table[i]) { + screen = i; + break; + } + } + + if (screen == EDITOR_SCRIPT) { + script_distraction = !script_distraction; + set_distraction_free_mode(script_distraction); + } else { + scene_distraction = !scene_distraction; + set_distraction_free_mode(scene_distraction); + } + } else { + set_distraction_free_mode(distraction_free->is_pressed()); + } } void EditorNode::set_distraction_free_mode(bool p_enter) { @@ -4806,6 +4832,9 @@ EditorNode::EditorNode() { _initializing_addons = false; docks_visible = true; + scene_distraction = false; + script_distraction = false; + FileAccess::set_backup_save(true); TranslationServer::get_singleton()->set_enabled(false); diff --git a/editor/editor_node.h b/editor/editor_node.h index 7de713eae9..fc107bb505 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -357,6 +357,9 @@ private: bool docks_visible; ToolButton *distraction_free; + bool scene_distraction; + bool script_distraction; + String _tmp_import_path; EditorExport *editor_export; diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 1b4f77419b..9fd76590a6 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -509,6 +509,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("interface/dim_transition_time", 0.08f); hints["interface/dim_transition_time"] = PropertyInfo(Variant::REAL, "interface/dim_transition_time", PROPERTY_HINT_RANGE, "0,1,0.001", PROPERTY_USAGE_DEFAULT); + set("interface/separate_distraction_mode", false); + set("filesystem/directories/autoscan_project_path", ""); hints["filesystem/directories/autoscan_project_path"] = PropertyInfo(Variant::STRING, "filesystem/directories/autoscan_project_path", PROPERTY_HINT_GLOBAL_DIR); set("filesystem/directories/default_project_path", ""); @@ -589,6 +591,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set("editors/3d/emulate_3_button_mouse", false); set("editors/3d/warped_mouse_panning", true); + set("editors/3d/freelook_base_speed", 1); + set("editors/3d/freelook_modifier_speed_factor", 5.0); + set("editors/2d/bone_width", 5); set("editors/2d/bone_color1", Color(1.0, 1.0, 1.0, 0.9)); set("editors/2d/bone_color2", Color(0.75, 0.75, 0.75, 0.9)); diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 19fd1208b9..21c2ae6eb3 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -168,18 +168,23 @@ Error ResourceImporterOBJ::import(const String &p_source_file, const String &p_s if (face[idx].size() == 3) { int norm = face[idx][2].to_int() - 1; + if (norm < 0) + norm += normals.size() + 1; ERR_FAIL_INDEX_V(norm, normals.size(), ERR_PARSE_ERROR); surf_tool->add_normal(normals[norm]); } if (face[idx].size() >= 2 && face[idx][1] != String()) { - int uv = face[idx][1].to_int() - 1; + if (uv < 0) + uv += uvs.size() + 1; ERR_FAIL_INDEX_V(uv, uvs.size(), ERR_PARSE_ERROR); surf_tool->add_uv(uvs[uv]); } int vtx = face[idx][0].to_int() - 1; + if (vtx < 0) + vtx += vertices.size() + 1; ERR_FAIL_INDEX_V(vtx, vertices.size(), ERR_PARSE_ERROR); Vector3 vertex = vertices[vtx]; diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index 430a5adeb1..27be6ea8f0 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -1049,7 +1049,7 @@ void CanvasItemEditor::_viewport_gui_input(const InputEvent &p_event) { return; float prev_zoom = zoom; - zoom = zoom * 0.95; + zoom = zoom * (1 - (0.05 * b.factor)); { Point2 ofs(b.x, b.y); ofs = ofs / prev_zoom - ofs / zoom; @@ -1067,7 +1067,7 @@ void CanvasItemEditor::_viewport_gui_input(const InputEvent &p_event) { return; float prev_zoom = zoom; - zoom = zoom * (1.0 / 0.95); + zoom = zoom * ((0.95 + (0.05 * b.factor)) / 0.95); { Point2 ofs(b.x, b.y); ofs = ofs / prev_zoom - ofs / zoom; diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index e84e782580..896a26c8e8 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -522,10 +522,10 @@ void Polygon2DEditor::_uv_input(const InputEvent &p_input) { } else if (mb.button_index == BUTTON_WHEEL_UP && mb.pressed) { - uv_zoom->set_value(uv_zoom->get_value() / 0.9); + uv_zoom->set_value(uv_zoom->get_value() / (1 - (0.1 * mb.factor))); } else if (mb.button_index == BUTTON_WHEEL_DOWN && mb.pressed) { - uv_zoom->set_value(uv_zoom->get_value() * 0.9); + uv_zoom->set_value(uv_zoom->get_value() * (1 - (0.1 * mb.factor))); } } else if (p_input.type == InputEvent::MOUSE_MOTION) { diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index d73349f773..0bd4d7d6d2 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -51,6 +51,12 @@ //#define GIZMO_SCALE_DEFAULT 0.28 #define GIZMO_SCALE_DEFAULT 0.15 +#define ZOOM_MIN_DISTANCE 0.001 +#define ZOOM_MULTIPLIER 1.08 +#define ZOOM_INDICATOR_DELAY_S 1.5 + +#define FREELOOK_MIN_SPEED 0.1 + void SpatialEditorViewport::_update_camera() { if (orthogonal) { //camera->set_orthogonal(size.width*cursor.distance,get_znear(),get_zfar()); @@ -58,20 +64,26 @@ void SpatialEditorViewport::_update_camera() { } else camera->set_perspective(get_fov(), get_znear(), get_zfar()); + Transform camera_transform = to_camera_transform(cursor); + + if (camera->get_global_transform() != camera_transform) { + camera->set_global_transform(camera_transform); + update_transform_gizmo_view(); + } +} + +Transform SpatialEditorViewport::to_camera_transform(const Cursor &p_cursor) const { Transform camera_transform; - camera_transform.translate(cursor.pos); - camera_transform.basis.rotate(Vector3(1, 0, 0), -cursor.x_rot); - camera_transform.basis.rotate(Vector3(0, 1, 0), -cursor.y_rot); + camera_transform.translate(p_cursor.pos); + camera_transform.basis.rotate(Vector3(1, 0, 0), -p_cursor.x_rot); + camera_transform.basis.rotate(Vector3(0, 1, 0), -p_cursor.y_rot); if (orthogonal) camera_transform.translate(0, 0, 4096); else - camera_transform.translate(0, 0, cursor.distance); + camera_transform.translate(0, 0, p_cursor.distance); - if (camera->get_global_transform() != camera_transform) { - camera->set_global_transform(camera_transform); - update_transform_gizmo_view(); - } + return camera_transform; } String SpatialEditorGizmo::get_handle_name(int p_idx) const { @@ -669,8 +681,7 @@ void SpatialEditorViewport::_list_select(InputEventMouseButton b) { selection_menu->add_item(spat->get_name()); selection_menu->set_item_icon(i, icon); selection_menu->set_item_metadata(i, node_path); - selection_menu->set_item_tooltip(i, String(spat->get_name()) + - "\nType: " + spat->get_class() + "\nPath: " + node_path); + selection_menu->set_item_tooltip(i, String(spat->get_name()) + "\nType: " + spat->get_class() + "\nPath: " + node_path); } selection_menu->set_global_position(Vector2(b.global_x, b.global_y)); @@ -704,19 +715,13 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { switch (b.button_index) { case BUTTON_WHEEL_UP: { - - cursor.distance /= 1.08; - if (cursor.distance < 0.001) - cursor.distance = 0.001; - + scale_cursor_distance(is_freelook_active() ? ZOOM_MULTIPLIER : 1.0 / ZOOM_MULTIPLIER); } break; - case BUTTON_WHEEL_DOWN: { - - if (cursor.distance < 0.001) - cursor.distance = 0.001; - cursor.distance *= 1.08; + case BUTTON_WHEEL_DOWN: { + scale_cursor_distance(is_freelook_active() ? 1.0 / ZOOM_MULTIPLIER : ZOOM_MULTIPLIER); } break; + case BUTTON_RIGHT: { NavigationScheme nav_scheme = (NavigationScheme)EditorSettings::get_singleton()->get("editors/3d/navigation_scheme").operator int(); @@ -729,76 +734,6 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { if (_edit.mode == TRANSFORM_NONE && b.pressed) { - Plane cursor_plane(cursor.cursor_pos, _get_camera_normal()); - - Vector3 ray_origin = _get_ray_pos(Vector2(b.x, b.y)); - Vector3 ray_dir = _get_ray(Vector2(b.x, b.y)); - - //gizmo modify - - if (b.mod.control) { - - Vector<ObjectID> instances = VisualServer::get_singleton()->instances_cull_ray(ray_origin, ray_dir, get_tree()->get_root()->get_world()->get_scenario()); - - Plane p(ray_origin, _get_camera_normal()); - - float min_d = 1e10; - bool found = false; - - for (int i = 0; i < instances.size(); i++) { - - Object *obj = ObjectDB::get_instance(instances[i]); - - if (!obj) - continue; - - VisualInstance *vi = obj->cast_to<VisualInstance>(); - if (!vi) - continue; - - //optimize by checking AABB (although should pre sort by distance) - Rect3 aabb = vi->get_global_transform().xform(vi->get_aabb()); - if (p.distance_to(aabb.get_support(-ray_dir)) > min_d) - continue; - - PoolVector<Face3> faces = vi->get_faces(VisualInstance::FACES_SOLID); - int c = faces.size(); - if (c > 0) { - PoolVector<Face3>::Read r = faces.read(); - - for (int j = 0; j < c; j++) { - - Vector3 inters; - if (r[j].intersects_ray(ray_origin, ray_dir, &inters)) { - - float d = p.distance_to(inters); - if (d < 0) - continue; - - if (d < min_d) { - min_d = d; - found = true; - } - } - } - } - } - - if (found) { - - //cursor.cursor_pos=ray_origin+ray_dir*min_d; - //VisualServer::get_singleton()->instance_set_transform(cursor_instance,Transform(Matrix3(),cursor.cursor_pos)); - } - - } else { - Vector3 new_pos; - if (cursor_plane.intersects_ray(ray_origin, ray_dir, &new_pos)) { - - //cursor.cursor_pos=new_pos; - //VisualServer::get_singleton()->instance_set_transform(cursor_instance,Transform(Matrix3(),cursor.cursor_pos)); - } - } - if (b.mod.alt) { if (nav_scheme == NAVIGATION_MAYA) @@ -832,6 +767,9 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { //VisualServer::get_singleton()->poly_clear(indicators); set_message(TTR("Transform Aborted."), 3); } + + freelook_active = b.pressed; + } break; case BUTTON_MIDDLE: { @@ -1043,6 +981,7 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { surface->update(); } + } break; } } break; @@ -1090,7 +1029,7 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { String n = _edit.gizmo->get_handle_name(_edit.gizmo_handle); set_message(n + ": " + String(v)); - } else if (m.button_mask & 1) { + } else if (m.button_mask & BUTTON_MASK_LEFT) { if (nav_scheme == NAVIGATION_MAYA && m.mod.alt) { nav_mode = NAVIGATION_ORBIT; @@ -1340,13 +1279,15 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { } } - } else if (m.button_mask & 2) { + } else if (m.button_mask & BUTTON_MASK_RIGHT) { if (nav_scheme == NAVIGATION_MAYA && m.mod.alt) { nav_mode = NAVIGATION_ZOOM; + } else { + nav_mode = NAVIGATION_LOOK; } - } else if (m.button_mask & 4) { + } else if (m.button_mask & BUTTON_MASK_MIDDLE) { if (nav_scheme == NAVIGATION_GODOT) { @@ -1402,12 +1343,7 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { if (nav_scheme == NAVIGATION_MAYA && m.mod.shift) pan_speed *= pan_speed_modifier; - Point2i relative; - if (bool(EditorSettings::get_singleton()->get("editors/3d/warped_mouse_panning"))) { - relative = Input::get_singleton()->warp_mouse_motion(m, surface->get_global_rect()); - } else { - relative = Point2i(m.relative_x, m.relative_y); - } + Point2i relative = _get_warped_mouse_motion(m); Transform camera_transform; @@ -1430,21 +1366,22 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { NavigationZoomStyle zoom_style = (NavigationZoomStyle)EditorSettings::get_singleton()->get("editors/3d/zoom_style").operator int(); if (zoom_style == NAVIGATION_ZOOM_HORIZONTAL) { if (m.relative_x > 0) - cursor.distance *= 1 - m.relative_x * zoom_speed; + scale_cursor_distance(1 - m.relative_x * zoom_speed); else if (m.relative_x < 0) - cursor.distance /= 1 + m.relative_x * zoom_speed; + scale_cursor_distance(1.0 / (1 + m.relative_x * zoom_speed)); } else { if (m.relative_y > 0) - cursor.distance *= 1 + m.relative_y * zoom_speed; + scale_cursor_distance(1 + m.relative_y * zoom_speed); else if (m.relative_y < 0) - cursor.distance /= 1 - m.relative_y * zoom_speed; + scale_cursor_distance(1.0 / (1 - m.relative_y * zoom_speed)); } } break; case NAVIGATION_ORBIT: { - cursor.x_rot += m.relative_y / 80.0; - cursor.y_rot += m.relative_x / 80.0; + Point2i relative = _get_warped_mouse_motion(m); + cursor.x_rot += relative.y / 80.0; + cursor.y_rot += relative.x / 80.0; if (cursor.x_rot > Math_PI / 2.0) cursor.x_rot = Math_PI / 2.0; if (cursor.x_rot < -Math_PI / 2.0) @@ -1453,6 +1390,30 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { _update_name(); } break; + case NAVIGATION_LOOK: { + // Freelook only works properly in perspective. + // It technically works too in ortho, but it's awful for a user due to fov being near zero + if (!orthogonal) { + Point2i relative = _get_warped_mouse_motion(m); + cursor.x_rot += relative.y / 120.0; + cursor.y_rot += relative.x / 120.0; + if (cursor.x_rot > Math_PI / 2.0) + cursor.x_rot = Math_PI / 2.0; + if (cursor.x_rot < -Math_PI / 2.0) + cursor.x_rot = -Math_PI / 2.0; + + // Look is like Orbit, except the cursor translates, not the camera + Transform camera_transform = to_camera_transform(cursor); + Vector3 pos = camera_transform.xform(Vector3(0, 0, 0)); + Vector3 diff = camera->get_translation() - pos; + cursor.pos += diff; + + name = ""; + _update_name(); + } + + } break; + default: {} } } break; @@ -1543,6 +1504,104 @@ void SpatialEditorViewport::_sinput(const InputEvent &p_event) { } } +void SpatialEditorViewport::scale_cursor_distance(real_t scale) { + + // Prevents zero distance which would short-circuit any scaling + if (cursor.distance < ZOOM_MIN_DISTANCE) + cursor.distance = ZOOM_MIN_DISTANCE; + + real_t prev_distance = cursor.distance; + cursor.distance *= scale; + + if (cursor.distance < ZOOM_MIN_DISTANCE) + cursor.distance = ZOOM_MIN_DISTANCE; + + if (is_freelook_active()) { + // In freelook mode, cursor reference is reversed so it needs to be adjusted + Vector3 forward = camera->get_transform().basis.xform(Vector3(0, 0, -1)); + cursor.pos += (cursor.distance - prev_distance) * forward; + } + + zoom_indicator_delay = ZOOM_INDICATOR_DELAY_S; + surface->update(); +} + +Point2i SpatialEditorViewport::_get_warped_mouse_motion(const InputEventMouseMotion &p_ev_mouse_motion) const { + Point2i relative; + if (bool(EditorSettings::get_singleton()->get("editors/3d/warped_mouse_panning"))) { + relative = Input::get_singleton()->warp_mouse_motion(p_ev_mouse_motion, surface->get_global_rect()); + } else { + relative = Point2i(p_ev_mouse_motion.relative_x, p_ev_mouse_motion.relative_y); + } + return relative; +} + +void SpatialEditorViewport::_update_freelook(real_t delta) { + + if (!is_freelook_active()) + return; + + Vector3 forward = camera->get_transform().basis.xform(Vector3(0, 0, -1)); + Vector3 right = camera->get_transform().basis.xform(Vector3(1, 0, 0)); + Vector3 up = camera->get_transform().basis.xform(Vector3(0, 1, 0)); + + int key_left = ED_SHORTCUT("spatial_editor/freelook_left", TTR("Freelook Left"), KEY_A)->get_shortcut().key.scancode; + int key_right = ED_SHORTCUT("spatial_editor/freelook_right", TTR("Freelook Right"), KEY_D)->get_shortcut().key.scancode; + int key_forward = ED_SHORTCUT("spatial_editor/freelook_forward", TTR("Freelook Forward"), KEY_W)->get_shortcut().key.scancode; + int key_backwards = ED_SHORTCUT("spatial_editor/freelook_backwards", TTR("Freelook Backwards"), KEY_S)->get_shortcut().key.scancode; + int key_up = ED_SHORTCUT("spatial_editor/freelook_up", TTR("Freelook Up"), KEY_Q)->get_shortcut().key.scancode; + int key_down = ED_SHORTCUT("spatial_editor/freelook_down", TTR("Freelook Down"), KEY_E)->get_shortcut().key.scancode; + int key_speed_modifier = ED_SHORTCUT("spatial_editor/freelook_speed_modifier", TTR("Freelook Speed Modifier"), KEY_SHIFT)->get_shortcut().key.scancode; + + Vector3 velocity; + bool pressed = false; + bool speed_modifier = false; + + const Input &input = *Input::get_singleton(); + + if (input.is_key_pressed(key_left)) { + velocity -= right; + pressed = true; + } + if (input.is_key_pressed(key_right)) { + velocity += right; + pressed = true; + } + if (input.is_key_pressed(key_forward)) { + velocity += forward; + pressed = true; + } + if (input.is_key_pressed(key_backwards)) { + velocity -= forward; + pressed = true; + } + if (input.is_key_pressed(key_up)) { + velocity += up; + pressed = true; + } + if (input.is_key_pressed(key_down)) { + velocity -= up; + pressed = true; + } + if (input.is_key_pressed(key_speed_modifier)) { + speed_modifier = true; + } + + if (pressed) { + const EditorSettings &s = *EditorSettings::get_singleton(); + const real_t base_speed = s.get("editors/3d/freelook_base_speed"); + const real_t modifier_speed_factor = s.get("editors/3d/freelook_modifier_speed_factor"); + + real_t speed = base_speed * cursor.distance; + if (speed_modifier) + speed *= modifier_speed_factor; + + velocity.normalize(); + + cursor.pos += velocity * (speed * delta); + } +} + void SpatialEditorViewport::set_message(String p_message, float p_time) { message = p_message; @@ -1579,6 +1638,17 @@ void SpatialEditorViewport::_notification(int p_what) { } */ + real_t delta = get_tree()->get_idle_process_time(); + + if (zoom_indicator_delay > 0) { + zoom_indicator_delay -= delta; + if (zoom_indicator_delay <= 0) { + surface->update(); + } + } + + _update_freelook(delta); + _update_camera(); Map<Node *, Object *> &selection = editor_selection->get_selection(); @@ -1674,6 +1744,23 @@ void SpatialEditorViewport::_notification(int p_what) { } } +// TODO That should be part of the drawing API... +static void stroke_rect(CanvasItem *ci, Rect2 rect, Color color, real_t width = 1.0) { + + // a---b + // | | + // c---d + Vector2 a(rect.pos); + Vector2 b(rect.pos.x + rect.size.x, rect.pos.y); + Vector2 c(rect.pos.x, rect.pos.y + rect.size.y); + Vector2 d(rect.pos + rect.size); + + ci->draw_line(a, b, color, width); + ci->draw_line(b, d, color, width); + ci->draw_line(d, c, color, width); + ci->draw_line(c, a, color, width); +} + void SpatialEditorViewport::_draw() { if (surface->has_focus()) { @@ -1730,10 +1817,37 @@ void SpatialEditorViewport::_draw() { draw_rect = Rect2(Vector2(), s).clip(draw_rect); - surface->draw_line(draw_rect.pos, draw_rect.pos + Vector2(draw_rect.size.x, 0), Color(0.6, 0.6, 0.1, 0.5), 2.0); - surface->draw_line(draw_rect.pos + Vector2(draw_rect.size.x, 0), draw_rect.pos + draw_rect.size, Color(0.6, 0.6, 0.1, 0.5), 2.0); - surface->draw_line(draw_rect.pos + draw_rect.size, draw_rect.pos + Vector2(0, draw_rect.size.y), Color(0.6, 0.6, 0.1, 0.5), 2.0); - surface->draw_line(draw_rect.pos, draw_rect.pos + Vector2(0, draw_rect.size.y), Color(0.6, 0.6, 0.1, 0.5), 2.0); + stroke_rect(surface, draw_rect, Color(0.6, 0.6, 0.1, 0.5), 2.0); + + } else { + + if (zoom_indicator_delay > 0.0) { + // Show indicative zoom factor + + real_t min_distance = ZOOM_MIN_DISTANCE; // TODO Why not pick znear to limit zoom? + real_t max_distance = camera->get_zfar(); + real_t scale_length = (max_distance - min_distance); + + if (Math::abs(scale_length) > CMP_EPSILON) { + real_t logscale_t = 1.0 - Math::log(1 + cursor.distance - min_distance) / Math::log(1 + scale_length); + + // There is no real maximum distance so that factor can become negative, + // Let's make it look asymptotic instead (will decrease slower and slower). + if (logscale_t < 0.25) + logscale_t = 0.25 * Math::exp(4.0 * logscale_t - 1.0); + + Vector2 surface_size = surface->get_size(); + real_t h = surface_size.y / 2.0; + real_t y = (surface_size.y - h) / 2.0; + + Rect2 r(10, y, 6, h); + real_t sy = r.size.y * logscale_t; + + surface->draw_rect(r, Color(1, 1, 1, 0.2)); + surface->draw_rect(Rect2(r.pos.x, r.pos.y + r.size.y - sy, r.size.x, sy), Color(1, 1, 1, 0.6)); + stroke_rect(surface, r.grow(1), Color(0, 0, 0, 0.7)); + } + } } } @@ -2143,6 +2257,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed clicked_includes_current = false; orthogonal = false; message_time = 0; + zoom_indicator_delay = 0.0; spatial_editor = p_spatial_editor; ViewportContainer *c = memnew(ViewportContainer); @@ -2205,6 +2320,8 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed preview = NULL; gizmo_scale = 1.0; + freelook_active = false; + selection_menu = memnew(PopupMenu); add_child(selection_menu); selection_menu->set_custom_minimum_size(Vector2(100, 0)); @@ -2278,7 +2395,7 @@ void SpatialEditor::update_transform_gizmo() { gizmo.transform.origin = pcenter; gizmo.transform.basis = gizmo_basis; - for (int i = 0; i < 4; i++) { + for (int i = 0; i < VIEWPORTS_COUNT; i++) { viewports[i]->update_transform_gizmo_view(); } } @@ -2434,7 +2551,7 @@ void SpatialEditor::set_state(const Dictionary &p_state) { Array vp = d["viewports"]; ERR_FAIL_COND(vp.size() > 4); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < VIEWPORTS_COUNT; i++) { viewports[i]->set_state(vp[i]); } } @@ -2726,7 +2843,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_USE_3_VIEWPORTS: { - for (int i = 1; i < 4; i++) { + for (int i = 1; i < VIEWPORTS_COUNT; i++) { if (i == 1) viewports[i]->hide(); @@ -2752,7 +2869,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_USE_3_VIEWPORTS_ALT: { - for (int i = 1; i < 4; i++) { + for (int i = 1; i < VIEWPORTS_COUNT; i++) { if (i == 1) viewports[i]->hide(); @@ -2778,7 +2895,7 @@ void SpatialEditor::_menu_item_pressed(int p_option) { } break; case MENU_VIEW_USE_4_VIEWPORTS: { - for (int i = 1; i < 4; i++) { + for (int i = 1; i < VIEWPORTS_COUNT; i++) { viewports[i]->show(); } @@ -3149,34 +3266,12 @@ void SpatialEditor::_finish_indicators() { VisualServer::get_singleton()->free(cursor_mesh); } -void SpatialEditor::_instance_scene() { -#if 0 - EditorNode *en = get_scene()->get_root_node()->cast_to<EditorNode>(); - ERR_FAIL_COND(!en); - String path = en->get_filesystem_dock()->get_selected_path(); - if (path=="") { - set_message(TTR("No scene selected to instance!")); - return; - } - - undo_redo->create_action(TTR("Instance at Cursor")); - - Node* scene = en->request_instance_scene(path); - - if (!scene) { - set_message(TTR("Could not instance scene!")); - undo_redo->commit_action(); //bleh - return; - } - - Spatial *s = scene->cast_to<Spatial>(); - if (s) { - - undo_redo->add_do_method(s,"set_global_transform",Transform(Matrix3(),cursor.cursor_pos)); +bool SpatialEditor::is_any_freelook_active() const { + for (unsigned int i = 0; i < VIEWPORTS_COUNT; ++i) { + if (viewports[i]->is_freelook_active()) + return true; } - - undo_redo->commit_action(); -#endif + return false; } void SpatialEditor::_unhandled_key_input(InputEvent p_event) { @@ -3203,19 +3298,27 @@ void SpatialEditor::_unhandled_key_input(InputEvent p_event) { case InputEvent::KEY: { - const InputEventKey &k = p_event.key; + // Note: need to check is_echo because first person movement keys might still be held + if (!is_any_freelook_active() && !p_event.is_echo()) { - if (!k.pressed) - break; + const InputEventKey &k = p_event.key; + + if (!k.pressed) + break; + + if (ED_IS_SHORTCUT("spatial_editor/tool_select", p_event)) + _menu_item_pressed(MENU_TOOL_SELECT); + + else if (ED_IS_SHORTCUT("spatial_editor/tool_move", p_event)) + _menu_item_pressed(MENU_TOOL_MOVE); - switch (k.scancode) { + else if (ED_IS_SHORTCUT("spatial_editor/tool_rotate", p_event)) + _menu_item_pressed(MENU_TOOL_ROTATE); - case KEY_Q: _menu_item_pressed(MENU_TOOL_SELECT); break; - case KEY_W: _menu_item_pressed(MENU_TOOL_MOVE); break; - case KEY_E: _menu_item_pressed(MENU_TOOL_ROTATE); break; - case KEY_R: _menu_item_pressed(MENU_TOOL_SCALE); break; + else if (ED_IS_SHORTCUT("spatial_editor/tool_scale", p_event)) + _menu_item_pressed(MENU_TOOL_SCALE); - case KEY_Z: { + else if (ED_IS_SHORTCUT("spatial_editor/display_wireframe", p_event)) { if (k.mod.shift || k.mod.control || k.mod.command) break; @@ -3224,10 +3327,7 @@ void SpatialEditor::_unhandled_key_input(InputEvent p_event) { } else { _menu_item_pressed(MENU_VIEW_DISPLAY_WIREFRAME); } - } break; - -#if 0 -#endif + } } } break; @@ -3242,8 +3342,6 @@ void SpatialEditor::_notification(int p_what) { tool_button[SpatialEditor::TOOL_MODE_ROTATE]->set_icon(get_icon("ToolRotate", "EditorIcons")); tool_button[SpatialEditor::TOOL_MODE_SCALE]->set_icon(get_icon("ToolScale", "EditorIcons")); tool_button[SpatialEditor::TOOL_MODE_LIST_SELECT]->set_icon(get_icon("ListSelect", "EditorIcons")); - instance_button->set_icon(get_icon("SpatialAdd", "EditorIcons")); - instance_button->hide(); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT), get_icon("Panels1", "EditorIcons")); view_menu->get_popup()->set_item_icon(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_2_VIEWPORTS), get_icon("Panels2", "EditorIcons")); @@ -3344,7 +3442,7 @@ void SpatialEditor::_toggle_maximize_view(Object *p_viewport) { if (!maximized) { - for (int i = 0; i < 4; i++) { + for (int i = 0; i < VIEWPORTS_COUNT; i++) { if (i == index) viewports[i]->set_area_as_parent_rect(); else @@ -3352,7 +3450,7 @@ void SpatialEditor::_toggle_maximize_view(Object *p_viewport) { } } else { - for (int i = 0; i < 4; i++) + for (int i = 0; i < VIEWPORTS_COUNT; i++) viewports[i]->show(); if (view_menu->get_popup()->is_item_checked(view_menu->get_popup()->get_item_index(MENU_VIEW_USE_1_VIEWPORT))) @@ -3383,7 +3481,6 @@ void SpatialEditor::_bind_methods() { ClassDB::bind_method("_node_removed", &SpatialEditor::_node_removed); ClassDB::bind_method("_menu_item_pressed", &SpatialEditor::_menu_item_pressed); ClassDB::bind_method("_xform_dialog_action", &SpatialEditor::_xform_dialog_action); - ClassDB::bind_method("_instance_scene", &SpatialEditor::_instance_scene); ClassDB::bind_method("_get_editor_data", &SpatialEditor::_get_editor_data); ClassDB::bind_method("_request_gizmo", &SpatialEditor::_request_gizmo); ClassDB::bind_method("_default_light_angle_input", &SpatialEditor::_default_light_angle_input); @@ -3399,7 +3496,7 @@ void SpatialEditor::clear() { settings_znear->set_value(EDITOR_DEF("editors/3d/default_z_near", 0.1)); settings_zfar->set_value(EDITOR_DEF("editors/3d/default_z_far", 1500.0)); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < VIEWPORTS_COUNT; i++) { viewports[i]->reset(); } @@ -3415,7 +3512,7 @@ void SpatialEditor::clear() { } } - for (int i = 0; i < 4; i++) { + for (int i = 0; i < VIEWPORTS_COUNT; i++) { viewports[i]->view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(SpatialEditorViewport::VIEW_AUDIO_LISTENER), i == 0); viewports[i]->viewport->set_as_audio_listener(i == 0); @@ -3520,12 +3617,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds); tool_button[TOOL_MODE_SCALE]->set_tooltip(TTR("Scale Mode (R)")); - instance_button = memnew(Button); - hbc_menu->add_child(instance_button); - instance_button->set_flat(true); - instance_button->connect("pressed", this, "_instance_scene"); - instance_button->hide(); - VSeparator *vs = memnew(VSeparator); hbc_menu->add_child(vs); @@ -3553,6 +3644,13 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F); ED_SHORTCUT("spatial_editor/align_selection_with_view", TTR("Align Selection With View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_F); + ED_SHORTCUT("spatial_editor/tool_select", TTR("Tool Select"), KEY_Q); + ED_SHORTCUT("spatial_editor/tool_move", TTR("Tool Move"), KEY_W); + ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Tool Rotate"), KEY_E); + ED_SHORTCUT("spatial_editor/tool_scale", TTR("Tool Scale"), KEY_R); + + ED_SHORTCUT("spatial_editor/display_wireframe", TTR("Display Wireframe"), KEY_Z); + PopupMenu *p; transform_menu = memnew(MenuButton); @@ -3618,7 +3716,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { viewport_base = memnew(Control); shader_split->add_child(viewport_base); viewport_base->set_v_size_flags(SIZE_EXPAND_FILL); - for (int i = 0; i < 4; i++) { + for (int i = 0; i < VIEWPORTS_COUNT; i++) { viewports[i] = memnew(SpatialEditorViewport(this, editor, i)); viewports[i]->connect("toggle_maximize_view", this, "_toggle_maximize_view"); diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 4302927426..01435028ac 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -114,6 +114,8 @@ private: bool orthogonal; float gizmo_scale; + bool freelook_active; + struct _RayResult { Spatial *item; @@ -168,7 +170,8 @@ private: NAVIGATION_NONE, NAVIGATION_PAN, NAVIGATION_ZOOM, - NAVIGATION_ORBIT + NAVIGATION_ORBIT, + NAVIGATION_LOOK }; enum TransformMode { TRANSFORM_NONE, @@ -203,8 +206,6 @@ private: struct Cursor { - Vector3 cursor_pos; - Vector3 pos; float x_rot, y_rot, distance; bool region_select; @@ -217,6 +218,10 @@ private: } } cursor; + void scale_cursor_distance(real_t scale); + + real_t zoom_indicator_delay; + RID move_gizmo_instance[3], rotate_gizmo_instance[3]; String last_message; @@ -227,10 +232,12 @@ private: // void _update_camera(); + Transform to_camera_transform(const Cursor &p_cursor) const; void _draw(); void _smouseenter(); void _sinput(const InputEvent &p_ie); + void _update_freelook(real_t delta); SpatialEditor *spatial_editor; Camera *previewing; @@ -243,6 +250,7 @@ private: void _selection_result_pressed(int); void _selection_menu_hide(); void _list_select(InputEventMouseButton b); + Point2i _get_warped_mouse_motion(const InputEventMouseMotion &p_ev_mouse_motion) const; protected: void _notification(int p_what); @@ -255,6 +263,7 @@ public: void set_state(const Dictionary &p_state); Dictionary get_state() const; void reset(); + bool is_freelook_active() const { return freelook_active; } void focus_selection(); @@ -295,11 +304,13 @@ public: }; private: + static const unsigned int VIEWPORTS_COUNT = 4; + EditorNode *editor; EditorSelection *editor_selection; Control *viewport_base; - SpatialEditorViewport *viewports[4]; + SpatialEditorViewport *viewports[VIEWPORTS_COUNT]; VSplitContainer *shader_split; HSplitContainer *palette_split; @@ -385,7 +396,6 @@ private: }; Button *tool_button[TOOL_MAX]; - Button *instance_button; MenuButton *transform_menu; MenuButton *view_menu; @@ -456,6 +466,8 @@ private: void _update_default_light_angle(); void _default_light_angle_input(const InputEvent &p_event); + bool is_any_freelook_active() const; + protected: void _notification(int p_what); //void _gui_input(InputEvent p_event); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index 90db23d236..40ffb8e246 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -229,6 +229,8 @@ void ProjectExportDialog::_edit_preset(int p_index) { } if (needs_templates) export_templates_error->show(); + else + export_templates_error->hide(); export_button->set_disabled(true); diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index 901b259960..835243e401 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -362,8 +362,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { else { String path = selected->get_filename(); script_create_dialog->config(selected->get_class(), path); - script_create_dialog->popup_centered(Size2(300, 290)); - //script_create_dialog->popup_centered_minsize(); + script_create_dialog->popup_centered(); } } break; diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index 15c540e132..1e86d8db4b 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -29,12 +29,23 @@ /*************************************************************************/ #include "script_create_dialog.h" +#include "editor/editor_scale.h" #include "editor_file_system.h" #include "global_config.h" #include "io/resource_saver.h" #include "os/file_access.h" #include "script_language.h" +void ScriptCreateDialog::_notification(int p_what) { + + switch (p_what) { + case NOTIFICATION_ENTER_TREE: { + path_button->set_icon(get_icon("Folder", "EditorIcons")); + parent_browse_button->set_icon(get_icon("Folder", "EditorIcons")); + } + } +} + void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_path) { class_name->set_text(""); @@ -46,6 +57,8 @@ void ScriptCreateDialog::config(const String &p_base_name, const String &p_base_ initial_bp = ""; file_path->set_text(""); } + _lang_changed(current_language); + _parent_name_changed(parent_name->get_text()); _class_name_changed(""); _path_changed(file_path->get_text()); } @@ -85,54 +98,40 @@ bool ScriptCreateDialog::_validate(const String &p_string) { void ScriptCreateDialog::_class_name_changed(const String &p_name) { - if (!_validate(parent_name->get_text())) { - error_label->set_text(TTR("Invalid parent class name or path")); - error_label->add_color_override("font_color", Color(1, 0.4, 0.0, 0.8)); - } else if (class_name->is_editable()) { - if (class_name->get_text() == "") { - error_label->set_text(TTR("Valid chars:") + " a-z A-Z 0-9 _"); - error_label->add_color_override("font_color", Color(1, 1, 1, 0.6)); - } else if (!_validate(class_name->get_text())) { - error_label->set_text(TTR("Invalid class name")); - error_label->add_color_override("font_color", Color(1, 0.2, 0.2, 0.8)); - } else { - error_label->set_text(TTR("Valid name")); - error_label->add_color_override("font_color", Color(0, 1.0, 0.8, 0.8)); - } + if (_validate(class_name->get_text())) { + is_class_name_valid = true; } else { + is_class_name_valid = false; + } + _update_dialog(); +} - error_label->set_text(TTR("N/A")); - error_label->add_color_override("font_color", Color(0, 1.0, 0.8, 0.8)); +void ScriptCreateDialog::_parent_name_changed(const String &p_parent) { + + if (_validate(parent_name->get_text())) { + is_parent_name_valid = true; + } else { + is_parent_name_valid = false; } + _update_dialog(); } void ScriptCreateDialog::ok_pressed() { - if (create_new) { + if (is_new_script_created) { _create_new(); } else { _load_exist(); } - create_new = true; - _update_controls(); + is_new_script_created = true; + _update_dialog(); } void ScriptCreateDialog::_create_new() { - if (class_name->is_editable() && !_validate(class_name->get_text())) { - alert->set_text(TTR("Class name is invalid!")); - alert->popup_centered_minsize(); - return; - } - if (!_validate(parent_name->get_text())) { - alert->set_text(TTR("Parent class name is invalid!")); - alert->popup_centered_minsize(); - return; - } - String cname; - if (class_name->is_editable()) + if (has_named_classes) cname = class_name->get_text(); Ref<Script> scr = ScriptServer::get_language(language_menu->get_selected())->get_template(cname, parent_name->get_text()); @@ -143,18 +142,13 @@ void ScriptCreateDialog::_create_new() { if (cname != "") scr->set_name(cname); - if (!internal->is_pressed()) { + if (!is_built_in) { String lpath = GlobalConfig::get_singleton()->localize_path(file_path->get_text()); scr->set_path(lpath); - if (!path_valid) { - alert->set_text(TTR("Invalid path!")); - alert->popup_centered_minsize(); - return; - } Error err = ResourceSaver::save(lpath, scr, ResourceSaver::FLAG_CHANGE_PATH); if (err != OK) { - alert->set_text(TTR("Could not create script in filesystem.")); - alert->popup_centered_minsize(); + alert->set_text(TTR("Error - Could not create script in filesystem.")); + alert->popup_centered(); return; } } @@ -168,9 +162,9 @@ void ScriptCreateDialog::_load_exist() { String path = file_path->get_text(); RES p_script = ResourceLoader::load(path, "Script"); if (p_script.is_null()) { - alert->get_ok()->set_text(TTR("Ugh")); + alert->get_ok()->set_text(TTR("OK")); alert->set_text(vformat(TTR("Error loading script from %s"), path)); - alert->popup_centered_minsize(); + alert->popup_centered(); return; } @@ -182,55 +176,59 @@ void ScriptCreateDialog::_lang_changed(int l) { l = language_menu->get_selected(); if (ScriptServer::get_language(l)->has_named_classes()) { - class_name->set_editable(true); + has_named_classes = true; } else { - class_name->set_editable(false); + has_named_classes = false; } if (ScriptServer::get_language(l)->can_inherit_from_file()) { - parent_browse_button->show(); + can_inherit_from_file = true; } else { - parent_browse_button->hide(); + can_inherit_from_file = false; } String selected_ext = "." + ScriptServer::get_language(l)->get_extension(); String path = file_path->get_text(); String extension = ""; - if (path.find(".") >= 0) { - extension = path.get_extension(); - } - - if (extension.length() == 0) { - // add extension if none - path += selected_ext; - _path_changed(path); - } else { - // change extension by selected language - List<String> extensions; - // get all possible extensions for script - for (int l = 0; l < language_menu->get_item_count(); l++) { - ScriptServer::get_language(l)->get_recognized_extensions(&extensions); + if (path != "") { + if (path.find(".") >= 0) { + extension = path.get_extension(); } - for (List<String>::Element *E = extensions.front(); E; E = E->next()) { - if (E->get().nocasecmp_to(extension) == 0) { - path = path.get_basename() + selected_ext; - _path_changed(path); - break; + if (extension.length() == 0) { + // add extension if none + path += selected_ext; + _path_changed(path); + } else { + // change extension by selected language + List<String> extensions; + // get all possible extensions for script + for (int l = 0; l < language_menu->get_item_count(); l++) { + ScriptServer::get_language(l)->get_recognized_extensions(&extensions); + } + + for (List<String>::Element *E = extensions.front(); E; E = E->next()) { + if (E->get().nocasecmp_to(extension) == 0) { + path = path.get_basename() + selected_ext; + _path_changed(path); + break; + } } } + file_path->set_text(path); } - file_path->set_text(path); - _class_name_changed(class_name->get_text()); + + _update_dialog(); } void ScriptCreateDialog::_built_in_pressed() { if (internal->is_pressed()) { - path_vb->hide(); + is_built_in = true; } else { - path_vb->show(); + is_built_in = false; } + _update_dialog(); } void ScriptCreateDialog::_browse_path(bool browse_parent) { @@ -269,40 +267,45 @@ void ScriptCreateDialog::_file_selected(const String &p_file) { void ScriptCreateDialog::_path_changed(const String &p_path) { - path_valid = false; + is_path_valid = false; + is_new_script_created = true; String p = p_path; if (p == "") { - - path_error_label->set_text(TTR("Path is empty")); - path_error_label->add_color_override("font_color", Color(1, 0.4, 0.0, 0.8)); + _msg_path_valid(false, TTR("Path is empty")); + _update_dialog(); return; } p = GlobalConfig::get_singleton()->localize_path(p); if (!p.begins_with("res://")) { - - path_error_label->set_text(TTR("Path is not local")); - path_error_label->add_color_override("font_color", Color(1, 0.4, 0.0, 0.8)); + _msg_path_valid(false, TTR("Path is not local")); + _update_dialog(); return; } if (p.find("/") || p.find("\\")) { DirAccess *d = DirAccess::create(DirAccess::ACCESS_RESOURCES); - if (d->change_dir(p.get_base_dir()) != OK) { - - path_error_label->set_text(TTR("Invalid base path")); - path_error_label->add_color_override("font_color", Color(1, 0.4, 0.0, 0.8)); + _msg_path_valid(false, TTR("Invalid base path")); memdelete(d); + _update_dialog(); return; } memdelete(d); } - FileAccess *f = FileAccess::create(FileAccess::ACCESS_RESOURCES); - create_new = !f->file_exists(p); + /* Does file already exist */ + + DirAccess *f = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (f->file_exists(p) && !(f->current_is_dir())) { + is_new_script_created = false; + is_path_valid = true; + } memdelete(f); + _update_dialog(); + + /* Check file extension */ String extension = p.get_extension(); List<String> extensions; @@ -313,45 +316,156 @@ void ScriptCreateDialog::_path_changed(const String &p_path) { } bool found = false; + bool match = false; int index = 0; for (List<String>::Element *E = extensions.front(); E; E = E->next()) { if (E->get().nocasecmp_to(extension) == 0) { - language_menu->select(index); // change Language option by extension + //FIXME (?) - changing language this way doesn't update controls, needs rework + //language_menu->select(index); // change Language option by extension found = true; + if (E->get() == ScriptServer::get_language(language_menu->get_selected())->get_extension()) { + match = true; + } break; } index++; } if (!found) { - path_error_label->set_text(TTR("Invalid extension")); - path_error_label->add_color_override("font_color", Color(1, 0.4, 0.0, 0.8)); + _msg_path_valid(false, TTR("Invalid extension")); + _update_dialog(); + return; + } + + if (!match) { + _msg_path_valid(false, TTR("Wrong extension chosen")); + _update_dialog(); return; } - _update_controls(); + /* All checks passed */ + + is_path_valid = true; + _update_dialog(); +} + +void ScriptCreateDialog::_msg_script_valid(bool valid, const String &p_msg) { + + error_label->set_text(TTR(p_msg)); + if (valid) { + error_label->add_color_override("font_color", Color(0, 1.0, 0.8, 0.8)); + } else { + error_label->add_color_override("font_color", Color(1, 0.2, 0.2, 0.8)); + } +} - path_error_label->add_color_override("font_color", Color(0, 1.0, 0.8, 0.8)); +void ScriptCreateDialog::_msg_path_valid(bool valid, const String &p_msg) { - path_valid = true; + path_error_label->set_text(TTR(p_msg)); + if (valid) { + path_error_label->add_color_override("font_color", Color(0, 1.0, 0.8, 0.8)); + } else { + path_error_label->add_color_override("font_color", Color(1, 0.4, 0.0, 0.8)); + } } -void ScriptCreateDialog::_update_controls() { +void ScriptCreateDialog::_update_dialog() { + + bool script_ok = true; + + /* "Add Script Dialog" gui logic and script checks */ + + // Is Script Valid (order from top to bottom) + get_ok()->set_disabled(true); + if (!is_built_in) { + if (!is_path_valid) { + _msg_script_valid(false, TTR("Invalid Path")); + script_ok = false; + } + } + if (has_named_classes && (!is_class_name_valid)) { + _msg_script_valid(false, TTR("Invalid class name")); + script_ok = false; + } + if (!is_parent_name_valid) { + _msg_script_valid(false, TTR("Invalid inherited parent name or path")); + script_ok = false; + } + if (script_ok) { + _msg_script_valid(true, TTR("Script valid")); + get_ok()->set_disabled(false); + } + + /* Does script have named classes */ - if (create_new) { - path_error_label->set_text(TTR("Create new script")); + if (has_named_classes) { + if (is_new_script_created) { + class_name->set_editable(true); + class_name->set_placeholder(TTR("Allowed: a-z, A-Z, 0-9 and _")); + class_name->set_placeholder_alpha(0.3); + } else { + class_name->set_editable(false); + } + } else { + class_name->set_editable(false); + class_name->set_placeholder(TTR("N/A")); + class_name->set_placeholder_alpha(1); + } + + /* Can script inherit from a file */ + + if (can_inherit_from_file) { + parent_browse_button->set_disabled(false); + } else { + parent_browse_button->set_disabled(true); + } + + /* Is script Built-in */ + + if (is_built_in) { + file_path->set_editable(false); + path_button->set_disabled(true); + re_check_path = true; + } else { + file_path->set_editable(true); + path_button->set_disabled(false); + if (re_check_path) { + re_check_path = false; + _path_changed(file_path->get_text()); + } + } + + /* Is Script created or loaded from existing file */ + + if (is_new_script_created) { + // New Script Created get_ok()->set_text(TTR("Create")); + parent_name->set_editable(true); + parent_browse_button->set_disabled(false); + internal->set_disabled(false); + if (is_built_in) { + _msg_path_valid(true, TTR("Built-in script (into scene file)")); + } else { + if (script_ok) { + _msg_path_valid(true, TTR("Create new script file")); + } + } } else { - path_error_label->set_text(TTR("Load existing script")); + // Script Loaded get_ok()->set_text(TTR("Load")); + parent_name->set_editable(false); + parent_browse_button->set_disabled(true); + internal->set_disabled(true); + if (script_ok) { + _msg_path_valid(true, TTR("Load existing script file")); + } } - parent_name->set_editable(create_new); - internal->set_disabled(!create_new); } void ScriptCreateDialog::_bind_methods() { ClassDB::bind_method("_class_name_changed", &ScriptCreateDialog::_class_name_changed); + ClassDB::bind_method("_parent_name_changed", &ScriptCreateDialog::_parent_name_changed); ClassDB::bind_method("_lang_changed", &ScriptCreateDialog::_lang_changed); ClassDB::bind_method("_built_in_pressed", &ScriptCreateDialog::_built_in_pressed); ClassDB::bind_method("_browse_path", &ScriptCreateDialog::_browse_path); @@ -362,37 +476,100 @@ void ScriptCreateDialog::_bind_methods() { ScriptCreateDialog::ScriptCreateDialog() { - /* SNAP DIALOG */ + editor_settings = EditorSettings::get_singleton(); + GridContainer *gc = memnew(GridContainer); VBoxContainer *vb = memnew(VBoxContainer); - add_child(vb); - //set_child_rect(vb); + HBoxContainer *hb = memnew(HBoxContainer); + Label *l = memnew(Label); + Control *empty = memnew(Control); + Control *empty_h = memnew(Control); + Control *empty_v = memnew(Control); + PanelContainer *pc = memnew(PanelContainer); - class_name = memnew(LineEdit); - VBoxContainer *vb2 = memnew(VBoxContainer); - vb2->add_child(class_name); - class_name->connect("text_changed", this, "_class_name_changed"); - error_label = memnew(Label); - error_label->set_text("valid chars: a-z A-Z 0-9 _"); - error_label->set_align(Label::ALIGN_CENTER); - vb2->add_child(error_label); - vb->add_margin_child(TTR("Class Name:"), vb2); + /* DIALOG */ - HBoxContainer *hb1 = memnew(HBoxContainer); - parent_name = memnew(LineEdit); - parent_name->connect("text_changed", this, "_class_name_changed"); - parent_name->set_h_size_flags(SIZE_EXPAND_FILL); - hb1->add_child(parent_name); - parent_browse_button = memnew(Button); - parent_browse_button->set_text(" .. "); - parent_browse_button->connect("pressed", this, "_browse_path", varray(true)); - hb1->add_child(parent_browse_button); - parent_browse_button->hide(); - vb->add_margin_child(TTR("Inherits:"), hb1); - is_browsing_parent = false; + /* Main Controls */ + + gc = memnew(GridContainer); + gc->set_columns(2); + + /* Error Stylebox Background */ + + StyleBoxFlat *sb = memnew(StyleBoxFlat); + sb->set_bg_color(Color(0, 0, 0, 0.05)); + sb->set_light_color(Color(1, 1, 1, 0.05)); + sb->set_dark_color(Color(1, 1, 1, 0.05)); + sb->set_border_blend(false); + sb->set_border_size(1); + sb->set_default_margin(MARGIN_TOP, 10.0 * EDSCALE); + sb->set_default_margin(MARGIN_BOTTOM, 10.0 * EDSCALE); + sb->set_default_margin(MARGIN_LEFT, 10.0 * EDSCALE); + sb->set_default_margin(MARGIN_RIGHT, 10.0 * EDSCALE); + + /* Error Messages Field */ + + vb = memnew(VBoxContainer); + + hb = memnew(HBoxContainer); + l = memnew(Label); + l->set_text(" - "); + hb->add_child(l); + error_label = memnew(Label); + error_label->set_text(TTR("Error!")); + error_label->set_align(Label::ALIGN_LEFT); + hb->add_child(error_label); + vb->add_child(hb); + + hb = memnew(HBoxContainer); + l = memnew(Label); + l->set_text(" - "); + hb->add_child(l); + path_error_label = memnew(Label); + path_error_label->set_text(TTR("Error!")); + path_error_label->set_align(Label::ALIGN_LEFT); + hb->add_child(path_error_label); + vb->add_child(hb); + + pc = memnew(PanelContainer); + pc->set_h_size_flags(Control::SIZE_FILL); + pc->add_style_override("panel", sb); + pc->add_child(vb); + + /* Margins */ + + empty_h = memnew(Control); + empty_h->set_h_size_flags(Control::SIZE_EXPAND_FILL); + empty_h->set_v_size_flags(Control::SIZE_EXPAND_FILL); + empty_h->set_custom_minimum_size(Size2(0, 10 * EDSCALE)); + empty_v = memnew(Control); + empty_v->set_h_size_flags(Control::SIZE_EXPAND_FILL); + empty_v->set_v_size_flags(Control::SIZE_EXPAND_FILL); + empty_v->set_custom_minimum_size(Size2(10, 0 * EDSCALE)); + + vb = memnew(VBoxContainer); + vb->add_child(empty_h->duplicate()); + vb->add_child(gc); + vb->add_child(empty_h->duplicate()); + vb->add_child(pc); + vb->add_child(empty_h->duplicate()); + hb = memnew(HBoxContainer); + hb->add_child(empty_v->duplicate()); + hb->add_child(vb); + hb->add_child(empty_v->duplicate()); + + add_child(hb); + + /* Language */ language_menu = memnew(OptionButton); - vb->add_margin_child(TTR("Language"), language_menu); + language_menu->set_custom_minimum_size(Size2(250, 0) * EDSCALE); + language_menu->set_h_size_flags(SIZE_EXPAND_FILL); + l = memnew(Label); + l->set_text(TTR("Language")); + l->set_align(Label::ALIGN_RIGHT); + gc->add_child(l); + gc->add_child(language_menu); int default_lang = 0; for (int i = 0; i < ScriptServer::get_language_count(); i++) { @@ -404,60 +581,108 @@ ScriptCreateDialog::ScriptCreateDialog() { } } - editor_settings = EditorSettings::get_singleton(); String last_selected_language = editor_settings->get_project_metadata("script_setup", "last_selected_language", ""); if (last_selected_language != "") { for (int i = 0; i < language_menu->get_item_count(); i++) { if (language_menu->get_item_text(i) == last_selected_language) { language_menu->select(i); + current_language = i; break; } } } else { language_menu->select(default_lang); + current_language = default_lang; } language_menu->connect("item_selected", this, "_lang_changed"); - //parent_name->set_text(); + /* Inherits */ - vb2 = memnew(VBoxContainer); - path_vb = memnew(VBoxContainer); - vb2->add_child(path_vb); + hb = memnew(HBoxContainer); + hb->set_h_size_flags(SIZE_EXPAND_FILL); + parent_name = memnew(LineEdit); + parent_name->connect("text_changed", this, "_parent_name_changed"); + parent_name->set_h_size_flags(SIZE_EXPAND_FILL); + hb->add_child(parent_name); + parent_browse_button = memnew(Button); + parent_browse_button->set_flat(true); + parent_browse_button->connect("pressed", this, "_browse_path", varray(true)); + hb->add_child(parent_browse_button); + l = memnew(Label); + l->set_text(TTR("Inherits")); + l->set_align(Label::ALIGN_RIGHT); + gc->add_child(l); + gc->add_child(hb); + is_browsing_parent = false; - HBoxContainer *hbc = memnew(HBoxContainer); - file_path = memnew(LineEdit); - file_path->connect("text_changed", this, "_path_changed"); - hbc->add_child(file_path); - file_path->set_h_size_flags(SIZE_EXPAND_FILL); - Button *b = memnew(Button); - b->set_text(" .. "); - b->connect("pressed", this, "_browse_path", varray(false)); - hbc->add_child(b); - path_vb->add_child(hbc); - path_error_label = memnew(Label); - path_vb->add_child(path_error_label); - path_error_label->set_text(TTR("Error!")); - path_error_label->set_align(Label::ALIGN_CENTER); + /* Class Name */ - internal = memnew(CheckButton); - internal->set_text(TTR("Built-In Script")); - vb2->add_child(internal); - internal->connect("pressed", this, "_built_in_pressed"); + class_name = memnew(LineEdit); + class_name->connect("text_changed", this, "_class_name_changed"); + class_name->set_h_size_flags(SIZE_EXPAND_FILL); + l = memnew(Label); + l->set_text(TTR("Class Name")); + l->set_align(Label::ALIGN_RIGHT); + gc->add_child(l); + gc->add_child(class_name); - vb->add_margin_child(TTR("Path:"), vb2); + /* Built-in Script */ - set_size(Size2(200, 150)); - set_hide_on_ok(false); - set_title(TTR("Attach Node Script")); + internal = memnew(CheckButton); + internal->connect("pressed", this, "_built_in_pressed"); + hb = memnew(HBoxContainer); + empty = memnew(Control); + hb->add_child(internal); + hb->add_child(empty); + l = memnew(Label); + l->set_text(TTR("Built-in Script")); + l->set_align(Label::ALIGN_RIGHT); + gc->add_child(l); + gc->add_child(hb); + + /* Path */ + + hb = memnew(HBoxContainer); + file_path = memnew(LineEdit); + file_path->connect("text_changed", this, "_path_changed"); + file_path->set_h_size_flags(SIZE_EXPAND_FILL); + hb->add_child(file_path); + path_button = memnew(Button); + path_button->set_flat(true); + path_button->connect("pressed", this, "_browse_path", varray(false)); + hb->add_child(path_button); + l = memnew(Label); + l->set_text(TTR("Path")); + l->set_align(Label::ALIGN_RIGHT); + gc->add_child(l); + gc->add_child(hb); + + /* Dialog Setup */ file_browse = memnew(EditorFileDialog); file_browse->connect("file_selected", this, "_file_selected"); add_child(file_browse); get_ok()->set_text(TTR("Create")); alert = memnew(AcceptDialog); + alert->set_as_minsize(); + alert->get_label()->set_autowrap(true); + alert->get_label()->set_align(Label::ALIGN_CENTER); + alert->get_label()->set_valign(Label::VALIGN_CENTER); + alert->get_label()->set_custom_minimum_size(Size2(325, 60) * EDSCALE); add_child(alert); - _lang_changed(0); - create_new = true; + set_as_minsize(); + set_hide_on_ok(false); + set_title(TTR("Attach Node Script")); + + is_parent_name_valid = false; + is_class_name_valid = false; + is_path_valid = false; + + has_named_classes = false; + can_inherit_from_file = false; + is_built_in = false; + + is_new_script_created = true; } diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 113d4a468c..862d4f88f2 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -34,8 +34,10 @@ #include "editor/editor_settings.h" #include "scene/gui/check_button.h" #include "scene/gui/dialogs.h" +#include "scene/gui/grid_container.h" #include "scene/gui/line_edit.h" #include "scene/gui/option_button.h" +#include "scene/gui/panel_container.h" class ScriptCreateDialog : public ConfirmationDialog { GDCLASS(ScriptCreateDialog, ConfirmationDialog); @@ -47,6 +49,7 @@ class ScriptCreateDialog : public ConfirmationDialog { Button *parent_browse_button; OptionButton *language_menu; LineEdit *file_path; + Button *path_button; EditorFileDialog *file_browse; CheckButton *internal; VBoxContainer *path_vb; @@ -56,20 +59,33 @@ class ScriptCreateDialog : public ConfirmationDialog { bool is_browsing_parent; String initial_bp; EditorSettings *editor_settings; + bool is_new_script_created; + bool is_path_valid; + bool has_named_classes; + bool can_inherit_from_file; + bool is_parent_name_valid; + bool is_class_name_valid; + bool is_built_in; + int current_language; + bool re_check_path; void _path_changed(const String &p_path = String()); void _lang_changed(int l = 0); void _built_in_pressed(); bool _validate(const String &p_strin); void _class_name_changed(const String &p_name); + void _parent_name_changed(const String &p_parent); void _browse_path(bool browse_parent); void _file_selected(const String &p_file); virtual void ok_pressed(); void _create_new(); void _load_exist(); - void _update_controls(); + void _msg_script_valid(bool valid, const String &p_msg = String()); + void _msg_path_valid(bool valid, const String &p_msg = String()); + void _update_dialog(); protected: + void _notification(int p_what); static void _bind_methods(); public: diff --git a/editor/script_editor_debugger.cpp b/editor/script_editor_debugger.cpp index 2bc00c62fb..ebf4b1cf3a 100644 --- a/editor/script_editor_debugger.cpp +++ b/editor/script_editor_debugger.cpp @@ -90,11 +90,13 @@ public: return ""; } - void add_property(const String &p_name, const Variant &p_value) { + void add_property(const String &p_name, const Variant &p_value, const PropertyHint &p_hint, const String p_hint_string) { PropertyInfo pinfo; pinfo.name = p_name; pinfo.type = p_value.get_type(); + pinfo.hint = p_hint; + pinfo.hint_string = p_hint_string; props.push_back(pinfo); values[p_name] = p_value; } @@ -437,7 +439,11 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da inspected_object->last_edited_id = id; - inspect_properties->edit(inspected_object); + if (tabs->get_current_tab() == 2) { + inspect_properties->edit(inspected_object); + } else { + editor->push_item(inspected_object); + } } else if (p_msg == "message:video_mem") { @@ -499,13 +505,20 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da String n = p_data[ofs + i * 2 + 0]; Variant v = p_data[ofs + i * 2 + 1]; + PropertyHint h = PROPERTY_HINT_NONE; + String hs = String(); if (n.begins_with("*")) { n = n.substr(1, n.length()); + h = PROPERTY_HINT_OBJECT_ID; + String s = v; + s = s.replace("[", ""); + hs = s.get_slice(":", 0); + v = s.get_slice(":", 1).to_int(); } - variables->add_property("members/" + n, v); + variables->add_property("members/" + n, v, h, hs); } ofs += mcount * 2; @@ -516,13 +529,20 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, const Array &p_da String n = p_data[ofs + i * 2 + 0]; Variant v = p_data[ofs + i * 2 + 1]; + PropertyHint h = PROPERTY_HINT_NONE; + String hs = String(); if (n.begins_with("*")) { n = n.substr(1, n.length()); + h = PROPERTY_HINT_OBJECT_ID; + String s = v; + s = s.replace("[", ""); + hs = s.get_slice(":", 0); + v = s.get_slice(":", 1).to_int(); } - variables->add_property("locals/" + n, v); + variables->add_property("locals/" + n, v, h, hs); } variables->update(); @@ -1056,6 +1076,9 @@ void ScriptEditorDebugger::stop() { EditorNode::get_singleton()->get_pause_button()->set_pressed(false); EditorNode::get_singleton()->get_pause_button()->set_disabled(true); + //avoid confusion when stopped debugging but an object is still edited + EditorNode::get_singleton()->push_item(NULL); + if (hide_on_stop) { if (is_visible_in_tree()) EditorNode::get_singleton()->hide_bottom_panel(); @@ -1636,6 +1659,7 @@ ScriptEditorDebugger::ScriptEditorDebugger(EditorNode *p_editor) { inspector->get_scene_tree()->set_column_title(0, TTR("Variable")); inspector->set_enable_capitalize_paths(false); inspector->set_read_only(true); + inspector->connect("object_id_selected", this, "_scene_tree_property_select_object"); sc->add_child(inspector); server = TCP_Server::create_ref(); diff --git a/editor/translations/ar.po b/editor/translations/ar.po index 766d8f9676..867302b657 100644 --- a/editor/translations/ar.po +++ b/editor/translations/ar.po @@ -1,5 +1,6 @@ # Arabic translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # athomield <athomield@hotmail.com>, 2017. diff --git a/editor/translations/bg.po b/editor/translations/bg.po index b23fa3a8fb..f884b33773 100644 --- a/editor/translations/bg.po +++ b/editor/translations/bg.po @@ -1,5 +1,6 @@ # Bulgarian translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Bojidar Marinov <bojidar.marinov.bg@gmail.com>, 2016. diff --git a/editor/translations/bn.po b/editor/translations/bn.po index 224c00cf5d..3e4dec7656 100644 --- a/editor/translations/bn.po +++ b/editor/translations/bn.po @@ -1,5 +1,6 @@ # Bengali translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Abu Md. Maruf Sarker <maruf.webdev@gmail.com>, 2016-2017. diff --git a/editor/translations/ca.po b/editor/translations/ca.po index 581e862716..6d7b245e58 100644 --- a/editor/translations/ca.po +++ b/editor/translations/ca.po @@ -1,5 +1,6 @@ # Catalan translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Roger BR <drai_kin@hotmail.com>, 2016. diff --git a/editor/translations/cs.po b/editor/translations/cs.po index 89d88a234f..4643a9ac21 100644 --- a/editor/translations/cs.po +++ b/editor/translations/cs.po @@ -1,5 +1,6 @@ # Czech translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Jan 'spl!te' Kondelík <j.kondelik@centrum.cz>, 2016. diff --git a/editor/translations/da.po b/editor/translations/da.po index b84be76247..ba9d018e5a 100644 --- a/editor/translations/da.po +++ b/editor/translations/da.po @@ -1,5 +1,6 @@ # Danish translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # David Lamhauge <davidlamhauge@gmail.com>, 2016. diff --git a/editor/translations/de.po b/editor/translations/de.po index ba6805d1f1..a10eaefa29 100644 --- a/editor/translations/de.po +++ b/editor/translations/de.po @@ -1,5 +1,6 @@ # German translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Alexander Mahr <alex.mahr@gmail.com>, 2016. diff --git a/editor/translations/de_CH.po b/editor/translations/de_CH.po index aeae6a5537..183f09e9a6 100644 --- a/editor/translations/de_CH.po +++ b/editor/translations/de_CH.po @@ -1,5 +1,6 @@ # Swiss High German translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Christian Fisch <christian.fiesel@gmail.com>, 2016. diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot index 5b62f132fa..5f50c159b8 100644 --- a/editor/translations/editor.pot +++ b/editor/translations/editor.pot @@ -1,5 +1,6 @@ # LANGUAGE translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. diff --git a/editor/translations/el.po b/editor/translations/el.po index 292c5a6fd3..0879b693ff 100644 --- a/editor/translations/el.po +++ b/editor/translations/el.po @@ -1,5 +1,6 @@ # Greek translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # gtsiam <gtsiam@windowslive.com>, 2017. diff --git a/editor/translations/es.po b/editor/translations/es.po index a7b9553892..f01c84718b 100644 --- a/editor/translations/es.po +++ b/editor/translations/es.po @@ -1,5 +1,6 @@ # Spanish translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Alejandro Alvarez <eliluminado00@gmail.com>, 2017. diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po index 6c9579916f..f826517b27 100644 --- a/editor/translations/es_AR.po +++ b/editor/translations/es_AR.po @@ -1,5 +1,6 @@ # Spanish (Argentina) translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Lisandro Lorea <lisandrolorea@gmail.com>, 2016-2017. diff --git a/editor/translations/extract.py b/editor/translations/extract.py index 616fec17a0..5e6c894936 100755 --- a/editor/translations/extract.py +++ b/editor/translations/extract.py @@ -38,7 +38,8 @@ unique_str = [] unique_loc = {} main_po = """ # LANGUAGE translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # FIRST AUTHOR <EMAIL@ADDRESS>, YEAR. diff --git a/editor/translations/fa.po b/editor/translations/fa.po index 2ec9b18d78..e8402fcb25 100644 --- a/editor/translations/fa.po +++ b/editor/translations/fa.po @@ -1,5 +1,6 @@ # Persian translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # alabd14313 <alabd14313@yahoo.com>, 2016. diff --git a/editor/translations/fr.po b/editor/translations/fr.po index 1418e6f493..8db0cf2555 100644 --- a/editor/translations/fr.po +++ b/editor/translations/fr.po @@ -1,5 +1,6 @@ # French translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Brice <bbric@free.fr>, 2016. diff --git a/editor/translations/hu.po b/editor/translations/hu.po index 8cb6c2caf1..2d1b36d2ea 100644 --- a/editor/translations/hu.po +++ b/editor/translations/hu.po @@ -1,5 +1,6 @@ # Hungarian translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Varga Dániel <danikah.danikah@gmail.com>, 2016. diff --git a/editor/translations/id.po b/editor/translations/id.po index 2126d324dd..2abf4090c8 100644 --- a/editor/translations/id.po +++ b/editor/translations/id.po @@ -1,5 +1,6 @@ # Indonesian translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Abdul Aziz Muslim Alqudsy <abdul.aziz.muslim.alqudsy@gmail.com>, 2016. diff --git a/editor/translations/it.po b/editor/translations/it.po index e055c6996a..08d04d296b 100644 --- a/editor/translations/it.po +++ b/editor/translations/it.po @@ -1,5 +1,6 @@ # Italian translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Dario Bonfanti <bonfi.96@hotmail.it>, 2016-2017. diff --git a/editor/translations/ja.po b/editor/translations/ja.po index f34e0d118b..beeaf264a2 100644 --- a/editor/translations/ja.po +++ b/editor/translations/ja.po @@ -1,5 +1,6 @@ # Japanese translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # akirakido <achts.y@gmail.com>, 2016. diff --git a/editor/translations/ko.po b/editor/translations/ko.po index 769089b860..08b10d2f7a 100644 --- a/editor/translations/ko.po +++ b/editor/translations/ko.po @@ -1,5 +1,6 @@ # Korean translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # 박한얼 (volzhs) <volzhs@gmail.com>, 2016-2017. diff --git a/editor/translations/nb.po b/editor/translations/nb.po index e7a64f501a..7ce577ebfa 100644 --- a/editor/translations/nb.po +++ b/editor/translations/nb.po @@ -1,5 +1,6 @@ # Norwegian Bokmål translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Anonymous <GentleSaucepan@protonmail.com>, 2017. diff --git a/editor/translations/nl.po b/editor/translations/nl.po index 55407145d2..f0d54ebd9d 100644 --- a/editor/translations/nl.po +++ b/editor/translations/nl.po @@ -1,5 +1,6 @@ # Dutch translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Aram Nap <xyphex.aram@gmail.com>, 2017 diff --git a/editor/translations/pl.po b/editor/translations/pl.po index 8eb2e9c884..ccee170c57 100644 --- a/editor/translations/pl.po +++ b/editor/translations/pl.po @@ -1,5 +1,6 @@ # Polish translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # 8-bit Pixel <dawdejw@gmail.com>, 2016. diff --git a/editor/translations/pr.po b/editor/translations/pr.po index 4df9c04664..4629c24f45 100644 --- a/editor/translations/pr.po +++ b/editor/translations/pr.po @@ -1,5 +1,6 @@ # Pirate translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Zion Nimchuk <zionnimchuk@gmail.com>, 2016-2017. diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po index 75be59068c..25055a0b7b 100644 --- a/editor/translations/pt_BR.po +++ b/editor/translations/pt_BR.po @@ -1,5 +1,6 @@ # Portuguese (Brazil) translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Allyson Souza <allyson_as@outlook.com>, 2017. diff --git a/editor/translations/pt_PT.po b/editor/translations/pt_PT.po index 913455b999..fa4629c5c1 100644 --- a/editor/translations/pt_PT.po +++ b/editor/translations/pt_PT.po @@ -1,5 +1,6 @@ # Portuguese (Portugal) translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # António Sarmento <antonio.luis.sarmento@gmail.com>, 2016. diff --git a/editor/translations/ru.po b/editor/translations/ru.po index 9f7aa6e26a..0c4a29fb63 100644 --- a/editor/translations/ru.po +++ b/editor/translations/ru.po @@ -1,5 +1,6 @@ # Russian translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # DimOkGamer <dimokgamer@gmail.com>, 2016-2017. diff --git a/editor/translations/sk.po b/editor/translations/sk.po index 697def1043..b0bee6aa6f 100644 --- a/editor/translations/sk.po +++ b/editor/translations/sk.po @@ -1,5 +1,6 @@ # Slovak translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # J08nY <johnenter@gmail.com>, 2016. diff --git a/editor/translations/sl.po b/editor/translations/sl.po index fad12d7f13..ea634658ce 100644 --- a/editor/translations/sl.po +++ b/editor/translations/sl.po @@ -1,5 +1,6 @@ # Slovenian translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # matevž lapajne <sivar.lapajne@gmail.com>, 2016. diff --git a/editor/translations/th.po b/editor/translations/th.po index 79cdaf6b10..b31532f3bf 100644 --- a/editor/translations/th.po +++ b/editor/translations/th.po @@ -1,5 +1,6 @@ # Thai translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Poommetee Ketson <poommetee@protonmail.com>, 2017. diff --git a/editor/translations/tr.po b/editor/translations/tr.po index 20a794b34a..b4d8975649 100644 --- a/editor/translations/tr.po +++ b/editor/translations/tr.po @@ -1,5 +1,6 @@ # Turkish translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Aprın Çor Tigin <kabusturk38@gmail.com>, 2016-2017. diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po index 651aa62001..ef3e3b30ca 100644 --- a/editor/translations/ur_PK.po +++ b/editor/translations/ur_PK.po @@ -1,5 +1,6 @@ # Urdu (Pakistan) translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Muhammad Ali <ali@codeonion.com>, 2016. diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po index 87ca113ce2..f3afcab79d 100644 --- a/editor/translations/zh_CN.po +++ b/editor/translations/zh_CN.po @@ -1,5 +1,6 @@ # Chinese (China) translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # 纯洁的坏蛋 <tqj.zyy@gmail.com>, 2016. diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po index dfac75ecab..e49582e901 100644 --- a/editor/translations/zh_HK.po +++ b/editor/translations/zh_HK.po @@ -1,5 +1,6 @@ # Chinese (Honk Kong) translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # Wesley (zx-wt) <ZX_WT@ymail.com>, 2016. diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po index 48b76484e0..7836cd2f76 100644 --- a/editor/translations/zh_TW.po +++ b/editor/translations/zh_TW.po @@ -1,5 +1,6 @@ # Chinese (Taiwan) translation of the Godot Engine editor -# Copyright (C) 2016-2017 Juan Linietsky, Ariel Manzur and the Godot community +# Copyright (C) 2007-2017 Juan Linietsky, Ariel Manzur +# Copyright (C) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) # This file is distributed under the same license as the Godot source code. # # popcade <popcade@gmail.com>, 2016. |