diff options
Diffstat (limited to 'editor')
24 files changed, 1046 insertions, 136 deletions
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 7f93917744..8933fd7fe8 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -428,6 +428,13 @@ void ConnectionsDock::_make_or_edit_connection() { bool oshot = connect_dialog->get_oneshot(); cToMake.flags = CONNECT_PERSIST | (defer ? CONNECT_DEFERRED : 0) | (oshot ? CONNECT_ONESHOT : 0); + bool add_script_function = connect_dialog->get_make_callback(); + PoolStringArray script_function_args; + if (add_script_function) { + // pick up args here before "it" is deleted by update_tree + script_function_args = it->get_metadata(0).operator Dictionary()["args"]; + } + if (connect_dialog->is_editing()) { _disconnect(*it); _connect(cToMake); @@ -435,9 +442,12 @@ void ConnectionsDock::_make_or_edit_connection() { _connect(cToMake); } - if (connect_dialog->get_make_callback()) { - PoolStringArray args = it->get_metadata(0).operator Dictionary()["args"]; - editor->emit_signal("script_add_function_request", target, cToMake.method, args); + // IMPORTANT NOTE: _disconnect and _connect cause an update_tree, + // which will delete the object "it" is pointing to + it = NULL; + + if (add_script_function) { + editor->emit_signal("script_add_function_request", target, cToMake.method, script_function_args); hide(); } diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index 7739b08eff..317fffad64 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -409,6 +409,7 @@ void EditorExportPlatform::_edit_files_with_filter(DirAccess *da, const Vector<S String cur_dir = da->get_current_dir().replace("\\", "/"); if (!cur_dir.ends_with("/")) cur_dir += "/"; + String cur_dir_no_prefix = cur_dir.replace("res://", ""); Vector<String> dirs; String f; @@ -417,8 +418,10 @@ void EditorExportPlatform::_edit_files_with_filter(DirAccess *da, const Vector<S dirs.push_back(f); else { String fullpath = cur_dir + f; + // Test also against path without res:// so that filters like `file.txt` can work. + String fullpath_no_prefix = cur_dir_no_prefix + f; for (int i = 0; i < p_filters.size(); ++i) { - if (fullpath.matchn(p_filters[i])) { + if (fullpath.matchn(p_filters[i]) || fullpath_no_prefix.matchn(p_filters[i])) { if (!exclude) { r_list.insert(fullpath); } else { diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp index 17f383c8ae..482b0dec35 100644 --- a/editor/editor_inspector.cpp +++ b/editor/editor_inspector.cpp @@ -91,6 +91,9 @@ void EditorProperty::_notification(int p_what) { Rect2 rect; Rect2 bottom_rect; + right_child_rect = Rect2(); + bottom_child_rect = Rect2(); + { int child_room = size.width * (1.0 - split_ratio); Ref<Font> font = get_font("font", "Tree"); @@ -118,7 +121,8 @@ void EditorProperty::_notification(int p_what) { if (bottom_editor) { - int m = get_constant("item_margin", "Tree"); + int m = 0; //get_constant("item_margin", "Tree"); + bottom_rect = Rect2(m, rect.size.height + get_constant("vseparation", "Tree"), size.width - m, bottom_editor->get_combined_minimum_size().height); } } @@ -147,10 +151,12 @@ void EditorProperty::_notification(int p_what) { continue; fit_child_in_rect(c, rect); + right_child_rect = rect; } if (bottom_editor) { fit_child_in_rect(bottom_editor, bottom_rect); + bottom_child_rect = bottom_rect; } update(); //need to redraw text @@ -158,6 +164,7 @@ void EditorProperty::_notification(int p_what) { if (p_what == NOTIFICATION_DRAW) { Ref<Font> font = get_font("font", "Tree"); + Color dark_color = get_color("dark_color_2", "Editor"); Size2 size = get_size(); if (bottom_editor) { @@ -171,6 +178,13 @@ void EditorProperty::_notification(int p_what) { draw_style_box(sb, Rect2(Vector2(), size)); } + if (right_child_rect != Rect2()) { + draw_rect(right_child_rect, dark_color); + } + if (bottom_child_rect != Rect2()) { + draw_rect(bottom_child_rect, dark_color); + } + Color color; if (draw_red) { color = get_color("error_color", "Editor"); @@ -251,7 +265,7 @@ void EditorProperty::_notification(int p_what) { //int vs = get_constant("vseparation", "Tree"); Color guide_color = get_color("guide_color", "Tree"); int vs_height = get_size().height; // vs / 2; - draw_line(Point2(0, vs_height), Point2(get_size().width, vs_height), guide_color); + // draw_line(Point2(0, vs_height), Point2(get_size().width, vs_height), guide_color); } } @@ -926,6 +940,14 @@ EditorInspectorCategory::EditorInspectorCategory() { //////////////////////////////////////////////// //////////////////////////////////////////////// +void EditorInspectorSection::_test_unfold() { + + if (!vbox_added) { + add_child(vbox); + vbox_added = true; + } +} + void EditorInspectorSection::_notification(int p_what) { if (p_what == NOTIFICATION_SORT_CHILDREN) { @@ -936,9 +958,9 @@ void EditorInspectorSection::_notification(int p_what) { #ifdef TOOLS_ENABLED if (foldable) { if (object->editor_is_section_unfolded(section)) { - arrow = get_icon("arrow", "Tree"); + arrow = get_icon("arrow_up", "Tree"); } else { - arrow = get_icon("arrow_collapsed", "Tree"); + arrow = get_icon("arrow", "Tree"); } } #endif @@ -951,7 +973,7 @@ void EditorInspectorSection::_notification(int p_what) { } offset.y += get_constant("vseparation", "Tree"); - offset.x += get_constant("item_margin", "Tree"); + offset.x += get_constant("inspector_margin", "Editor"); Rect2 rect(offset, size - offset); @@ -979,9 +1001,9 @@ void EditorInspectorSection::_notification(int p_what) { #ifdef TOOLS_ENABLED if (foldable) { if (object->editor_is_section_unfolded(section)) { - arrow = get_icon("arrow", "Tree"); + arrow = get_icon("arrow_up", "Tree"); } else { - arrow = get_icon("arrow_collapsed", "Tree"); + arrow = get_icon("arrow", "Tree"); } } #endif @@ -998,14 +1020,14 @@ void EditorInspectorSection::_notification(int p_what) { int hs = get_constant("hseparation", "Tree"); + Color color = get_color("font_color", "Tree"); + draw_string(font, Point2(hs, font->get_ascent() + (h - font->get_height()) / 2).floor(), label, color, get_size().width); + int ofs = 0; if (arrow.is_valid()) { - draw_texture(arrow, Point2(ofs, (h - arrow->get_height()) / 2).floor()); + draw_texture(arrow, Point2(get_size().width - arrow->get_width(), (h - arrow->get_height()) / 2).floor()); ofs += hs + arrow->get_width(); } - - Color color = get_color("font_color", "Tree"); - draw_string(font, Point2(ofs, font->get_ascent() + (h - font->get_height()) / 2).floor(), label, color, get_size().width); } } @@ -1027,8 +1049,8 @@ Size2 EditorInspectorSection::get_minimum_size() const { } Ref<Font> font = get_font("font", "Tree"); - ms.height += font->get_ascent() + get_constant("vseparation", "Tree"); - ms.width += get_constant("item_margin", "Tree"); + ms.height += font->get_height() + get_constant("vseparation", "Tree"); + ms.width += get_constant("inspector_margin", "Editor"); return ms; } @@ -1041,16 +1063,20 @@ void EditorInspectorSection::setup(const String &p_section, const String &p_labe bg_color = p_bg_color; foldable = p_foldable; + if (!foldable && !vbox_added) { + add_child(vbox); + vbox_added = true; + } + #ifdef TOOLS_ENABLED if (foldable) { + _test_unfold(); if (object->editor_is_section_unfolded(section)) { vbox->show(); } else { vbox->hide(); } } - // void editor_set_section_unfold(const String &p_section, bool p_unfolded); - #endif } @@ -1063,6 +1089,9 @@ void EditorInspectorSection::_gui_input(const Ref<InputEvent> &p_event) { Ref<InputEventMouseButton> mb = p_event; if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT) { + + _test_unfold(); + bool unfold = !object->editor_is_section_unfolded(section); object->editor_set_section_unfold(section, unfold); if (unfold) { @@ -1082,6 +1111,9 @@ void EditorInspectorSection::unfold() { if (!foldable) return; + + _test_unfold(); + #ifdef TOOLS_ENABLED object->editor_set_section_unfold(section, true); @@ -1094,6 +1126,8 @@ void EditorInspectorSection::fold() { if (!foldable) return; + if (!vbox_added) + return; //kinda pointless #ifdef TOOLS_ENABLED object->editor_set_section_unfold(section, false); @@ -1115,7 +1149,14 @@ EditorInspectorSection::EditorInspectorSection() { object = NULL; foldable = false; vbox = memnew(VBoxContainer); - add_child(vbox); + vbox_added = false; + //add_child(vbox); +} + +EditorInspectorSection::~EditorInspectorSection() { + if (!vbox_added) { + memdelete(vbox); + } } //////////////////////////////////////////////// @@ -1276,8 +1317,10 @@ void EditorInspector::update_tree() { String filter = search_box ? search_box->get_text() : ""; String group; String group_base; + VBoxContainer *category_vbox = NULL; - List<PropertyInfo> plist; + List<PropertyInfo> + plist; object->get_property_list(&plist, true); HashMap<String, VBoxContainer *> item_path; @@ -1329,6 +1372,7 @@ void EditorInspector::update_tree() { EditorInspectorCategory *category = memnew(EditorInspectorCategory); main_vbox->add_child(category); + category_vbox = NULL; //reset String type = p.name; if (has_icon(type, "EditorIcons")) @@ -1414,6 +1458,11 @@ void EditorInspector::update_tree() { continue; } + if (category_vbox == NULL) { + category_vbox = memnew(VBoxContainer); + main_vbox->add_child(category_vbox); + } + VBoxContainer *current_vbox = main_vbox; { @@ -1441,6 +1490,14 @@ void EditorInspector::update_tree() { current_vbox = item_path[acc_path]; level = (MIN(level + 1, 4)); } + + if (current_vbox == main_vbox) { + //do not add directly to the main vbox, given it has no spacing + if (category_vbox == NULL) { + category_vbox = memnew(VBoxContainer); + } + current_vbox = category_vbox; + } } bool checkable = false; @@ -1627,6 +1684,10 @@ void EditorInspector::edit(Object *p_object) { object = p_object; if (object) { + update_scroll_request = 0; //reset + if (scroll_cache.has(object->get_instance_id())) { //if exists, set something else + update_scroll_request = scroll_cache[object->get_instance_id()]; //done this way because wait until full size is accomodated + } object->add_change_receptor(this); update_tree(); } @@ -1732,6 +1793,19 @@ int EditorInspector::get_scroll_offset() const { return get_v_scroll(); } +void EditorInspector::set_use_sub_inspector_bg(bool p_enable) { + + use_sub_inspector_bg = p_enable; + if (!is_inside_tree()) + return; + + if (use_sub_inspector_bg) { + add_style_override("bg", get_stylebox("sub_inspector_bg", "Editor")); + } else { + add_style_override("bg", get_stylebox("bg", "Tree")); + } +} + void EditorInspector::_edit_request_change(Object *p_object, const String &p_property) { if (object != p_object) //may be undoing/redoing for a non edited object, so ignore @@ -1942,7 +2016,11 @@ void EditorInspector::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { get_tree()->connect("node_removed", this, "_node_removed"); - add_style_override("bg", get_stylebox("bg", "Tree")); + if (use_sub_inspector_bg) { + add_style_override("bg", get_stylebox("sub_inspector_bg", "Editor")); + } else if (is_inside_tree()) { + add_style_override("bg", get_stylebox("bg", "Tree")); + } } if (p_what == NOTIFICATION_EXIT_TREE) { @@ -1952,6 +2030,10 @@ void EditorInspector::_notification(int p_what) { if (p_what == NOTIFICATION_PROCESS) { + if (update_scroll_request >= 0) { + get_v_scrollbar()->call_deferred("set_value", update_scroll_request); + update_scroll_request = -1; + } if (refresh_countdown > 0) { refresh_countdown -= get_process_delta_time(); if (refresh_countdown <= 0) { @@ -1999,6 +2081,16 @@ void EditorInspector::_changed_callback(Object *p_changed, const char *p_prop) { _edit_request_change(p_changed, p_prop); } +void EditorInspector::_vscroll_changed(double p_offset) { + + if (update_scroll_request >= 0) //waiting, do nothing + return; + + if (object) { + scroll_cache[object->get_instance_id()] = p_offset; + } +} + void EditorInspector::_bind_methods() { ClassDB::bind_method("_property_changed", &EditorInspector::_property_changed, DEFVAL(false)); @@ -2014,6 +2106,8 @@ void EditorInspector::_bind_methods() { ClassDB::bind_method("_property_selected", &EditorInspector::_property_selected); ClassDB::bind_method("_resource_selected", &EditorInspector::_resource_selected); ClassDB::bind_method("_object_id_selected", &EditorInspector::_object_id_selected); + ClassDB::bind_method("_vscroll_changed", &EditorInspector::_vscroll_changed); + ClassDB::bind_method("refresh", &EditorInspector::refresh); ADD_SIGNAL(MethodInfo("property_keyed", PropertyInfo(Variant::STRING, "property"))); @@ -2026,6 +2120,7 @@ EditorInspector::EditorInspector() { undo_redo = NULL; main_vbox = memnew(VBoxContainer); main_vbox->set_h_size_flags(SIZE_EXPAND_FILL); + main_vbox->add_constant_override("separation", 0); add_child(main_vbox); set_enable_h_scroll(false); set_enable_v_scroll(true); @@ -2047,4 +2142,8 @@ EditorInspector::EditorInspector() { _prop_edited = "property_edited"; set_process(true); property_focusable = -1; + use_sub_inspector_bg = false; + + get_v_scrollbar()->connect("value_changed", this, "_vscroll_changed"); + update_scroll_request = -1; } diff --git a/editor/editor_inspector.h b/editor/editor_inspector.h index b7a492f114..320641c693 100644 --- a/editor/editor_inspector.h +++ b/editor/editor_inspector.h @@ -55,6 +55,9 @@ private: bool draw_red; bool keying; + Rect2 right_child_rect; + Rect2 bottom_child_rect; + Rect2 keying_rect; bool keying_hover; Rect2 revert_rect; @@ -194,9 +197,12 @@ class EditorInspectorSection : public Container { String section; Object *object; VBoxContainer *vbox; + bool vbox_added; //optimization Color bg_color; bool foldable; + void _test_unfold(); + protected: void _notification(int p_what); static void _bind_methods(); @@ -213,6 +219,7 @@ public: Object *get_edited_object(); EditorInspectorSection(); + ~EditorInspectorSection(); }; class EditorInspector : public ScrollContainer { @@ -249,16 +256,20 @@ class EditorInspector : public ScrollContainer { bool update_all_pending; bool read_only; bool keying; + bool use_sub_inspector_bg; float refresh_countdown; bool update_tree_pending; StringName _prop_edited; StringName property_selected; int property_focusable; + int update_scroll_request; Map<StringName, Map<StringName, String> > descr_cache; Map<StringName, String> class_descr_cache; + Map<ObjectID, int> scroll_cache; + void _edit_set(const String &p_name, const Variant &p_value, bool p_refresh_all, const String &p_changed_field); void _property_changed(const String &p_path, const Variant &p_value, bool changing = false); @@ -281,6 +292,8 @@ class EditorInspector : public ScrollContainer { void _filter_changed(const String &p_text); void _parse_added_editors(VBoxContainer *current_vbox, Ref<EditorInspectorPlugin> ped); + void _vscroll_changed(double); + protected: static void _bind_methods(); void _notification(int p_what); @@ -330,6 +343,8 @@ public: void set_scroll_offset(int p_offset); int get_scroll_offset() const; + void set_use_sub_inspector_bg(bool p_enable); + EditorInspector(); }; diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index 70bc090bc4..52f6f1ed0e 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -73,6 +73,7 @@ #include "editor/plugins/animation_state_machine_editor.h" #include "editor/plugins/animation_tree_editor_plugin.h" #include "editor/plugins/asset_library_editor_plugin.h" +#include "editor/plugins/audio_stream_editor_plugin.h" #include "editor/plugins/baked_lightmap_editor_plugin.h" #include "editor/plugins/camera_editor_plugin.h" #include "editor/plugins/canvas_item_editor_plugin.h" @@ -1855,10 +1856,6 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { } break; - case SETTINGS_EXPORT_PREFERENCES: { - - //project_export_settings->popup_centered_ratio(); - } break; case FILE_IMPORT_SUBSCENE: { if (!editor_data.get_edited_scene_root()) { @@ -4189,7 +4186,7 @@ void EditorNode::_dropped_files(const Vector<String> &p_files, int p_screen) { for (int i = 0; i < p_files.size(); i++) { String from = p_files[i]; - if (!ResourceFormatImporter::get_singleton()->can_be_imported(from) && (just_copy.find(from.get_extension().to_lower()) != -1)) { + if (!ResourceFormatImporter::get_singleton()->can_be_imported(from) && (just_copy.find(from.get_extension().to_lower()) == -1)) { continue; } String to = to_path.plus_file(from.get_file()); @@ -4673,7 +4670,7 @@ EditorNode::EditorNode() { EDITOR_DEF("interface/inspector/capitalize_properties", true); EDITOR_DEF("interface/inspector/disable_folding", false); EDITOR_DEF("interface/inspector/open_resources_in_current_inspector", true); - EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "Material,Mesh"); + EDITOR_DEF("interface/inspector/resources_types_to_open_in_new_inspector", "SpatialMaterial"); EDITOR_DEF("run/auto_save/save_before_running", true); theme_base = memnew(Control); @@ -5445,6 +5442,7 @@ EditorNode::EditorNode() { add_editor_plugin(memnew(CollisionShape2DEditorPlugin(this))); add_editor_plugin(memnew(CurveEditorPlugin(this))); add_editor_plugin(memnew(TextureEditorPlugin(this))); + add_editor_plugin(memnew(AudioStreamEditorPlugin(this))); add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); add_editor_plugin(memnew(AudioBusesEditorPlugin(audio_bus_editor))); add_editor_plugin(memnew(SkeletonEditorPlugin(this))); diff --git a/editor/editor_node.h b/editor/editor_node.h index 7aa060fe14..88fe008b34 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -164,7 +164,6 @@ private: SETTINGS_UPDATE_ALWAYS, SETTINGS_UPDATE_CHANGES, SETTINGS_UPDATE_SPINNER_HIDE, - SETTINGS_EXPORT_PREFERENCES, SETTINGS_PREFERENCES, SETTINGS_LAYOUT_SAVE, SETTINGS_LAYOUT_DELETE, diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index cd0bba4c9c..0b49b5a801 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -178,6 +178,8 @@ void EditorPropertyTextEnum::_bind_methods() { EditorPropertyTextEnum::EditorPropertyTextEnum() { options = memnew(OptionButton); options->set_clip_text(true); + options->set_flat(true); + add_child(options); add_focusable(options); options->connect("item_selected", this, "_option_selected"); @@ -441,6 +443,7 @@ void EditorPropertyEnum::_bind_methods() { EditorPropertyEnum::EditorPropertyEnum() { options = memnew(OptionButton); options->set_clip_text(true); + options->set_flat(true); add_child(options); add_focusable(options); options->connect("item_selected", this, "_option_selected"); @@ -641,9 +644,11 @@ void EditorPropertyLayers::setup(LayerType p_layer_type) { } if (name == "") { - name = "Layer " + itos(i + 1); + name = TTR("Layer") + " " + itos(i + 1); } + name += "\n" + vformat(TTR("Bit %d, value %d"), i, 1 << i); + names.push_back(name); } @@ -733,6 +738,7 @@ void EditorPropertyInteger::setup(int p_min, int p_max, bool p_allow_greater, bo EditorPropertyInteger::EditorPropertyInteger() { spin = memnew(EditorSpinSlider); + spin->set_flat(true); add_child(spin); add_focusable(spin); spin->connect("value_changed", this, "_value_changed"); @@ -819,6 +825,7 @@ void EditorPropertyFloat::setup(double p_min, double p_max, double p_step, bool EditorPropertyFloat::EditorPropertyFloat() { spin = memnew(EditorSpinSlider); + spin->set_flat(true); add_child(spin); add_focusable(spin); spin->connect("value_changed", this, "_value_changed"); @@ -829,6 +836,12 @@ EditorPropertyFloat::EditorPropertyFloat() { void EditorPropertyEasing::_drag_easing(const Ref<InputEvent> &p_ev) { + Ref<InputEventMouseButton> mb = p_ev; + if (mb.is_valid() && mb->is_pressed() && mb->get_button_index() == BUTTON_RIGHT) { + preset->set_global_position(easing_draw->get_global_transform().xform(mb->get_position())); + preset->popup(); + } + Ref<InputEventMouseMotion> mm = p_ev; if (mm.is_valid() && mm->get_button_mask() & BUTTON_MASK_LEFT) { @@ -866,7 +879,7 @@ void EditorPropertyEasing::_draw_easing() { Size2 s = easing_draw->get_size(); Rect2 r(Point2(), s); r = r.grow(3); - get_stylebox("normal", "LineEdit")->draw(ci, r); + //get_stylebox("normal", "LineEdit")->draw(ci, r); int points = 48; @@ -876,6 +889,7 @@ void EditorPropertyEasing::_draw_easing() { Ref<Font> f = get_font("font", "Label"); Color color = get_color("font_color", "Label"); + Vector<Point2> lines; for (int i = 1; i <= points; i++) { float ifl = i / float(points); @@ -888,10 +902,12 @@ void EditorPropertyEasing::_draw_easing() { iflp = 1.0 - iflp; } - VisualServer::get_singleton()->canvas_item_add_line(ci, Point2(iflp * s.width, prev * s.height), Point2(ifl * s.width, h * s.height), color); + lines.push_back(Point2(ifl * s.width, h * s.height)); + lines.push_back(Point2(iflp * s.width, prev * s.height)); prev = h; } + easing_draw->draw_multiline(lines, color, 1.0, true); f->draw(ci, Point2(10, 10 + f->get_ascent()), String::num(exp, 2), color); } @@ -899,29 +915,17 @@ void EditorPropertyEasing::update_property() { easing_draw->update(); } -void EditorPropertyEasing::_set_preset(float p_val) { - emit_signal("property_changed", get_edited_property(), p_val); +void EditorPropertyEasing::_set_preset(int p_preset) { + static const float preset_value[EASING_MAX] = { 0.0, 1.0, 2.0, 0.5, -2.0, -0.5 }; + + emit_signal("property_changed", get_edited_property(), preset_value[p_preset]); easing_draw->update(); } void EditorPropertyEasing::setup(bool p_full, bool p_flip) { flip = p_flip; - if (p_full) { - HBoxContainer *hb2 = memnew(HBoxContainer); - vb->add_child(hb2); - button_out_in = memnew(ToolButton); - button_out_in->set_tooltip(TTR("Out-In")); - button_out_in->set_h_size_flags(SIZE_EXPAND_FILL); - button_out_in->connect("pressed", this, "_set_preset", varray(-0.5)); - hb2->add_child(button_out_in); - - button_in_out = memnew(ToolButton); - button_in_out->set_tooltip(TTR("In")); - button_in_out->set_h_size_flags(SIZE_EXPAND_FILL); - button_in_out->connect("pressed", this, "_set_preset", varray(-2)); - hb2->add_child(button_in_out); - } + full = p_full; } void EditorPropertyEasing::_notification(int p_what) { @@ -929,15 +933,19 @@ void EditorPropertyEasing::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_ENTER_TREE: { + preset->clear(); + preset->add_icon_item(get_icon("CurveConstant", "EditorIcons"), "Zero", EASING_ZERO); + preset->add_icon_item(get_icon("CurveLinear", "EditorIcons"), "Linear", EASING_LINEAR); + preset->add_icon_item(get_icon("CurveIn", "EditorIcons"), "In", EASING_IN); + preset->add_icon_item(get_icon("CurveOut", "EditorIcons"), "Out", EASING_OUT); + if (full) { + preset->add_icon_item(get_icon("CurveInOut", "EditorIcons"), "In-Out", EASING_IN_OUT); + preset->add_icon_item(get_icon("CurveOutIn", "EditorIcons"), "Out-In", EASING_OUT_IN); + } easing_draw->set_custom_minimum_size(Size2(0, get_font("font", "Label")->get_height() * 2)); - button_linear->set_icon(get_icon("CurveLinear", "EditorIcons")); - button_out->set_icon(get_icon("CurveOut", "EditorIcons")); - button_in->set_icon(get_icon("CurveIn", "EditorIcons")); - button_constant->set_icon(get_icon("CurveConstant", "EditorIcons")); - if (button_out_in) - button_out_in->set_icon(get_icon("CurveOutIn", "EditorIcons")); - if (button_in_out) - button_in_out->set_icon(get_icon("CurveInOut", "EditorIcons")); + } break; + case NOTIFICATION_RESIZED: { + } break; } } @@ -951,47 +959,18 @@ void EditorPropertyEasing::_bind_methods() { EditorPropertyEasing::EditorPropertyEasing() { - vb = memnew(VBoxContainer); - add_child(vb); - HBoxContainer *hb = memnew(HBoxContainer); - set_label_reference(hb); - - vb->add_child(hb); - - button_linear = memnew(ToolButton); - button_linear->set_tooltip(TTR("Linear")); - button_linear->set_h_size_flags(SIZE_EXPAND_FILL); - button_linear->connect("pressed", this, "_set_preset", varray(1)); - hb->add_child(button_linear); - - button_constant = memnew(ToolButton); - button_constant->set_tooltip(TTR("Linear")); - button_constant->set_h_size_flags(SIZE_EXPAND_FILL); - button_constant->connect("pressed", this, "_set_preset", varray(0)); - hb->add_child(button_constant); - - button_out = memnew(ToolButton); - button_out->set_tooltip(TTR("Out")); - button_out->set_h_size_flags(SIZE_EXPAND_FILL); - button_out->connect("pressed", this, "_set_preset", varray(0.5)); - hb->add_child(button_out); - - button_in = memnew(ToolButton); - button_in->set_tooltip(TTR("In")); - button_in->set_h_size_flags(SIZE_EXPAND_FILL); - button_in->connect("pressed", this, "_set_preset", varray(2)); - hb->add_child(button_in); - - button_in_out = NULL; - button_out_in = NULL; - easing_draw = memnew(Control); easing_draw->connect("draw", this, "_draw_easing"); easing_draw->connect("gui_input", this, "_drag_easing"); easing_draw->set_default_cursor_shape(Control::CURSOR_MOVE); - vb->add_child(easing_draw); + add_child(easing_draw); + + preset = memnew(PopupMenu); + add_child(preset); + preset->connect("id_pressed", this, "_set_preset"); flip = false; + full = false; } ///////////////////// VECTOR2 ///////////////////////// @@ -1014,6 +993,18 @@ void EditorPropertyVector2::update_property() { setting = false; } +void EditorPropertyVector2::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 2; i++) { + + Color c = base; + c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } +} + void EditorPropertyVector2::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyVector2::_value_changed); @@ -1034,6 +1025,7 @@ EditorPropertyVector2::EditorPropertyVector2() { static const char *desc[2] = { "x", "y" }; for (int i = 0; i < 2; i++) { spin[i] = memnew(EditorSpinSlider); + spin[i]->set_flat(true); spin[i]->set_label(desc[i]); vb->add_child(spin[i]); add_focusable(spin[i]); @@ -1066,7 +1058,17 @@ void EditorPropertyRect2::update_property() { spin[3]->set_value(val.size.y); setting = false; } +void EditorPropertyRect2::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 4; i++) { + Color c = base; + c.set_hsv(float(i % 2) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } +} void EditorPropertyRect2::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyRect2::_value_changed); @@ -1088,6 +1090,8 @@ EditorPropertyRect2::EditorPropertyRect2() { for (int i = 0; i < 4; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_label(desc[i]); + spin[i]->set_flat(true); + vb->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); @@ -1116,7 +1120,17 @@ void EditorPropertyVector3::update_property() { spin[2]->set_value(val.z); setting = false; } +void EditorPropertyVector3::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 3; i++) { + Color c = base; + c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } +} void EditorPropertyVector3::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyVector3::_value_changed); @@ -1138,6 +1152,8 @@ EditorPropertyVector3::EditorPropertyVector3() { for (int i = 0; i < 3; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_label(desc[i]); + spin[i]->set_flat(true); + vb->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); @@ -1168,7 +1184,17 @@ void EditorPropertyPlane::update_property() { spin[3]->set_value(val.d); setting = false; } +void EditorPropertyPlane::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 3; i++) { + Color c = base; + c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } +} void EditorPropertyPlane::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyPlane::_value_changed); @@ -1190,6 +1216,7 @@ EditorPropertyPlane::EditorPropertyPlane() { for (int i = 0; i < 4; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_label(desc[i]); + spin[i]->set_flat(true); vb->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); @@ -1221,7 +1248,17 @@ void EditorPropertyQuat::update_property() { spin[3]->set_value(val.w); setting = false; } +void EditorPropertyQuat::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 3; i++) { + Color c = base; + c.set_hsv(float(i) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } +} void EditorPropertyQuat::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyQuat::_value_changed); @@ -1243,6 +1280,8 @@ EditorPropertyQuat::EditorPropertyQuat() { for (int i = 0; i < 4; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_label(desc[i]); + spin[i]->set_flat(true); + vb->add_child(spin[i]); add_focusable(spin[i]); spin[i]->connect("value_changed", this, "_value_changed"); @@ -1280,7 +1319,17 @@ void EditorPropertyAABB::update_property() { setting = false; } +void EditorPropertyAABB::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 6; i++) { + Color c = base; + c.set_hsv(float(i % 3) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } +} void EditorPropertyAABB::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyAABB::_value_changed); @@ -1304,6 +1353,8 @@ EditorPropertyAABB::EditorPropertyAABB() { for (int i = 0; i < 6; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_label(desc[i]); + spin[i]->set_flat(true); + g->add_child(spin[i]); spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); add_focusable(spin[i]); @@ -1342,7 +1393,17 @@ void EditorPropertyTransform2D::update_property() { setting = false; } +void EditorPropertyTransform2D::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 6; i++) { + Color c = base; + c.set_hsv(float(i % 2) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } +} void EditorPropertyTransform2D::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyTransform2D::_value_changed); @@ -1362,10 +1423,11 @@ EditorPropertyTransform2D::EditorPropertyTransform2D() { g->set_columns(2); add_child(g); - static const char *desc[6] = { "xx", "xy", "yx", "yy", "ox", "oy" }; + static const char *desc[6] = { "x", "y", "x", "y", "x", "y" }; for (int i = 0; i < 6; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_label(desc[i]); + spin[i]->set_flat(true); g->add_child(spin[i]); spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); add_focusable(spin[i]); @@ -1410,7 +1472,17 @@ void EditorPropertyBasis::update_property() { setting = false; } +void EditorPropertyBasis::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 9; i++) { + Color c = base; + c.set_hsv(float(i % 3) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } +} void EditorPropertyBasis::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyBasis::_value_changed); @@ -1430,10 +1502,11 @@ EditorPropertyBasis::EditorPropertyBasis() { g->set_columns(3); add_child(g); - static const char *desc[9] = { "xx", "xy", "xz", "yx", "yy", "yz", "zx", "zy", "zz" }; + static const char *desc[9] = { "x", "y", "z", "x", "y", "z", "x", "y", "z" }; for (int i = 0; i < 9; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_label(desc[i]); + spin[i]->set_flat(true); g->add_child(spin[i]); spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); add_focusable(spin[i]); @@ -1484,7 +1557,17 @@ void EditorPropertyTransform::update_property() { setting = false; } +void EditorPropertyTransform::_notification(int p_what) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { + Color base = get_color("accent_color", "Editor"); + for (int i = 0; i < 12; i++) { + Color c = base; + c.set_hsv(float(i % 3) / 3.0 + 0.05, c.get_s() * 0.75, c.get_v()); + spin[i]->set_custom_label_color(true, c); + } + } +} void EditorPropertyTransform::_bind_methods() { ClassDB::bind_method(D_METHOD("_value_changed"), &EditorPropertyTransform::_value_changed); @@ -1504,10 +1587,11 @@ EditorPropertyTransform::EditorPropertyTransform() { g->set_columns(3); add_child(g); - static const char *desc[12] = { "xx", "xy", "xz", "yx", "yy", "yz", "zx", "zy", "zz", "ox", "oy", "oz" }; + static const char *desc[12] = { "x", "y", "z", "x", "y", "z", "x", "y", "z", "x", "y", "z" }; for (int i = 0; i < 12; i++) { spin[i] = memnew(EditorSpinSlider); spin[i]->set_label(desc[i]); + spin[i]->set_flat(true); g->add_child(spin[i]); spin[i]->set_h_size_flags(SIZE_EXPAND_FILL); add_focusable(spin[i]); @@ -1854,7 +1938,19 @@ void EditorPropertyResource::_resource_preview(const String &p_path, const Ref<T RES p = get_edited_object()->get(get_edited_property()); if (p.is_valid() && p->get_instance_id() == p_obj) { if (p_preview.is_valid()) { - assign->set_icon(p_preview); + String type = p->get_class_name(); + preview->set_margin(MARGIN_LEFT, assign->get_icon()->get_width() + assign->get_stylebox("normal")->get_default_margin(MARGIN_LEFT) + get_constant("hseparation", "Button")); + if (type == "GradientTexture") { + preview->set_stretch_mode(TextureRect::STRETCH_SCALE); + assign->set_custom_minimum_size(Size2(1, 1)); + } else { + preview->set_stretch_mode(TextureRect::STRETCH_KEEP_ASPECT_CENTERED); + int thumbnail_size = EditorSettings::get_singleton()->get("filesystem/file_dialog/thumbnail_size"); + thumbnail_size *= EDSCALE; + assign->set_custom_minimum_size(Size2(1, thumbnail_size)); + } + preview->set_texture(p_preview); + assign->set_text(""); } } } @@ -2048,6 +2144,9 @@ void EditorPropertyResource::update_property() { sub_inspector = memnew(EditorInspector); sub_inspector->set_enable_v_scroll(false); + sub_inspector->set_use_sub_inspector_bg(true); + sub_inspector->set_enable_capitalize_paths(true); + sub_inspector->connect("property_keyed", this, "_sub_inspector_property_keyed"); sub_inspector->connect("resource_selected", this, "_sub_inspector_resource_selected"); sub_inspector->connect("object_id_selected", this, "_sub_inspector_object_id_selected"); @@ -2095,6 +2194,7 @@ void EditorPropertyResource::update_property() { #endif } + preview->set_texture(Ref<Texture>()); if (res == RES()) { assign->set_icon(Ref<Texture>()); assign->set_text(TTR("[empty]")); @@ -2333,6 +2433,14 @@ EditorPropertyResource::EditorPropertyResource() { assign->connect("draw", this, "_button_draw"); hbc->add_child(assign); + preview = memnew(TextureRect); + preview->set_expand(true); + preview->set_anchors_and_margins_preset(PRESET_WIDE); + preview->set_margin(MARGIN_TOP, 1); + preview->set_margin(MARGIN_BOTTOM, -1); + preview->set_margin(MARGIN_RIGHT, -1); + assign->add_child(preview); + menu = memnew(PopupMenu); add_child(menu); edit = memnew(Button); diff --git a/editor/editor_properties.h b/editor/editor_properties.h index ecccd7274d..0afb1bf955 100644 --- a/editor/editor_properties.h +++ b/editor/editor_properties.h @@ -278,16 +278,26 @@ public: class EditorPropertyEasing : public EditorProperty { GDCLASS(EditorPropertyEasing, EditorProperty) Control *easing_draw; - ToolButton *button_out, *button_in, *button_linear, *button_constant; - ToolButton *button_in_out, *button_out_in; - VBoxContainer *vb; + PopupMenu *preset; + bool full; + + enum { + EASING_ZERO, + EASING_LINEAR, + EASING_IN, + EASING_OUT, + EASING_IN_OUT, + EASING_OUT_IN, + EASING_MAX + + }; bool flip; void _drag_easing(const Ref<InputEvent> &p_ev); void _draw_easing(); void _notification(int p_what); - void _set_preset(float p_val); + void _set_preset(int); protected: static void _bind_methods(); @@ -305,6 +315,7 @@ class EditorPropertyVector2 : public EditorProperty { void _value_changed(double p_val); protected: + void _notification(int p_what); static void _bind_methods(); public: @@ -320,6 +331,7 @@ class EditorPropertyRect2 : public EditorProperty { void _value_changed(double p_val); protected: + void _notification(int p_what); static void _bind_methods(); public: @@ -335,6 +347,7 @@ class EditorPropertyVector3 : public EditorProperty { void _value_changed(double p_val); protected: + void _notification(int p_what); static void _bind_methods(); public: @@ -350,6 +363,7 @@ class EditorPropertyPlane : public EditorProperty { void _value_changed(double p_val); protected: + void _notification(int p_what); static void _bind_methods(); public: @@ -365,6 +379,7 @@ class EditorPropertyQuat : public EditorProperty { void _value_changed(double p_val); protected: + void _notification(int p_what); static void _bind_methods(); public: @@ -380,6 +395,7 @@ class EditorPropertyAABB : public EditorProperty { void _value_changed(double p_val); protected: + void _notification(int p_what); static void _bind_methods(); public: @@ -395,6 +411,7 @@ class EditorPropertyTransform2D : public EditorProperty { void _value_changed(double p_val); protected: + void _notification(int p_what); static void _bind_methods(); public: @@ -410,6 +427,7 @@ class EditorPropertyBasis : public EditorProperty { void _value_changed(double p_val); protected: + void _notification(int p_what); static void _bind_methods(); public: @@ -425,6 +443,7 @@ class EditorPropertyTransform : public EditorProperty { void _value_changed(double p_val); protected: + void _notification(int p_what); static void _bind_methods(); public: @@ -488,6 +507,7 @@ class EditorPropertyResource : public EditorProperty { }; Button *assign; + TextureRect *preview; Button *edit; PopupMenu *menu; EditorFileDialog *file; diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index c7a33de3f1..79023a1f28 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -90,10 +90,12 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) { } grabbing_spinner_dist_cache += diff_x; - if (!grabbing_spinner && ABS(grabbing_spinner_dist_cache) > 4) { + if (!grabbing_spinner && ABS(grabbing_spinner_dist_cache) > 4 * EDSCALE) { Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_CAPTURED); grabbing_spinner = true; - } else { + } + + if (grabbing_spinner) { if (mm->get_control() || updown_offset != -1) { set_value(Math::round(get_value())); if (ABS(grabbing_spinner_dist_cache) > 6) { @@ -159,20 +161,20 @@ void EditorSpinSlider::_notification(int p_what) { updown_offset = -1; Ref<StyleBox> sb = get_stylebox("normal", "LineEdit"); - draw_style_box(sb, Rect2(Vector2(), get_size())); + if (!flat) { + draw_style_box(sb, Rect2(Vector2(), get_size())); + } Ref<Font> font = get_font("font", "LineEdit"); + int sep_base = 4 * EDSCALE; + int sep = sep_base + sb->get_offset().x; //make it have the same margin on both sides, looks better + + int string_width = font->get_string_size(label).width; + int number_width = get_size().width - sb->get_minimum_size().width - string_width - sep; - int avail_width = get_size().width - sb->get_minimum_size().width; - avail_width -= font->get_string_size(label).width; Ref<Texture> updown = get_icon("updown", "SpinBox"); if (get_step() == 1) { - avail_width -= updown->get_width(); - } - - if (has_focus()) { - Ref<StyleBox> focus = get_stylebox("focus", "LineEdit"); - draw_style_box(focus, Rect2(Vector2(), get_size())); + number_width -= updown->get_width(); } String numstr = get_text_value(); @@ -180,10 +182,26 @@ void EditorSpinSlider::_notification(int p_what) { int vofs = (get_size().height - font->get_height()) / 2 + font->get_ascent(); Color fc = get_color("font_color", "LineEdit"); + Color lc; + if (use_custom_label_color) { + lc = custom_label_color; + } else { + lc = fc; + } - int label_ofs = sb->get_offset().x + avail_width; - draw_string(font, Vector2(label_ofs, vofs), label, fc * Color(1, 1, 1, 0.5)); - draw_string(font, Vector2(sb->get_offset().x, vofs), numstr, fc, avail_width); + if (flat && label != String()) { + Color label_bg_color = get_color("dark_color_3", "Editor"); + draw_rect(Rect2(Vector2(), Vector2(sb->get_offset().x * 2 + string_width, get_size().height)), label_bg_color); + } + + if (has_focus()) { + Ref<StyleBox> focus = get_stylebox("focus", "LineEdit"); + draw_style_box(focus, Rect2(Vector2(), get_size())); + } + + draw_string(font, Vector2(sb->get_offset().x, vofs), label, lc * Color(1, 1, 1, 0.5)); + + draw_string(font, Vector2(sb->get_offset().x + string_width + sep, vofs), numstr, fc, number_width); if (get_step() == 1) { Ref<Texture> updown = get_icon("updown", "SpinBox"); @@ -250,9 +268,11 @@ void EditorSpinSlider::_notification(int p_what) { update(); } if (p_what == NOTIFICATION_FOCUS_ENTER) { - if (!Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && !value_input_just_closed) { + /* Sorry, I dont like this, it makes navigating the different fields with arrows more difficult + * if (!Input::get_singleton()->is_mouse_button_pressed(BUTTON_LEFT) && !value_input_just_closed) { _focus_entered(); - } + }*/ + value_input_just_closed = false; } } @@ -334,6 +354,21 @@ bool EditorSpinSlider::is_read_only() const { return read_only; } +void EditorSpinSlider::set_flat(bool p_enable) { + + flat = p_enable; + update(); +} + +bool EditorSpinSlider::is_flat() const { + return flat; +} + +void EditorSpinSlider::set_custom_label_color(bool p_use_custom_label_color, Color p_custom_label_color) { + use_custom_label_color = p_use_custom_label_color; + custom_label_color = p_custom_label_color; +} + void EditorSpinSlider::_focus_entered() { Rect2 gr = get_global_rect(); value_input->set_text(get_text_value()); @@ -353,6 +388,9 @@ void EditorSpinSlider::_bind_methods() { ClassDB::bind_method(D_METHOD("set_read_only", "read_only"), &EditorSpinSlider::set_read_only); ClassDB::bind_method(D_METHOD("is_read_only"), &EditorSpinSlider::is_read_only); + ClassDB::bind_method(D_METHOD("set_flat", "flat"), &EditorSpinSlider::set_flat); + ClassDB::bind_method(D_METHOD("is_flat"), &EditorSpinSlider::is_flat); + ClassDB::bind_method(D_METHOD("_gui_input"), &EditorSpinSlider::_gui_input); ClassDB::bind_method(D_METHOD("_grabber_mouse_entered"), &EditorSpinSlider::_grabber_mouse_entered); ClassDB::bind_method(D_METHOD("_grabber_mouse_exited"), &EditorSpinSlider::_grabber_mouse_exited); @@ -363,10 +401,12 @@ void EditorSpinSlider::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "label"), "set_label", "get_label"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "read_only"), "set_read_only", "is_read_only"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); } EditorSpinSlider::EditorSpinSlider() { + flat = false; grabbing_spinner_attempt = false; grabbing_spinner = false; grabbing_spinner_dist_cache = 0; @@ -395,4 +435,5 @@ EditorSpinSlider::EditorSpinSlider() { value_input_just_closed = false; hide_slider = false; read_only = false; + use_custom_label_color = false; } diff --git a/editor/editor_spin_slider.h b/editor/editor_spin_slider.h index 5316c0264a..fb32534ef4 100644 --- a/editor/editor_spin_slider.h +++ b/editor/editor_spin_slider.h @@ -68,6 +68,10 @@ class EditorSpinSlider : public Range { void _value_input_entered(const String &); void _value_focus_exited(); bool hide_slider; + bool flat; + + bool use_custom_label_color; + Color custom_label_color; protected: void _notification(int p_what); @@ -88,6 +92,11 @@ public: void set_read_only(bool p_enable); bool is_read_only() const; + void set_flat(bool p_enable); + bool is_flat() const; + + void set_custom_label_color(bool p_use_custom_label_color, Color p_custom_label_color); + virtual Size2 get_minimum_size() const; EditorSpinSlider(); }; diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 0534a398f4..084caff083 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -656,6 +656,14 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_icon("visibility_xray", "PopupMenu", theme->get_icon("GuiVisibilityXray", "EditorIcons")); theme->set_constant("vseparation", "PopupMenu", (extra_spacing + default_margin_size) * EDSCALE); + Ref<StyleBoxFlat> sub_inspector_bg = make_flat_stylebox(dark_color_1, 2, 0, 0, 0); + sub_inspector_bg->set_border_width(MARGIN_LEFT, 2); + sub_inspector_bg->set_border_color(MARGIN_LEFT, accent_color * Color(1, 1, 1, 0.3)); + sub_inspector_bg->set_draw_center(true); + + theme->set_stylebox("sub_inspector_bg", "Editor", sub_inspector_bg); + theme->set_constant("inspector_margin", "Editor", 8 * EDSCALE); + // Tree & ItemList background Ref<StyleBoxFlat> style_tree_bg = style_default->duplicate(); style_tree_bg->set_bg_color(dark_color_1); @@ -666,6 +674,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // Tree theme->set_icon("checked", "Tree", theme->get_icon("GuiChecked", "EditorIcons")); theme->set_icon("unchecked", "Tree", theme->get_icon("GuiUnchecked", "EditorIcons")); + theme->set_icon("arrow_up", "Tree", theme->get_icon("GuiTreeArrowUp", "EditorIcons")); theme->set_icon("arrow", "Tree", theme->get_icon("GuiTreeArrowDown", "EditorIcons")); theme->set_icon("arrow_collapsed", "Tree", theme->get_icon("GuiTreeArrowRight", "EditorIcons")); theme->set_icon("updown", "Tree", theme->get_icon("GuiTreeUpdown", "EditorIcons")); diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index 541c848ca3..931785333f 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -123,7 +123,6 @@ void ExportTemplateManager::_update_template_list() { void ExportTemplateManager::_download_template(const String &p_version) { - print_line("download " + p_version); while (template_list->get_child_count()) { memdelete(template_list->get_child(0)); } @@ -228,7 +227,10 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ version = data_str; } - fc++; + if (file.get_file().size() != 0) { + fc++; + } + ret = unzGoToNextFile(pkg); } @@ -268,6 +270,11 @@ void ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ String file = String(fname).get_file(); + if (file.size() == 0) { + ret = unzGoToNextFile(pkg); + continue; + } + Vector<uint8_t> data; data.resize(info.uncompressed_size); @@ -344,7 +351,6 @@ void ExportTemplateManager::_http_download_mirror_completed(int p_status, int p_ bool mirrors_found = false; Dictionary d = r; - print_line(r); if (d.has("mirrors")) { Array mirrors = d["mirrors"]; for (int i = 0; i < mirrors.size(); i++) { @@ -499,7 +505,6 @@ void ExportTemplateManager::_notification(int p_what) { if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { if (!is_visible_in_tree()) { - print_line("closed"); set_process(false); } } diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index eebf1b6ab8..f65fb5365b 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -1862,7 +1862,7 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_file_option"), &FileSystemDock::_file_option); ClassDB::bind_method(D_METHOD("_folder_option"), &FileSystemDock::_folder_option); ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm); - ClassDB::bind_method(D_METHOD("_move_operation_confirm"), &FileSystemDock::_move_operation_confirm); + ClassDB::bind_method(D_METHOD("_move_operation_confirm", "to_path", "overwrite"), &FileSystemDock::_move_operation_confirm, DEFVAL(false)); ClassDB::bind_method(D_METHOD("_move_with_overwrite"), &FileSystemDock::_move_with_overwrite); ClassDB::bind_method(D_METHOD("_rename_operation_confirm"), &FileSystemDock::_rename_operation_confirm); ClassDB::bind_method(D_METHOD("_duplicate_operation_confirm"), &FileSystemDock::_duplicate_operation_confirm); diff --git a/editor/icons/icon_GUI_tree_arrow_up.svg b/editor/icons/icon_GUI_tree_arrow_up.svg new file mode 100644 index 0000000000..4e6e8e9e29 --- /dev/null +++ b/editor/icons/icon_GUI_tree_arrow_up.svg @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="12" + height="12" + version="1.1" + viewBox="0 0 12 12" + id="svg6" + sodipodi:docname="icon_GUI_tree_arrow_up.svg" + inkscape:version="0.92.3 (2405546, 2018-03-11)"> + <metadata + id="metadata12"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title /> + </cc:Work> + </rdf:RDF> + </metadata> + <defs + id="defs10" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1673" + inkscape:window-height="594" + id="namedview8" + showgrid="false" + inkscape:zoom="19.666667" + inkscape:cx="-4.3220338" + inkscape:cy="6.0000001" + inkscape:window-x="67" + inkscape:window-y="27" + inkscape:window-maximized="0" + inkscape:current-layer="svg6" /> + <g + transform="rotate(180,6,526.08476)" + id="g4"> + <path + d="m 3,1045.4 3,3 3,-3" + id="path2" + inkscape:connector-curvature="0" + style="fill:none;stroke:#ffffff;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-opacity:0.39216003" /> + </g> +</svg> diff --git a/editor/plugins/audio_stream_editor_plugin.cpp b/editor/plugins/audio_stream_editor_plugin.cpp new file mode 100644 index 0000000000..ddb03d0250 --- /dev/null +++ b/editor/plugins/audio_stream_editor_plugin.cpp @@ -0,0 +1,284 @@ +/*************************************************************************/ +/* audio_stream_editor_plugin.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "audio_stream_editor_plugin.h" + +#include "editor/editor_settings.h" +#include "io/resource_loader.h" +#include "project_settings.h" + +void AudioStreamEditor::_notification(int p_what) { + + if (p_what == NOTIFICATION_READY) { + AudioStreamPreviewGenerator::get_singleton()->connect("preview_updated", this, "_preview_changed"); + } + + if (p_what == NOTIFICATION_THEME_CHANGED || p_what == NOTIFICATION_ENTER_TREE) { + _play_button->set_icon(get_icon("MainPlay", "EditorIcons")); + _stop_button->set_icon(get_icon("Stop", "EditorIcons")); + _preview->set_frame_color(get_color("dark_color_2", "Editor")); + set_frame_color(get_color("dark_color_1", "Editor")); + + _indicator->update(); + _preview->update(); + } + + if (p_what == NOTIFICATION_PROCESS) { + _current = _player->get_playback_position(); + _indicator->update(); + _preview->update(); + } + + if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + if (!is_visible_in_tree()) { + _stop(); + } + } +} + +void AudioStreamEditor::_draw_preview() { + Rect2 rect = _preview->get_rect(); + Size2 size = get_size(); + + Ref<AudioStreamPreview> preview = AudioStreamPreviewGenerator::get_singleton()->generate_preview(stream); + float preview_len = preview->get_length(); + + Vector<Vector2> lines; + lines.resize(size.width * 2); + + for (int i = 0; i < size.width; i++) { + + float ofs = i * preview_len / size.width; + float ofs_n = (i + 1) * preview_len / size.width; + float max = preview->get_max(ofs, ofs_n) * 0.5 + 0.5; + float min = preview->get_min(ofs, ofs_n) * 0.5 + 0.5; + + int idx = i; + lines[idx * 2 + 0] = Vector2(i + 1, rect.position.y + min * rect.size.y); + lines[idx * 2 + 1] = Vector2(i + 1, rect.position.y + max * rect.size.y); + } + + Vector<Color> color; + color.push_back(get_color("contrast_color_2", "Editor")); + + VS::get_singleton()->canvas_item_add_multiline(_preview->get_canvas_item(), lines, color); +} + +void AudioStreamEditor::_preview_changed(ObjectID p_which) { + + if (stream.is_valid() && stream->get_instance_id() == p_which) { + _preview->update(); + } +} + +void AudioStreamEditor::_changed_callback(Object *p_changed, const char *p_prop) { + + if (!is_visible()) + return; + update(); +} + +void AudioStreamEditor::_play() { + + if (_player->is_playing()) { + _player->stop(); + _play_button->set_icon(get_icon("MainPlay", "EditorIcons")); + set_process(false); + } else { + _player->play(_current); + _play_button->set_icon(get_icon("Pause", "EditorIcons")); + set_process(true); + } +} + +void AudioStreamEditor::_stop() { + + _player->stop(); + _on_finished(); +} + +void AudioStreamEditor::_on_finished() { + + _play_button->set_icon(get_icon("MainPlay", "EditorIcons")); + _current = 0; + _indicator->update(); + set_process(false); +} + +void AudioStreamEditor::_draw_indicator() { + + if (!stream.is_valid()) { + return; + } + + Rect2 rect = _preview->get_rect(); + float len = stream->get_length(); + float ofs_x = _current / len * rect.size.width; + _indicator->draw_line(Point2(ofs_x, 0), Point2(ofs_x, rect.size.height), get_color("accent_color", "Editor"), 1); + + _current_label->set_text(String::num(_current, 2).pad_decimals(2) + " /"); +} + +void AudioStreamEditor::_on_input_indicator(Ref<InputEvent> p_event) { + Ref<InputEventMouseButton> mb = p_event; + + if (mb.is_valid()) { + if (mb->is_pressed()) { + _seek_to(mb->get_position().x); + } + _dragging = mb->is_pressed(); + } + + Ref<InputEventMouseMotion> mm = p_event; + + if (mm.is_valid()) { + if (_dragging) { + _seek_to(mm->get_position().x); + } + } +} + +void AudioStreamEditor::_seek_to(real_t p_x) { + _current = p_x / _preview->get_rect().size.x * stream->get_length(); + _current = CLAMP(_current, 0, stream->get_length()); + _player->seek(_current); + _indicator->update(); +} + +void AudioStreamEditor::edit(Ref<AudioStream> p_stream) { + + if (!stream.is_null()) + stream->remove_change_receptor(this); + + stream = p_stream; + _player->set_stream(stream); + _current = 0; + String text = String::num(stream->get_length(), 2).pad_decimals(2) + "s"; + _duration_label->set_text(text); + + if (!stream.is_null()) { + stream->add_change_receptor(this); + update(); + } else { + hide(); + } +} + +void AudioStreamEditor::_bind_methods() { + + ClassDB::bind_method(D_METHOD("_preview_changed"), &AudioStreamEditor::_preview_changed); + ClassDB::bind_method(D_METHOD("_play"), &AudioStreamEditor::_play); + ClassDB::bind_method(D_METHOD("_stop"), &AudioStreamEditor::_stop); + ClassDB::bind_method(D_METHOD("_on_finished"), &AudioStreamEditor::_on_finished); + ClassDB::bind_method(D_METHOD("_draw_preview"), &AudioStreamEditor::_draw_preview); + ClassDB::bind_method(D_METHOD("_draw_indicator"), &AudioStreamEditor::_draw_indicator); + ClassDB::bind_method(D_METHOD("_on_input_indicator"), &AudioStreamEditor::_on_input_indicator); +} + +AudioStreamEditor::AudioStreamEditor() { + + set_custom_minimum_size(Size2(1, 100)); + _current = 0; + _dragging = false; + + _player = memnew(AudioStreamPlayer); + _player->connect("finished", this, "_on_finished"); + add_child(_player); + + VBoxContainer *vbox = memnew(VBoxContainer); + vbox->set_anchors_and_margins_preset(PRESET_WIDE, PRESET_MODE_MINSIZE, 0); + add_child(vbox); + + _preview = memnew(ColorRect); + _preview->set_v_size_flags(SIZE_EXPAND_FILL); + _preview->connect("draw", this, "_draw_preview"); + vbox->add_child(_preview); + + _indicator = memnew(Control); + _indicator->set_anchors_and_margins_preset(PRESET_WIDE); + _indicator->connect("draw", this, "_draw_indicator"); + _indicator->connect("gui_input", this, "_on_input_indicator"); + _preview->add_child(_indicator); + + HBoxContainer *hbox = memnew(HBoxContainer); + hbox->add_constant_override("separation", 0); + vbox->add_child(hbox); + + _play_button = memnew(ToolButton); + hbox->add_child(_play_button); + _play_button->set_focus_mode(Control::FOCUS_NONE); + _play_button->connect("pressed", this, "_play"); + + _stop_button = memnew(ToolButton); + hbox->add_child(_stop_button); + _stop_button->set_focus_mode(Control::FOCUS_NONE); + _stop_button->connect("pressed", this, "_stop"); + + _current_label = memnew(Label); + _current_label->set_align(Label::ALIGN_RIGHT); + _current_label->set_h_size_flags(SIZE_EXPAND_FILL); + _current_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + _current_label->set_modulate(Color(1, 1, 1, 0.5)); + hbox->add_child(_current_label); + + _duration_label = memnew(Label); + _duration_label->add_font_override("font", EditorNode::get_singleton()->get_gui_base()->get_font("status_source", "EditorFonts")); + hbox->add_child(_duration_label); +} + +void AudioStreamEditorPlugin::edit(Object *p_object) { + + AudioStream *s = Object::cast_to<AudioStream>(p_object); + if (!s) + return; + + audio_editor->edit(Ref<AudioStream>(s)); +} + +bool AudioStreamEditorPlugin::handles(Object *p_object) const { + + return p_object->is_class("AudioStream"); +} + +void AudioStreamEditorPlugin::make_visible(bool p_visible) { + + audio_editor->set_visible(p_visible); +} + +AudioStreamEditorPlugin::AudioStreamEditorPlugin(EditorNode *p_node) { + + editor = p_node; + audio_editor = memnew(AudioStreamEditor); + add_control_to_container(CONTAINER_PROPERTY_EDITOR_BOTTOM, audio_editor); + audio_editor->hide(); +} + +AudioStreamEditorPlugin::~AudioStreamEditorPlugin() { +} diff --git a/editor/plugins/audio_stream_editor_plugin.h b/editor/plugins/audio_stream_editor_plugin.h new file mode 100644 index 0000000000..1887874b74 --- /dev/null +++ b/editor/plugins/audio_stream_editor_plugin.h @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* audio_stream_editor_plugin.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef AUDIO_STREAM_EDITOR_PLUGIN_H +#define AUDIO_STREAM_EDITOR_PLUGIN_H + +#include "editor/editor_node.h" +#include "editor/editor_plugin.h" +#include "scene/audio/audio_player.h" +#include "scene/gui/color_rect.h" +#include "scene/resources/texture.h" + +class AudioStreamEditor : public ColorRect { + + GDCLASS(AudioStreamEditor, ColorRect); + + Ref<AudioStream> stream; + AudioStreamPlayer *_player; + ColorRect *_preview; + Control *_indicator; + Label *_current_label; + Label *_duration_label; + + ToolButton *_play_button; + ToolButton *_stop_button; + + float _current; + bool _dragging; + +protected: + void _notification(int p_what); + void _preview_changed(ObjectID p_which); + void _play(); + void _stop(); + void _on_finished(); + void _draw_preview(); + void _draw_indicator(); + void _on_input_indicator(Ref<InputEvent> p_event); + void _seek_to(real_t p_x); + void _changed_callback(Object *p_changed, const char *p_prop); + static void _bind_methods(); + +public: + void edit(Ref<AudioStream> p_stream); + AudioStreamEditor(); +}; + +class AudioStreamEditorPlugin : public EditorPlugin { + + GDCLASS(AudioStreamEditorPlugin, EditorPlugin); + + AudioStreamEditor *audio_editor; + EditorNode *editor; + +public: + virtual String get_name() const { return "Audio"; } + bool has_main_screen() const { return false; } + virtual void edit(Object *p_object); + virtual bool handles(Object *p_object) const; + virtual void make_visible(bool p_visible); + + AudioStreamEditorPlugin(EditorNode *p_node); + ~AudioStreamEditorPlugin(); +}; + +#endif // AUDIO_STREAM_EDITOR_PLUGIN_H diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index 5ec42b07aa..33e182faef 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -109,6 +109,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { action_point = i; moving_from = curve->get_point_out(i); moving_screen_from = gpoint; + orig_in_length = curve->get_point_in(action_point).length(); return true; } else if (dist_to_p_in < grab_threshold && i > 0) { @@ -116,6 +117,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { action_point = i; moving_from = curve->get_point_in(i); moving_screen_from = gpoint; + orig_out_length = curve->get_point_out(action_point).length(); return true; } } @@ -205,6 +207,11 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { undo_redo->create_action(TTR("Move In-Control in Curve")); undo_redo->add_do_method(curve.ptr(), "set_point_in", action_point, new_pos); undo_redo->add_undo_method(curve.ptr(), "set_point_in", action_point, moving_from); + + if (mirror_handle_angle) { + undo_redo->add_do_method(curve.ptr(), "set_point_out", action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_out_length)); + undo_redo->add_undo_method(curve.ptr(), "set_point_out", action_point, mirror_handle_length ? -moving_from : (-moving_from.normalized() * orig_out_length)); + } undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update"); undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update"); undo_redo->commit_action(); @@ -216,6 +223,11 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { undo_redo->create_action(TTR("Move Out-Control in Curve")); undo_redo->add_do_method(curve.ptr(), "set_point_out", action_point, new_pos); undo_redo->add_undo_method(curve.ptr(), "set_point_out", action_point, moving_from); + + if (mirror_handle_angle) { + undo_redo->add_do_method(curve.ptr(), "set_point_in", action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_in_length)); + undo_redo->add_undo_method(curve.ptr(), "set_point_in", action_point, mirror_handle_length ? -moving_from : (-moving_from.normalized() * orig_in_length)); + } undo_redo->add_do_method(canvas_item_editor->get_viewport_control(), "update"); undo_redo->add_undo_method(canvas_item_editor->get_viewport_control(), "update"); undo_redo->commit_action(); @@ -255,10 +267,16 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { case ACTION_MOVING_IN: { curve->set_point_in(action_point, new_pos); + + if (mirror_handle_angle) + curve->set_point_out(action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_out_length)); } break; case ACTION_MOVING_OUT: { curve->set_point_out(action_point, new_pos); + + if (mirror_handle_angle) + curve->set_point_in(action_point, mirror_handle_length ? -new_pos : (-new_pos.normalized() * orig_in_length)); } break; } @@ -342,6 +360,7 @@ void Path2DEditor::_bind_methods() { //ClassDB::bind_method(D_METHOD("_menu_option"),&Path2DEditor::_menu_option); ClassDB::bind_method(D_METHOD("_node_visibility_changed"), &Path2DEditor::_node_visibility_changed); ClassDB::bind_method(D_METHOD("_mode_selected"), &Path2DEditor::_mode_selected); + ClassDB::bind_method(D_METHOD("_handle_option_pressed"), &Path2DEditor::_handle_option_pressed); } void Path2DEditor::_mode_selected(int p_mode) { @@ -396,11 +415,33 @@ void Path2DEditor::_mode_selected(int p_mode) { mode = Mode(p_mode); } +void Path2DEditor::_handle_option_pressed(int p_option) { + + PopupMenu *pm; + pm = handle_menu->get_popup(); + + switch (p_option) { + case HANDLE_OPTION_ANGLE: { + bool is_checked = pm->is_item_checked(HANDLE_OPTION_ANGLE); + mirror_handle_angle = !is_checked; + pm->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle); + pm->set_item_disabled(HANDLE_OPTION_LENGTH, !mirror_handle_angle); + } break; + case HANDLE_OPTION_LENGTH: { + bool is_checked = pm->is_item_checked(HANDLE_OPTION_LENGTH); + mirror_handle_length = !is_checked; + pm->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length); + } break; + } +} + Path2DEditor::Path2DEditor(EditorNode *p_editor) { canvas_item_editor = NULL; editor = p_editor; undo_redo = editor->get_undo_redo(); + mirror_handle_angle = true; + mirror_handle_length = true; mode = MODE_EDIT; action = ACTION_NONE; @@ -444,6 +485,20 @@ Path2DEditor::Path2DEditor(EditorNode *p_editor) { curve_close->set_tooltip(TTR("Close Curve")); curve_close->connect("pressed", this, "_mode_selected", varray(ACTION_CLOSE)); base_hb->add_child(curve_close); + + PopupMenu *menu; + + handle_menu = memnew(MenuButton); + handle_menu->set_text(TTR("Options")); + base_hb->add_child(handle_menu); + + menu = handle_menu->get_popup(); + menu->add_check_item(TTR("Mirror Handle Angles")); + menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle); + menu->add_check_item(TTR("Mirror Handle Lengths")); + menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length); + menu->connect("id_pressed", this, "_handle_option_pressed"); + base_hb->hide(); curve_edit->set_pressed(true); diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h index c92a696967..1e3955f84f 100644 --- a/editor/plugins/path_2d_editor_plugin.h +++ b/editor/plugins/path_2d_editor_plugin.h @@ -69,6 +69,15 @@ class Path2DEditor : public HBoxContainer { ToolButton *curve_edit_curve; ToolButton *curve_del; ToolButton *curve_close; + MenuButton *handle_menu; + + bool mirror_handle_angle; + bool mirror_handle_length; + + enum HandleOption { + HANDLE_OPTION_ANGLE, + HANDLE_OPTION_LENGTH + }; enum Action { @@ -82,8 +91,11 @@ class Path2DEditor : public HBoxContainer { int action_point; Point2 moving_from; Point2 moving_screen_from; + float orig_in_length; + float orig_out_length; void _mode_selected(int p_mode); + void _handle_option_pressed(int p_option); void _node_visibility_changed(); friend class Path2DEditorPlugin; diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 6dde639c54..72a8b55a52 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -128,11 +128,22 @@ void PathSpatialGizmo::set_handle(int p_idx, Camera *p_camera, const Point2 &p_p if (p.intersects_ray(ray_from, ray_dir, &inters)) { + if (!PathEditorPlugin::singleton->is_handle_clicked()) { + orig_in_length = c->get_point_in(idx).length(); + orig_out_length = c->get_point_out(idx).length(); + PathEditorPlugin::singleton->set_handle_clicked(true); + } + Vector3 local = gi.xform(inters) - base; if (t == 0) { c->set_point_in(idx, local); + + if (PathEditorPlugin::singleton->mirror_angle_enabled()) + c->set_point_out(idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_out_length)); } else { c->set_point_out(idx, local); + if (PathEditorPlugin::singleton->mirror_angle_enabled()) + c->set_point_in(idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -local : (-local.normalized() * orig_in_length)); } } } @@ -165,8 +176,6 @@ void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p int idx = p_idx / 2; int t = p_idx % 2; - Vector3 ofs; - if (t == 0) { if (p_cancel) { c->set_point_in(p_idx, p_restore); @@ -176,6 +185,11 @@ void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p ur->create_action(TTR("Set Curve In Position")); ur->add_do_method(c.ptr(), "set_point_in", idx, c->get_point_in(idx)); ur->add_undo_method(c.ptr(), "set_point_in", idx, p_restore); + + if (PathEditorPlugin::singleton->mirror_angle_enabled()) { + ur->add_do_method(c.ptr(), "set_point_out", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_in(idx) : (-c->get_point_in(idx).normalized() * orig_out_length)); + ur->add_undo_method(c.ptr(), "set_point_out", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_out_length)); + } ur->commit_action(); } else { @@ -188,6 +202,11 @@ void PathSpatialGizmo::commit_handle(int p_idx, const Variant &p_restore, bool p ur->create_action(TTR("Set Curve Out Position")); ur->add_do_method(c.ptr(), "set_point_out", idx, c->get_point_out(idx)); ur->add_undo_method(c.ptr(), "set_point_out", idx, p_restore); + + if (PathEditorPlugin::singleton->mirror_angle_enabled()) { + ur->add_do_method(c.ptr(), "set_point_in", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -c->get_point_out(idx) : (-c->get_point_out(idx).normalized() * orig_in_length)); + ur->add_undo_method(c.ptr(), "set_point_in", idx, PathEditorPlugin::singleton->mirror_length_enabled() ? -static_cast<Vector3>(p_restore) : (-static_cast<Vector3>(p_restore).normalized() * orig_in_length)); + } ur->commit_action(); } } @@ -291,6 +310,9 @@ bool PathEditorPlugin::forward_spatial_gui_input(Camera *p_camera, const Ref<Inp Point2 mbpos(mb->get_position().x, mb->get_position().y); + if (!mb->is_pressed()) + set_handle_clicked(false); + if (mb->is_pressed() && mb->get_button_index() == BUTTON_LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->get_control()))) { //click into curve, break it down PoolVector<Vector3> v3a = c->tessellate(); @@ -459,6 +481,7 @@ void PathEditorPlugin::make_visible(bool p_visible) { curve_edit->show(); curve_del->show(); curve_close->show(); + handle_menu->show(); sep->show(); } else { @@ -466,6 +489,7 @@ void PathEditorPlugin::make_visible(bool p_visible) { curve_edit->hide(); curve_del->hide(); curve_close->hide(); + handle_menu->hide(); sep->hide(); { @@ -495,6 +519,26 @@ void PathEditorPlugin::_close_curve() { c->add_point(c->get_point_position(0), c->get_point_in(0), c->get_point_out(0)); } +void PathEditorPlugin::_handle_option_pressed(int p_option) { + + PopupMenu *pm; + pm = handle_menu->get_popup(); + + switch (p_option) { + case HANDLE_OPTION_ANGLE: { + bool is_checked = pm->is_item_checked(HANDLE_OPTION_ANGLE); + mirror_handle_angle = !is_checked; + pm->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle); + pm->set_item_disabled(HANDLE_OPTION_LENGTH, !mirror_handle_angle); + } break; + case HANDLE_OPTION_LENGTH: { + bool is_checked = pm->is_item_checked(HANDLE_OPTION_LENGTH); + mirror_handle_length = !is_checked; + pm->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length); + } break; + } +} + void PathEditorPlugin::_notification(int p_what) { if (p_what == NOTIFICATION_ENTER_TREE) { @@ -510,6 +554,7 @@ void PathEditorPlugin::_bind_methods() { ClassDB::bind_method(D_METHOD("_mode_changed"), &PathEditorPlugin::_mode_changed); ClassDB::bind_method(D_METHOD("_close_curve"), &PathEditorPlugin::_close_curve); + ClassDB::bind_method(D_METHOD("_handle_option_pressed"), &PathEditorPlugin::_handle_option_pressed); } PathEditorPlugin *PathEditorPlugin::singleton = NULL; @@ -519,6 +564,8 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) { path = NULL; editor = p_node; singleton = this; + mirror_handle_angle = true; + mirror_handle_length = true; path_material = Ref<SpatialMaterial>(memnew(SpatialMaterial)); path_material->set_albedo(Color(0.5, 0.5, 1.0, 0.8)); @@ -567,6 +614,20 @@ PathEditorPlugin::PathEditorPlugin(EditorNode *p_node) { curve_close->set_tooltip(TTR("Close Curve")); SpatialEditor::get_singleton()->add_control_to_menu_panel(curve_close); + PopupMenu *menu; + + handle_menu = memnew(MenuButton); + handle_menu->set_text(TTR("Options")); + handle_menu->hide(); + SpatialEditor::get_singleton()->add_control_to_menu_panel(handle_menu); + + menu = handle_menu->get_popup(); + menu->add_check_item(TTR("Mirror Handle Angles")); + menu->set_item_checked(HANDLE_OPTION_ANGLE, mirror_handle_angle); + menu->add_check_item(TTR("Mirror Handle Lengths")); + menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length); + menu->connect("id_pressed", this, "_handle_option_pressed"); + curve_edit->set_pressed(true); /* collision_polygon_editor = memnew( PathEditor(p_node) ); diff --git a/editor/plugins/path_editor_plugin.h b/editor/plugins/path_editor_plugin.h index 6d5f07f729..52dfb78b61 100644 --- a/editor/plugins/path_editor_plugin.h +++ b/editor/plugins/path_editor_plugin.h @@ -1,4 +1,4 @@ -/*************************************************************************/ +/*************************************************************************/ /* path_editor_plugin.h */ /*************************************************************************/ /* This file is part of: */ @@ -40,6 +40,8 @@ class PathSpatialGizmo : public EditorSpatialGizmo { Path *path; mutable Vector3 original; + mutable float orig_in_length; + mutable float orig_out_length; public: virtual String get_handle_name(int p_idx) const; @@ -60,6 +62,7 @@ class PathEditorPlugin : public EditorPlugin { ToolButton *curve_edit; ToolButton *curve_del; ToolButton *curve_close; + MenuButton *handle_menu; EditorNode *editor; @@ -67,6 +70,15 @@ class PathEditorPlugin : public EditorPlugin { void _mode_changed(int p_idx); void _close_curve(); + void _handle_option_pressed(int p_option); + bool handle_clicked; + bool mirror_handle_angle; + bool mirror_handle_length; + + enum HandleOption { + HANDLE_OPTION_ANGLE, + HANDLE_OPTION_LENGTH + }; protected: void _notification(int p_what); @@ -88,6 +100,11 @@ public: virtual bool handles(Object *p_object) const; virtual void make_visible(bool p_visible); + bool mirror_angle_enabled() { return mirror_handle_angle; } + bool mirror_length_enabled() { return mirror_handle_length; } + bool is_handle_clicked() { return handle_clicked; } + void set_handle_clicked(bool clicked) { handle_clicked = clicked; } + PathEditorPlugin(EditorNode *p_node); ~PathEditorPlugin(); }; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 9a351c26fa..682ca744ff 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -768,17 +768,17 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("VectorOp", "Operators", "VisualShaderNodeVectorOp")); add_options.push_back(AddOption("ColorOp", "Operators", "VisualShaderNodeColorOp")); add_options.push_back(AddOption("TransformMult", "Operators", "VisualShaderNodeTransformMult")); - add_options.push_back(AddOption("TransformVecMult", "Operators", "VisualShaderNodeTransformVecMult")); + add_options.push_back(AddOption("TransformVectorMult", "Operators", "VisualShaderNodeTransformVecMult")); add_options.push_back(AddOption("ScalarFunc", "Functions", "VisualShaderNodeScalarFunc")); add_options.push_back(AddOption("VectorFunc", "Functions", "VisualShaderNodeVectorFunc")); add_options.push_back(AddOption("DotProduct", "Functions", "VisualShaderNodeDotProduct")); add_options.push_back(AddOption("VectorLen", "Functions", "VisualShaderNodeVectorLen")); add_options.push_back(AddOption("ScalarInterp", "Interpolation", "VisualShaderNodeScalarInterp")); add_options.push_back(AddOption("VectorInterp", "Interpolation", "VisualShaderNodeVectorInterp")); - add_options.push_back(AddOption("VectorConstruct", "Construct", "VisualShaderNodeVectorConstruct")); - add_options.push_back(AddOption("TransformConstruct", "Construct", "VisualShaderNodeTransformConstruct")); - add_options.push_back(AddOption("VectorDestruct", "Destruct", "VisualShaderNodeVectorDestruct")); - add_options.push_back(AddOption("TransformDestruct", "Destruct", "VisualShaderNodeTransformDestruct")); + add_options.push_back(AddOption("VectorCompose", "Compose", "VisualShaderNodeVectorCompose")); + add_options.push_back(AddOption("TransformCompose", "Compose", "VisualShaderNodeTransformCompose")); + add_options.push_back(AddOption("VectorDecompose", "Decompose", "VisualShaderNodeVectorDecompose")); + add_options.push_back(AddOption("TransformDecompose", "Decompose", "VisualShaderNodeTransformDecompose")); add_options.push_back(AddOption("Scalar", "Uniforms", "VisualShaderNodeScalarUniform")); add_options.push_back(AddOption("Vector", "Uniforms", "VisualShaderNodeVec3Uniform")); add_options.push_back(AddOption("Color", "Uniforms", "VisualShaderNodeColorUniform")); diff --git a/editor/project_export.cpp b/editor/project_export.cpp index 9f87fc82b5..170546f14c 100644 --- a/editor/project_export.cpp +++ b/editor/project_export.cpp @@ -76,6 +76,9 @@ void ProjectExportDialog::popup_export() { } _update_presets(); + if (presets->get_current() >= 0) { + _edit_preset(presets->get_current()); // triggers rescan for templates if newly installed + } // Restore valid window bounds or pop up at default size. if (EditorSettings::get_singleton()->has_setting("interface/dialogs/export_bounds")) { @@ -154,7 +157,6 @@ void ProjectExportDialog::_update_presets() { if (current_idx != -1) { presets->select(current_idx); - //_edit_preset(current_idx); } updating = false; @@ -167,6 +169,7 @@ void ProjectExportDialog::_edit_preset(int p_index) { name->set_editable(false); runnable->set_disabled(true); parameters->edit(NULL); + presets->unselect_all(); delete_preset->set_disabled(true); sections->hide(); patches->clear(); @@ -438,11 +441,9 @@ void ProjectExportDialog::_delete_preset() { void ProjectExportDialog::_delete_preset_confirm() { int idx = presets->get_current(); - parameters->edit(NULL); //to avoid crash _edit_preset(-1); EditorExport::get_singleton()->remove_export_preset(idx); _update_presets(); - _edit_preset(presets->get_current()); } Variant ProjectExportDialog::get_drag_data_fw(const Point2 &p_point, Control *p_from) { diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp index 8c7565a441..7e4e589bb4 100644 --- a/editor/project_settings_editor.cpp +++ b/editor/project_settings_editor.cpp @@ -394,6 +394,7 @@ void ProjectSettingsEditor::_show_last_added(const Ref<InputEvent> &p_event, con while (child) { Variant input = child->get_meta("__input"); if (p_event == input) { + r->set_collapsed(false); child->select(0); found = true; break; @@ -654,6 +655,14 @@ void ProjectSettingsEditor::_update_actions() { if (setting) return; + Map<String, bool> collapsed; + + if (input_editor->get_root() && input_editor->get_root()->get_children()) { + for (TreeItem *item = input_editor->get_root()->get_children(); item; item = item->get_next()) { + collapsed[item->get_text(0)] = item->is_collapsed(); + } + } + input_editor->clear(); TreeItem *root = input_editor->create_item(); input_editor->set_hide_root(true); @@ -677,6 +686,8 @@ void ProjectSettingsEditor::_update_actions() { TreeItem *item = input_editor->create_item(root); item->set_text(0, name); item->set_custom_bg_color(0, get_color("prop_subsection", "Editor")); + if (collapsed.has(name)) + item->set_collapsed(collapsed[name]); item->set_editable(1, true); item->set_cell_mode(1, TreeItem::CELL_MODE_RANGE); diff --git a/editor/spatial_editor_gizmos.cpp b/editor/spatial_editor_gizmos.cpp index 3b0ac8864a..c45dea0df7 100644 --- a/editor/spatial_editor_gizmos.cpp +++ b/editor/spatial_editor_gizmos.cpp @@ -3272,10 +3272,10 @@ NavigationMeshSpatialGizmo::NavigationMeshSpatialGizmo(NavigationMeshInstance *p navmesh = p_navmesh; } - ////// - /// - /// - /// +////// +/// +/// +/// #define BODY_A_RADIUS 0.25 #define BODY_B_RADIUS 0.27 |