diff options
Diffstat (limited to 'editor')
88 files changed, 1031 insertions, 657 deletions
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp index 014bb08144..c93dc2b340 100644 --- a/editor/animation_track_editor.cpp +++ b/editor/animation_track_editor.cpp @@ -1748,7 +1748,11 @@ void AnimationTimelineEdit::_play_position_draw() { if (px >= get_name_limit() && px < (play_position->get_size().width - get_buttons_width())) { Color color = get_color("accent_color", "Editor"); - play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(EDSCALE)); + play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE)); + play_position->draw_texture( + get_icon("TimelineIndicator", "EditorIcons"), + Point2(px - get_icon("TimelineIndicator", "EditorIcons")->get_width() * 0.5, 0), + color); } } @@ -2438,7 +2442,7 @@ void AnimationTrackEdit::_play_position_draw() { if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) { Color color = get_color("accent_color", "Editor"); - play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(EDSCALE)); + play_position->draw_line(Point2(px, 0), Point2(px, h), color, Math::round(2 * EDSCALE)); } } @@ -3184,7 +3188,7 @@ void AnimationTrackEditGroup::_notification(int p_what) { if (px >= timeline->get_name_limit() && px < (get_size().width - timeline->get_buttons_width())) { Color accent = get_color("accent_color", "Editor"); - draw_line(Point2(px, 0), Point2(px, get_size().height), accent, Math::round(EDSCALE)); + draw_line(Point2(px, 0), Point2(px, get_size().height), accent, Math::round(2 * EDSCALE)); } } } @@ -5050,10 +5054,9 @@ float AnimationTrackEditor::get_moving_selection_offset() const { void AnimationTrackEditor::_box_selection_draw() { - Color color = get_color("accent_color", "Editor"); - color.a = 0.2; - Rect2 rect = Rect2(Point2(), box_selection->get_size()); - box_selection->draw_rect(rect, color); + const Rect2 selection_rect = Rect2(Point2(), box_selection->get_size()); + box_selection->draw_rect(selection_rect, get_color("box_selection_fill_color", "Editor")); + box_selection->draw_rect(selection_rect, get_color("box_selection_stroke_color", "Editor"), false, Math::round(EDSCALE)); } void AnimationTrackEditor::_scroll_input(const Ref<InputEvent> &p_event) { diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 89a88dc6e7..33af5927b3 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -163,16 +163,17 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) result_col = col; _update_results_count(); - set_error(vformat(TTR("Found %d match(es)."), results_count)); } else { + results_count = 0; result_line = -1; result_col = -1; text_edit->set_search_text(""); text_edit->set_search_flags(p_flags); text_edit->set_current_search_result(line, col); - set_error(text.empty() ? "" : TTR("No Matches")); } + _update_matches_label(); + return found; } @@ -196,7 +197,7 @@ void FindReplaceBar::_replace() { void FindReplaceBar::_replace_all() { text_edit->disconnect("text_changed", this, "_editor_text_changed"); - // line as x so it gets priority in comparison, column as y + // Line as x so it gets priority in comparison, column as y. Point2i orig_cursor(text_edit->cursor_get_line(), text_edit->cursor_get_column()); Point2i prev_match = Point2(-1, -1); @@ -228,7 +229,7 @@ void FindReplaceBar::_replace_all() { Point2i match_to(result_line, result_col + search_text_len); if (match_from < prev_match) { - break; // done + break; // Done. } prev_match = Point2i(result_line, result_col + replace_text.length()); @@ -241,14 +242,14 @@ void FindReplaceBar::_replace_all() { continue; } - // replace but adjust selection bounds + // Replace but adjust selection bounds. text_edit->insert_text_at_cursor(replace_text); if (match_to.x == selection_end.x) { selection_end.y += replace_text.length() - search_text_len; } } else { - // just replace + // Just replace. text_edit->insert_text_at_cursor(replace_text); } @@ -260,12 +261,12 @@ void FindReplaceBar::_replace_all() { replace_all_mode = false; - // restore editor state (selection, cursor, scroll) + // Restore editor state (selection, cursor, scroll). text_edit->cursor_set_line(orig_cursor.x); text_edit->cursor_set_column(orig_cursor.y); if (selection_enabled && is_selection_only()) { - // reselect + // Reselect. text_edit->select(selection_begin.x, selection_begin.y, selection_end.x, selection_end.y); } else { text_edit->deselect(); @@ -283,20 +284,6 @@ void FindReplaceBar::_get_search_from(int &r_line, int &r_col) { r_line = text_edit->cursor_get_line(); r_col = text_edit->cursor_get_column(); - if (text_edit->is_selection_active() && !replace_all_mode) { - - int selection_line = text_edit->get_selection_from_line(); - - if (text_edit->get_selection_text() == get_search_text() && r_line == selection_line) { - - int selection_from_col = text_edit->get_selection_from_column(); - - if (r_col >= selection_from_col && r_col <= text_edit->get_selection_to_column()) { - r_col = selection_from_col; - } - } - } - if (r_line == result_line && r_col >= result_col && r_col <= result_col + get_search_text().length()) { r_col = result_col; } @@ -332,6 +319,18 @@ void FindReplaceBar::_update_results_count() { } } +void FindReplaceBar::_update_matches_label() { + + if (search_text->get_text().empty() || results_count == -1) { + matches_label->hide(); + } else { + matches_label->show(); + + matches_label->add_color_override("font_color", results_count > 0 ? Color(1, 1, 1) : EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); + matches_label->set_text(vformat(results_count == 1 ? TTR("%d match.") : TTR("%d matches."), results_count)); + } +} + bool FindReplaceBar::search_current() { uint32_t flags = 0; @@ -349,6 +348,9 @@ bool FindReplaceBar::search_current() { bool FindReplaceBar::search_prev() { + if (!is_visible()) + popup_search(true); + uint32_t flags = 0; String text = get_search_text(); @@ -361,13 +363,17 @@ bool FindReplaceBar::search_prev() { int line, col; _get_search_from(line, col); + if (text_edit->is_selection_active()) + col--; // Skip currently selected word. - col -= text.length(); - if (col < 0) { - line -= 1; - if (line < 0) - line = text_edit->get_line_count() - 1; - col = text_edit->get_line(line).length(); + if (line == result_line && col == result_col) { + col -= text.length(); + if (col < 0) { + line -= 1; + if (line < 0) + line = text_edit->get_line_count() - 1; + col = text_edit->get_line(line).length(); + } } return _search(flags, line, col); @@ -375,6 +381,9 @@ bool FindReplaceBar::search_prev() { bool FindReplaceBar::search_next() { + if (!is_visible()) + popup_search(true); + uint32_t flags = 0; String text; if (replace_all_mode) @@ -411,38 +420,54 @@ void FindReplaceBar::_hide_bar() { text_edit->set_search_text(""); result_line = -1; result_col = -1; - set_error(""); hide(); } -void FindReplaceBar::_show_search() { +void FindReplaceBar::_show_search(bool p_focus_replace, bool p_show_only) { show(); - search_text->call_deferred("grab_focus"); + if (p_show_only) + return; + + if (p_focus_replace) { + search_text->deselect(); + replace_text->call_deferred("grab_focus"); + } else { + replace_text->deselect(); + search_text->call_deferred("grab_focus"); + } if (text_edit->is_selection_active() && !selection_only->is_pressed()) { search_text->set_text(text_edit->get_selection_text()); } if (!get_search_text().empty()) { - search_text->select_all(); - search_text->set_cursor_position(search_text->get_text().length()); - search_current(); + if (p_focus_replace) { + replace_text->select_all(); + replace_text->set_cursor_position(replace_text->get_text().length()); + } else { + search_text->select_all(); + search_text->set_cursor_position(search_text->get_text().length()); + } + + results_count = -1; + _update_results_count(); + _update_matches_label(); } } -void FindReplaceBar::popup_search() { +void FindReplaceBar::popup_search(bool p_show_only) { - replace_text->hide(); + if (!is_visible()) + replace_text->hide(); hbc_button_replace->hide(); hbc_option_replace->hide(); - _show_search(); + _show_search(false, p_show_only); } void FindReplaceBar::popup_replace() { if (!replace_text->is_visible_in_tree()) { - replace_text->clear(); replace_text->show(); hbc_button_replace->show(); hbc_option_replace->show(); @@ -450,7 +475,7 @@ void FindReplaceBar::popup_replace() { selection_only->set_pressed((text_edit->is_selection_active() && text_edit->get_selection_from_line() < text_edit->get_selection_to_line())); - _show_search(); + _show_search(is_visible() || text_edit->is_selection_active()); } void FindReplaceBar::_search_options_changed(bool p_pressed) { @@ -557,6 +582,7 @@ FindReplaceBar::FindReplaceBar() { vbc_lineedit = memnew(VBoxContainer); add_child(vbc_lineedit); + vbc_lineedit->set_alignment(ALIGN_CENTER); vbc_lineedit->set_h_size_flags(SIZE_EXPAND_FILL); VBoxContainer *vbc_button = memnew(VBoxContainer); add_child(vbc_button); @@ -565,8 +591,10 @@ FindReplaceBar::FindReplaceBar() { HBoxContainer *hbc_button_search = memnew(HBoxContainer); vbc_button->add_child(hbc_button_search); + hbc_button_search->set_alignment(ALIGN_END); hbc_button_replace = memnew(HBoxContainer); vbc_button->add_child(hbc_button_replace); + hbc_button_replace->set_alignment(ALIGN_END); HBoxContainer *hbc_option_search = memnew(HBoxContainer); vbc_option->add_child(hbc_option_search); @@ -580,6 +608,10 @@ FindReplaceBar::FindReplaceBar() { search_text->connect("text_changed", this, "_search_text_changed"); search_text->connect("text_entered", this, "_search_text_entered"); + matches_label = memnew(Label); + hbc_button_search->add_child(matches_label); + matches_label->hide(); + find_prev = memnew(ToolButton); hbc_button_search->add_child(find_prev); find_prev->set_focus_mode(FOCUS_NONE); @@ -720,7 +752,7 @@ void CodeTextEditor::_zoom_changed() { } void CodeTextEditor::_reset_zoom() { - Ref<DynamicFont> font = text_editor->get_font("font"); // reset source font size to default + Ref<DynamicFont> font = text_editor->get_font("font"); // Reset source font size to default. if (font.is_valid()) { EditorSettings::get_singleton()->set("interface/editor/code_font_size", 14); @@ -1230,7 +1262,7 @@ void CodeTextEditor::toggle_inline_comment(const String &delimiter) { int col_to = text_editor->get_selection_to_column(); int cursor_pos = text_editor->cursor_get_column(); - // Check if all lines in the selected block are commented + // Check if all lines in the selected block are commented. bool is_commented = true; for (int i = begin; i <= end; i++) { if (!text_editor->get_line(i).begins_with(delimiter)) { @@ -1425,14 +1457,14 @@ void CodeTextEditor::_on_settings_change() { font_size = EditorSettings::get_singleton()->get("interface/editor/code_font_size"); - // AUTO BRACE COMPLETION + // Auto brace completion. text_editor->set_auto_brace_completion( EDITOR_GET("text_editor/completion/auto_brace_complete")); code_complete_timer->set_wait_time( EDITOR_GET("text_editor/completion/code_complete_delay")); - // call hint settings + // Call hint settings. text_editor->set_callhint_settings( EDITOR_GET("text_editor/completion/put_callhint_tooltip_below_current_line"), EDITOR_GET("text_editor/completion/callhint_tooltip_offset")); diff --git a/editor/code_editor.h b/editor/code_editor.h index 700e72627c..f2a55cfb70 100644 --- a/editor/code_editor.h +++ b/editor/code_editor.h @@ -64,6 +64,7 @@ class FindReplaceBar : public HBoxContainer { GDCLASS(FindReplaceBar, HBoxContainer); LineEdit *search_text; + Label *matches_label; ToolButton *find_prev; ToolButton *find_next; CheckBox *case_sensitive; @@ -90,8 +91,9 @@ class FindReplaceBar : public HBoxContainer { void _get_search_from(int &r_line, int &r_col); void _update_results_count(); + void _update_matches_label(); - void _show_search(); + void _show_search(bool p_focus_replace = false, bool p_show_only = false); void _hide_bar(); void _editor_text_changed(); @@ -123,7 +125,7 @@ public: void set_text_edit(TextEdit *p_text_edit); - void popup_search(); + void popup_search(bool p_show_only = false); void popup_replace(); bool search_current(); diff --git a/editor/collada/collada.cpp b/editor/collada/collada.cpp index edd59f3057..aea7f461f1 100644 --- a/editor/collada/collada.cpp +++ b/editor/collada/collada.cpp @@ -1903,8 +1903,7 @@ void Collada::_parse_animation(XMLParser &parser) { Vector<float> &output = float_sources[output_id]; - ERR_EXPLAIN("Wrong number of keys in output"); - ERR_CONTINUE((output.size() / stride) != key_count); + ERR_CONTINUE_MSG((output.size() / stride) != key_count, "Wrong number of keys in output."); for (int j = 0; j < key_count; j++) { track.keys.write[j].data.resize(output_len); @@ -2447,8 +2446,7 @@ void Collada::_find_morph_nodes(VisualScene *p_vscene, Node *p_node) { state.morph_ownership_map[base] = nj->id; break; } else { - ERR_EXPLAIN("Invalid scene"); - ERR_FAIL(); + ERR_FAIL_MSG("Invalid scene."); } } } diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp index 48bc409b73..c5b81c4685 100644 --- a/editor/connections_dialog.cpp +++ b/editor/connections_dialog.cpp @@ -881,7 +881,6 @@ void ConnectionsDock::update_tree() { icon = get_icon(scr->get_class(), "EditorIcons"); } } - } else { ClassDB::get_signal_list(base, &node_signals2, true); @@ -891,6 +890,10 @@ void ConnectionsDock::update_tree() { name = base; } + if (!icon.is_valid()) { + icon = get_icon("Object", "EditorIcons"); + } + TreeItem *pitem = NULL; if (node_signals2.size()) { @@ -939,7 +942,7 @@ void ConnectionsDock::update_tree() { item->set_metadata(0, sinfo); item->set_icon(0, get_icon("Signal", "EditorIcons")); - // Set tooltip with the signal's documentation + // Set tooltip with the signal's documentation. { String descr; bool found = false; diff --git a/editor/create_dialog.h b/editor/create_dialog.h index f6c3b57589..f3ed1d7af6 100644 --- a/editor/create_dialog.h +++ b/editor/create_dialog.h @@ -38,9 +38,6 @@ #include "scene/gui/label.h" #include "scene/gui/line_edit.h" #include "scene/gui/tree.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class CreateDialog : public ConfirmationDialog { diff --git a/editor/doc/doc_data.cpp b/editor/doc/doc_data.cpp index 5b8c8fffb8..0f99e2ba1e 100644 --- a/editor/doc/doc_data.cpp +++ b/editor/doc/doc_data.cpp @@ -720,8 +720,7 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> & methods.push_back(method); } else { - ERR_EXPLAIN("Invalid tag in doc file: " + parser->get_node_name()); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + parser->get_node_name() + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == section) @@ -841,8 +840,7 @@ Error DocData::_load(Ref<XMLParser> parser) { if (parser->get_node_type() == XMLParser::NODE_TEXT) c.tutorials.push_back(parser->get_node_data().strip_edges()); } else { - ERR_EXPLAIN("Invalid tag in doc file: " + name3); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "tutorials") break; //end of <tutorials> @@ -883,8 +881,7 @@ Error DocData::_load(Ref<XMLParser> parser) { prop2.description = parser->get_node_data(); c.properties.push_back(prop2); } else { - ERR_EXPLAIN("Invalid tag in doc file: " + name3); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "members") @@ -912,8 +909,7 @@ Error DocData::_load(Ref<XMLParser> parser) { prop2.description = parser->get_node_data(); c.theme_properties.push_back(prop2); } else { - ERR_EXPLAIN("Invalid tag in doc file: " + name3); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "theme_items") @@ -943,8 +939,7 @@ Error DocData::_load(Ref<XMLParser> parser) { constant2.description = parser->get_node_data(); c.constants.push_back(constant2); } else { - ERR_EXPLAIN("Invalid tag in doc file: " + name3); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name3 + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "constants") @@ -953,8 +948,7 @@ Error DocData::_load(Ref<XMLParser> parser) { } else { - ERR_EXPLAIN("Invalid tag in doc file: " + name2); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Invalid tag in doc file: " + name2 + "."); } } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END && parser->get_node_name() == "class") @@ -991,10 +985,8 @@ Error DocData::save_classes(const String &p_default_path, const Map<String, Stri Error err; String save_file = save_path.plus_file(c.name + ".xml"); FileAccessRef f = FileAccess::open(save_file, FileAccess::WRITE, &err); - if (err) { - ERR_EXPLAIN("Can't write doc file: " + save_file); - ERR_CONTINUE(err); - } + + ERR_CONTINUE_MSG(err != OK, "Can't write doc file: " + save_file + "."); _write_string(f, 0, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>"); diff --git a/editor/editor_about.h b/editor/editor_about.h index 87e824083e..e2ba366c65 100644 --- a/editor/editor_about.h +++ b/editor/editor_about.h @@ -43,9 +43,6 @@ #include "scene/gui/tree.h" #include "editor_scale.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class EditorAbout : public AcceptDialog { diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp index 7210211d90..555a7f99c8 100644 --- a/editor/editor_autoload_settings.cpp +++ b/editor/editor_autoload_settings.cpp @@ -315,8 +315,7 @@ void EditorAutoloadSettings::_autoload_file_callback(const String &p_path) { Node *EditorAutoloadSettings::_create_autoload(const String &p_path) { RES res = ResourceLoader::load(p_path); - ERR_EXPLAIN("Can't autoload: " + p_path); - ERR_FAIL_COND_V(res.is_null(), NULL); + ERR_FAIL_COND_V_MSG(res.is_null(), NULL, "Can't autoload: " + p_path + "."); Node *n = NULL; if (res->is_class("PackedScene")) { Ref<PackedScene> ps = res; @@ -325,20 +324,17 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) { Ref<Script> s = res; StringName ibt = s->get_instance_base_type(); bool valid_type = ClassDB::is_parent_class(ibt, "Node"); - ERR_EXPLAIN("Script does not inherit a Node: " + p_path); - ERR_FAIL_COND_V(!valid_type, NULL); + ERR_FAIL_COND_V_MSG(!valid_type, NULL, "Script does not inherit a Node: " + p_path + "."); Object *obj = ClassDB::instance(ibt); - ERR_EXPLAIN("Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt)); - ERR_FAIL_COND_V(obj == NULL, NULL); + ERR_FAIL_COND_V_MSG(obj == NULL, NULL, "Cannot instance script for autoload, expected 'Node' inheritance, got: " + String(ibt) + "."); n = Object::cast_to<Node>(obj); n->set_script(s.get_ref_ptr()); } - ERR_EXPLAIN("Path in autoload not a node or script: " + p_path); - ERR_FAIL_COND_V(!n, NULL); + ERR_FAIL_COND_V_MSG(!n, NULL, "Path in autoload not a node or script: " + p_path + "."); return n; } diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp index f5846c10f6..c98635d16b 100644 --- a/editor/editor_data.cpp +++ b/editor/editor_data.cpp @@ -537,6 +537,7 @@ int EditorData::add_edited_scene(int p_at_pos) { p_at_pos = edited_scene.size(); EditedScene es; es.root = NULL; + es.path = String(); es.history_current = -1; es.version = 0; es.live_edit_root = NodePath(String("/root")); @@ -653,6 +654,8 @@ bool EditorData::check_and_update_scene(int p_idx) { memdelete(edited_scene[p_idx].root); edited_scene.write[p_idx].root = new_scene; + if (new_scene->get_filename() != "") + edited_scene.write[p_idx].path = new_scene->get_filename(); edited_scene.write[p_idx].selection = new_selection; return true; @@ -684,6 +687,12 @@ void EditorData::set_edited_scene_root(Node *p_root) { ERR_FAIL_INDEX(current_edited_scene, edited_scene.size()); edited_scene.write[current_edited_scene].root = p_root; + if (p_root) { + if (p_root->get_filename() != "") + edited_scene.write[current_edited_scene].path = p_root->get_filename(); + else + p_root->set_filename(edited_scene[current_edited_scene].path); + } } int EditorData::get_edited_scene_count() const { @@ -773,6 +782,7 @@ String EditorData::get_scene_title(int p_idx) const { void EditorData::set_scene_path(int p_idx, const String &p_path) { ERR_FAIL_INDEX(p_idx, edited_scene.size()); + edited_scene.write[p_idx].path = p_path; if (!edited_scene[p_idx].root) return; @@ -783,9 +793,14 @@ String EditorData::get_scene_path(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), String()); - if (!edited_scene[p_idx].root) - return ""; - return edited_scene[p_idx].root->get_filename(); + if (edited_scene[p_idx].root) { + if (edited_scene[p_idx].root->get_filename() == "") + edited_scene[p_idx].root->set_filename(edited_scene[p_idx].path); + else + return edited_scene[p_idx].root->get_filename(); + } + + return edited_scene[p_idx].path; } void EditorData::set_edited_scene_live_edit_root(const NodePath &p_root) { diff --git a/editor/editor_data.h b/editor/editor_data.h index 845878e070..df83135942 100644 --- a/editor/editor_data.h +++ b/editor/editor_data.h @@ -117,6 +117,7 @@ public: struct EditedScene { Node *root; + String path; Dictionary editor_states; List<Node *> selection; Vector<EditorHistory::History> history_stored; diff --git a/editor/editor_export.cpp b/editor/editor_export.cpp index ed262d9c4f..cb1754bb10 100644 --- a/editor/editor_export.cpp +++ b/editor/editor_export.cpp @@ -35,6 +35,7 @@ #include "core/io/resource_saver.h" #include "core/io/zip_io.h" #include "core/math/crypto_core.h" +#include "core/os/dir_access.h" #include "core/os/file_access.h" #include "core/project_settings.h" #include "core/script_language.h" @@ -884,6 +885,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> & String engine_cfb = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmp" + config_file); ProjectSettings::get_singleton()->save_custom(engine_cfb, custom_map, custom_list); Vector<uint8_t> data = FileAccess::get_file_as_array(engine_cfb); + DirAccess::remove_file_or_error(engine_cfb); p_func(p_udata, "res://" + config_file, data, idx, total); @@ -916,8 +918,10 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c memdelete(ftmp); //close tmp file - if (err) + if (err != OK) { + DirAccess::remove_file_or_error(tmppath); return err; + } pd.file_ofs.sort(); //do sort, so we can do binary search later @@ -926,11 +930,17 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c if (!p_embed) { // Regular output to separate PCK file f = FileAccess::open(p_path, FileAccess::WRITE); - ERR_FAIL_COND_V(!f, ERR_CANT_CREATE); + if (!f) { + DirAccess::remove_file_or_error(tmppath); + ERR_FAIL_V(ERR_CANT_CREATE); + } } else { // Append to executable f = FileAccess::open(p_path, FileAccess::READ_WRITE); - ERR_FAIL_COND_V(!f, ERR_FILE_CANT_OPEN); + if (!f) { + DirAccess::remove_file_or_error(tmppath); + ERR_FAIL_V(ERR_FILE_CANT_OPEN); + } f->seek_end(); embed_pos = f->get_position(); @@ -995,13 +1005,13 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c f->store_8(0); } - //save the rest of the data + // Save the rest of the data. ftmp = FileAccess::open(tmppath, FileAccess::READ); if (!ftmp) { memdelete(f); - ERR_EXPLAIN("Can't open file to read from path: " + String(tmppath)); - ERR_FAIL_V(ERR_CANT_CREATE); + DirAccess::remove_file_or_error(tmppath); + ERR_FAIL_V_MSG(ERR_CANT_CREATE, "Can't open file to read from path: " + String(tmppath) + "."); } const int bufsize = 16384; @@ -1035,6 +1045,7 @@ Error EditorExportPlatform::save_pack(const Ref<EditorExportPreset> &p_preset, c } memdelete(f); + DirAccess::remove_file_or_error(tmppath); return OK; } @@ -1043,8 +1054,6 @@ Error EditorExportPlatform::save_zip(const Ref<EditorExportPreset> &p_preset, co EditorProgress ep("savezip", TTR("Packing"), 102, true); - //FileAccess *tmp = FileAccess::open(tmppath,FileAccess::WRITE); - FileAccess *src_f; zlib_filefunc_def io = zipio_create_io_from_file(&src_f); zipFile zip = zipOpen2(p_path.utf8().get_data(), APPEND_STATUS_CREATE, NULL, &io); @@ -1694,11 +1703,18 @@ void EditorExportTextSceneToBinaryPlugin::_export_file(const String &p_path, con bool convert = GLOBAL_GET("editor/convert_text_resources_to_binary_on_export"); if (!convert) return; - String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("file.res"); + String tmp_path = EditorSettings::get_singleton()->get_cache_dir().plus_file("tmpfile.res"); Error err = ResourceFormatLoaderText::convert_file_to_binary(p_path, tmp_path); - ERR_FAIL_COND(err != OK); + if (err != OK) { + DirAccess::remove_file_or_error(tmp_path); + ERR_FAIL(); + } Vector<uint8_t> data = FileAccess::get_file_as_array(tmp_path); - ERR_FAIL_COND(data.size() == 0); + if (data.size() == 0) { + DirAccess::remove_file_or_error(tmp_path); + ERR_FAIL(); + } + DirAccess::remove_file_or_error(tmp_path); add_file(p_path + ".converted.res", data, true); } diff --git a/editor/editor_file_dialog.cpp b/editor/editor_file_dialog.cpp index 1f43740858..8c9aedc7b7 100644 --- a/editor/editor_file_dialog.cpp +++ b/editor/editor_file_dialog.cpp @@ -257,6 +257,7 @@ void EditorFileDialog::_post_popup() { if (is_visible_in_tree()) { Ref<Texture> folder = get_icon("folder", "FileDialog"); + const Color folder_color = get_color("folder", "FileDialog"); recent->clear(); bool res = access == ACCESS_RESOURCES; @@ -274,6 +275,7 @@ void EditorFileDialog::_post_popup() { recent->add_item(name, folder); recent->set_item_metadata(recent->get_item_count() - 1, recentd[i]); + recent->set_item_icon_modulate(recent->get_item_count() - 1, folder_color); } local_history.clear(); @@ -734,6 +736,7 @@ void EditorFileDialog::update_file_list() { dir_access->list_dir_begin(); Ref<Texture> folder = get_icon("folder", "FileDialog"); + const Color folder_color = get_color("folder", "FileDialog"); List<String> files; List<String> dirs; @@ -774,6 +777,7 @@ void EditorFileDialog::update_file_list() { d["dir"] = true; item_list->set_item_metadata(item_list->get_item_count() - 1, d); + item_list->set_item_icon_modulate(item_list->get_item_count() - 1, folder_color); dirs.pop_front(); } @@ -1200,6 +1204,7 @@ void EditorFileDialog::_update_favorites() { String current = get_current_dir(); Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons"); + const Color folder_color = get_color("folder", "FileDialog"); favorites->clear(); favorite->set_pressed(false); @@ -1230,6 +1235,7 @@ void EditorFileDialog::_update_favorites() { } favorites->set_item_metadata(favorites->get_item_count() - 1, favorited[i]); + favorites->set_item_icon_modulate(favorites->get_item_count() - 1, folder_color); if (setthis) { favorite->set_pressed(true); diff --git a/editor/editor_file_dialog.h b/editor/editor_file_dialog.h index 86bf0f0eb3..2ecfa7db15 100644 --- a/editor/editor_file_dialog.h +++ b/editor/editor_file_dialog.h @@ -44,9 +44,6 @@ class DependencyRemoveDialog; -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class EditorFileDialog : public ConfirmationDialog { GDCLASS(EditorFileDialog, ConfirmationDialog); diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp index be3df2815e..6d3377a85b 100644 --- a/editor/editor_file_system.cpp +++ b/editor/editor_file_system.cpp @@ -1930,8 +1930,7 @@ void EditorFileSystem::reimport_files(const Vector<String> &p_files) { Error err = da->make_dir(".import"); if (err) { memdelete(da); - ERR_EXPLAIN("Failed to create 'res://.import' folder."); - ERR_FAIL(); + ERR_FAIL_MSG("Failed to create 'res://.import' folder."); } } memdelete(da); diff --git a/editor/editor_fonts.cpp b/editor/editor_fonts.cpp index 73438ffc0c..55cae35a4a 100644 --- a/editor/editor_fonts.cpp +++ b/editor/editor_fonts.cpp @@ -94,7 +94,31 @@ void editor_register_fonts(Ref<Theme> p_theme) { /* Custom font */ bool font_antialiased = (bool)EditorSettings::get_singleton()->get("interface/editor/font_antialiased"); - DynamicFontData::Hinting font_hinting = (DynamicFontData::Hinting)(int)EditorSettings::get_singleton()->get("interface/editor/font_hinting"); + int font_hinting_setting = (int)EditorSettings::get_singleton()->get("interface/editor/font_hinting"); + + DynamicFontData::Hinting font_hinting; + switch (font_hinting_setting) { + case 0: + // The "Auto" setting uses the setting that best matches the OS' font rendering: + // - macOS doesn't use font hinting. + // - Windows uses ClearType, which is in between "Light" and "Normal" hinting. + // - Linux has configurable font hinting, but most distributions including Ubuntu default to "Light". +#ifdef OSX_ENABLED + font_hinting = DynamicFontData::HINTING_NONE; +#else + font_hinting = DynamicFontData::HINTING_LIGHT; +#endif + break; + case 1: + font_hinting = DynamicFontData::HINTING_NONE; + break; + case 2: + font_hinting = DynamicFontData::HINTING_LIGHT; + break; + default: + font_hinting = DynamicFontData::HINTING_NORMAL; + break; + } String custom_font_path = EditorSettings::get_singleton()->get("interface/editor/main_font"); Ref<DynamicFontData> CustomFont; diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp index 7aa24c7476..385b6924df 100644 --- a/editor/editor_help.cpp +++ b/editor/editor_help.cpp @@ -1738,19 +1738,13 @@ void FindBar::_update_results_count() { void FindBar::_update_matches_label() { - if (results_count > 0) { - matches_label->show(); - - matches_label->add_color_override("font_color", Color(1, 1, 1)); - matches_label->set_text(vformat(TTR("Found %d match(es)."), results_count)); - } else if (search_text->get_text().empty()) { - + if (search_text->get_text().empty() || results_count == -1) { matches_label->hide(); } else { matches_label->show(); - matches_label->add_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); - matches_label->set_text(TTR("No Matches")); + matches_label->add_color_override("font_color", results_count > 0 ? Color(1, 1, 1) : EditorNode::get_singleton()->get_gui_base()->get_color("error_color", "Editor")); + matches_label->set_text(vformat(results_count == 1 ? TTR("%d match.") : TTR("%d matches."), results_count)); } } diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index ae2a6d2802..5ec071d71a 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -1926,10 +1926,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) { switch (p_option) { case FILE_NEW_SCENE: { - int idx = editor_data.add_edited_scene(-1); - _scene_tab_changed(idx); - editor_data.clear_editor_states(); - _update_scene_tabs(); + new_scene(); } break; case FILE_NEW_INHERITED_SCENE: @@ -2798,8 +2795,7 @@ void EditorNode::select_editor_by_name(const String &p_name) { } } - ERR_EXPLAIN("The editor name '" + p_name + "' was not found."); - ERR_FAIL(); + ERR_FAIL_MSG("The editor name '" + p_name + "' was not found."); } void EditorNode::add_editor_plugin(EditorPlugin *p_editor, bool p_config_changed) { @@ -2925,31 +2921,35 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled, return; } - String path = cf->get_value("plugin", "script"); - path = String("res://addons").plus_file(p_addon).plus_file(path); + String script_path = cf->get_value("plugin", "script"); + Ref<Script> script; // We need to save it for creating "ep" below. - Ref<Script> script = ResourceLoader::load(path); + // Only try to load the script if it has a name. Else, the plugin has no init script. + if (script_path.length() > 0) { + script_path = String("res://addons").plus_file(p_addon).plus_file(script_path); + script = ResourceLoader::load(script_path); - if (script.is_null()) { - show_warning(vformat(TTR("Unable to load addon script from path: '%s'."), path)); - return; - } + if (script.is_null()) { + show_warning(vformat(TTR("Unable to load addon script from path: '%s'."), script_path)); + return; + } - //errors in the script cause the base_type to be "" - if (String(script->get_instance_base_type()) == "") { - show_warning(vformat(TTR("Unable to load addon script from path: '%s' There seems to be an error in the code, please check the syntax."), path)); - return; - } + // Errors in the script cause the base_type to be an empty string. + if (String(script->get_instance_base_type()) == "") { + show_warning(vformat(TTR("Unable to load addon script from path: '%s' There seems to be an error in the code, please check the syntax."), script_path)); + return; + } - //could check inheritance.. - if (String(script->get_instance_base_type()) != "EditorPlugin") { - show_warning(vformat(TTR("Unable to load addon script from path: '%s' Base type is not EditorPlugin."), path)); - return; - } + // Plugin init scripts must inherit from EditorPlugin and be tools. + if (String(script->get_instance_base_type()) != "EditorPlugin") { + show_warning(vformat(TTR("Unable to load addon script from path: '%s' Base type is not EditorPlugin."), script_path)); + return; + } - if (!script->is_tool()) { - show_warning(vformat(TTR("Unable to load addon script from path: '%s' Script is not in tool mode."), path)); - return; + if (!script->is_tool()) { + show_warning(vformat(TTR("Unable to load addon script from path: '%s' Script is not in tool mode."), script_path)); + return; + } } EditorPlugin *ep = memnew(EditorPlugin); @@ -3162,6 +3162,14 @@ void EditorNode::fix_dependencies(const String &p_for_file) { dependency_fixer->edit(p_for_file); } +int EditorNode::new_scene() { + int idx = editor_data.add_edited_scene(-1); + _scene_tab_changed(idx); + editor_data.clear_editor_states(); + _update_scene_tabs(); + return idx; +} + Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, bool p_set_inherited, bool p_clear_errors, bool p_force_open_imported) { if (!is_inside_tree()) { @@ -4366,6 +4374,15 @@ bool EditorNode::ensure_main_scene(bool p_from_native) { return true; } +void EditorNode::run_play() { + _menu_option_confirm(RUN_STOP, true); + _run(false); +} + +void EditorNode::run_stop() { + _menu_option_confirm(RUN_STOP, false); +} + int EditorNode::get_current_tab() { return scene_tabs->get_current_tab(); } @@ -4783,8 +4800,7 @@ void EditorNode::remove_control_from_dock(Control *p_control) { } } - ERR_EXPLAIN("Control was not in dock"); - ERR_FAIL_COND(!dock); + ERR_FAIL_COND_MSG(!dock, "Control was not in dock."); dock->remove_child(p_control); _update_dock_slots_visibility(); @@ -5496,6 +5512,9 @@ EditorNode::EditorNode() { } } + // Define a minimum window size to prevent UI elements from overlapping or being cut off + OS::get_singleton()->set_min_window_size(Size2(1024, 600) * EDSCALE); + ResourceLoader::set_abort_on_missing_resources(false); FileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files")); EditorFileDialog::set_default_show_hidden_files(EditorSettings::get_singleton()->get("filesystem/file_dialog/show_hidden_files")); @@ -5934,19 +5953,19 @@ EditorNode::EditorNode() { p->add_shortcut(ED_SHORTCUT("editor/new_scene", TTR("New Scene")), FILE_NEW_SCENE); p->add_shortcut(ED_SHORTCUT("editor/new_inherited_scene", TTR("New Inherited Scene...")), FILE_NEW_INHERITED_SCENE); p->add_shortcut(ED_SHORTCUT("editor/open_scene", TTR("Open Scene..."), KEY_MASK_CMD + KEY_O), FILE_OPEN_SCENE); + p->add_shortcut(ED_SHORTCUT("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_T), FILE_OPEN_PREV); + p->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT); + p->add_separator(); p->add_shortcut(ED_SHORTCUT("editor/save_scene", TTR("Save Scene"), KEY_MASK_CMD + KEY_S), FILE_SAVE_SCENE); p->add_shortcut(ED_SHORTCUT("editor/save_scene_as", TTR("Save Scene As..."), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_S), FILE_SAVE_AS_SCENE); p->add_shortcut(ED_SHORTCUT("editor/save_all_scenes", TTR("Save All Scenes"), KEY_MASK_ALT + KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_S), FILE_SAVE_ALL_SCENES); - p->add_separator(); - p->add_shortcut(ED_SHORTCUT("editor/close_scene", TTR("Close Scene"), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_W), FILE_CLOSE); - p->add_separator(); - p->add_submenu_item(TTR("Open Recent"), "RecentScenes", FILE_OPEN_RECENT); - p->add_shortcut(ED_SHORTCUT("editor/reopen_closed_scene", TTR("Reopen Closed Scene"), KEY_MASK_CMD + KEY_MASK_SHIFT + KEY_T), FILE_OPEN_PREV); + p->add_separator(); p->add_shortcut(ED_SHORTCUT("editor/quick_open", TTR("Quick Open..."), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_O), FILE_QUICK_OPEN); p->add_shortcut(ED_SHORTCUT("editor/quick_open_scene", TTR("Quick Open Scene..."), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_O), FILE_QUICK_OPEN_SCENE); p->add_shortcut(ED_SHORTCUT("editor/quick_open_script", TTR("Quick Open Script..."), KEY_MASK_ALT + KEY_MASK_CMD + KEY_O), FILE_QUICK_OPEN_SCRIPT); + p->add_separator(); PopupMenu *pm_export = memnew(PopupMenu); pm_export->set_name("Export"); @@ -5959,8 +5978,10 @@ EditorNode::EditorNode() { p->add_separator(); p->add_shortcut(ED_SHORTCUT("editor/undo", TTR("Undo"), KEY_MASK_CMD + KEY_Z), EDIT_UNDO, true); p->add_shortcut(ED_SHORTCUT("editor/redo", TTR("Redo"), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_Z), EDIT_REDO, true); + p->add_separator(); p->add_shortcut(ED_SHORTCUT("editor/revert_scene", TTR("Revert Scene")), EDIT_REVERT); + p->add_shortcut(ED_SHORTCUT("editor/close_scene", TTR("Close Scene"), KEY_MASK_SHIFT + KEY_MASK_CMD + KEY_W), FILE_CLOSE); recent_scenes = memnew(PopupMenu); recent_scenes->set_name("RecentScenes"); @@ -5980,27 +6001,27 @@ EditorNode::EditorNode() { p = project_menu->get_popup(); p->set_hide_on_window_lose_focus(true); - p->add_shortcut(ED_SHORTCUT("editor/project_settings", TTR("Project Settings")), RUN_SETTINGS); - p->add_separator(); + p->add_shortcut(ED_SHORTCUT("editor/project_settings", TTR("Project Settings...")), RUN_SETTINGS); p->connect("id_pressed", this, "_menu_option"); - p->add_shortcut(ED_SHORTCUT("editor/export", TTR("Export")), FILE_EXPORT_PROJECT); + + p->add_separator(); + p->add_shortcut(ED_SHORTCUT("editor/export", TTR("Export...")), FILE_EXPORT_PROJECT); + p->add_item(TTR("Install Android Build Template..."), FILE_INSTALL_ANDROID_SOURCE); + p->add_item(TTR("Open Project Data Folder"), RUN_PROJECT_DATA_FOLDER); plugin_config_dialog = memnew(PluginConfigDialog); plugin_config_dialog->connect("plugin_ready", this, "_on_plugin_ready"); gui_base->add_child(plugin_config_dialog); + p->add_separator(); tool_menu = memnew(PopupMenu); tool_menu->set_name("Tools"); tool_menu->connect("index_pressed", this, "_tool_menu_option"); - p->add_separator(); p->add_child(tool_menu); p->add_submenu_item(TTR("Tools"), "Tools"); - tool_menu->add_item(TTR("Orphan Resource Explorer"), TOOLS_ORPHAN_RESOURCES); - tool_menu->add_item(TTR("Open Project Data Folder"), RUN_PROJECT_DATA_FOLDER); - p->add_separator(); - p->add_item(TTR("Install Android Build Template"), FILE_INSTALL_ANDROID_SOURCE); - p->add_separator(); + tool_menu->add_item(TTR("Orphan Resource Explorer..."), TOOLS_ORPHAN_RESOURCES); + p->add_separator(); #ifdef OSX_ENABLED p->add_shortcut(ED_SHORTCUT("editor/quit_to_project_list", TTR("Quit to Project List"), KEY_MASK_SHIFT + KEY_MASK_ALT + KEY_Q), RUN_PROJECT_MANAGER, true); #else @@ -6052,7 +6073,7 @@ EditorNode::EditorNode() { p = settings_menu->get_popup(); p->set_hide_on_window_lose_focus(true); - p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings")), SETTINGS_PREFERENCES); + p->add_shortcut(ED_SHORTCUT("editor/editor_settings", TTR("Editor Settings...")), SETTINGS_PREFERENCES); p->add_separator(); editor_layouts = memnew(PopupMenu); @@ -6087,11 +6108,8 @@ EditorNode::EditorNode() { } p->add_separator(); - p->add_item(TTR("Manage Editor Features"), SETTINGS_MANAGE_FEATURE_PROFILES); - - p->add_separator(); - - p->add_item(TTR("Manage Export Templates"), SETTINGS_MANAGE_EXPORT_TEMPLATES); + p->add_item(TTR("Manage Editor Features..."), SETTINGS_MANAGE_FEATURE_PROFILES); + p->add_item(TTR("Manage Export Templates..."), SETTINGS_MANAGE_EXPORT_TEMPLATES); // Help Menu help_menu = memnew(MenuButton); diff --git a/editor/editor_node.h b/editor/editor_node.h index 8d536a1b86..a8443549ed 100644 --- a/editor/editor_node.h +++ b/editor/editor_node.h @@ -86,10 +86,6 @@ #include "scene/gui/tree.h" #include "scene/gui/viewport_container.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - typedef void (*EditorNodeInitCallback)(); typedef void (*EditorPluginInitializeCallback)(); typedef bool (*EditorBuildCallback)(); @@ -749,6 +745,7 @@ public: void fix_dependencies(const String &p_for_file); void clear_scene() { _cleanup_scene(); } + int new_scene(); Error load_scene(const String &p_scene, bool p_ignore_broken_deps = false, bool p_set_inherited = false, bool p_clear_errors = true, bool p_force_open_imported = false); Error load_resource(const String &p_resource, bool p_ignore_broken_deps = false); @@ -869,6 +866,9 @@ public: static void add_build_callback(EditorBuildCallback p_callback); bool ensure_main_scene(bool p_from_native); + + void run_play(); + void run_stop(); }; struct EditorProgress { diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h index 52ab444522..7b6f55e93d 100644 --- a/editor/editor_plugin.h +++ b/editor/editor_plugin.h @@ -41,10 +41,6 @@ #include "scene/main/node.h" #include "scene/resources/texture.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class EditorNode; class Spatial; class Camera; diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp index 3300228921..20ba07c102 100644 --- a/editor/editor_properties.cpp +++ b/editor/editor_properties.cpp @@ -116,7 +116,7 @@ void EditorPropertyMultilineText::_open_big_text() { add_child(big_text_dialog); } - big_text_dialog->popup_centered_ratio(); + big_text_dialog->popup_centered_clamped(Size2(1000, 900) * EDSCALE, 0.8); big_text->set_text(text->get_text()); big_text->grab_focus(); } diff --git a/editor/editor_resource_preview.cpp b/editor/editor_resource_preview.cpp index 327e61cea3..4a7a9fb863 100644 --- a/editor/editor_resource_preview.cpp +++ b/editor/editor_resource_preview.cpp @@ -46,8 +46,7 @@ bool EditorResourcePreviewGenerator::handles(const String &p_type) const { if (get_script_instance() && get_script_instance()->has_method("handles")) { return get_script_instance()->call("handles", p_type); } - ERR_EXPLAIN("EditorResourcePreviewGenerator::handles needs to be overridden"); - ERR_FAIL_V(false); + ERR_FAIL_V_MSG(false, "EditorResourcePreviewGenerator::handles needs to be overridden."); } Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from, const Size2 &p_size) const { @@ -55,8 +54,7 @@ Ref<Texture> EditorResourcePreviewGenerator::generate(const RES &p_from, const S if (get_script_instance() && get_script_instance()->has_method("generate")) { return get_script_instance()->call("generate", p_from, p_size); } - ERR_EXPLAIN("EditorResourcePreviewGenerator::generate needs to be overridden"); - ERR_FAIL_V(Ref<Texture>()); + ERR_FAIL_V_MSG(Ref<Texture>(), "EditorResourcePreviewGenerator::generate needs to be overridden."); } Ref<Texture> EditorResourcePreviewGenerator::generate_from_path(const String &p_path, const Size2 &p_size) const { diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index e3f2a888d6..cb3bfa3a49 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -324,8 +324,8 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("interface/editor/code_font_size", 14); hints["interface/editor/code_font_size"] = PropertyInfo(Variant::INT, "interface/editor/code_font_size", PROPERTY_HINT_RANGE, "8,48,1", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/font_antialiased", true); - _initial_set("interface/editor/font_hinting", 2); - hints["interface/editor/font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/font_hinting", PROPERTY_HINT_ENUM, "None,Light,Normal", PROPERTY_USAGE_DEFAULT); + _initial_set("interface/editor/font_hinting", 0); + hints["interface/editor/font_hinting"] = PropertyInfo(Variant::INT, "interface/editor/font_hinting", PROPERTY_HINT_ENUM, "Auto,None,Light,Normal", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/main_font", ""); hints["interface/editor/main_font"] = PropertyInfo(Variant::STRING, "interface/editor/main_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/main_font_bold", ""); @@ -334,9 +334,9 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { hints["interface/editor/code_font"] = PropertyInfo(Variant::STRING, "interface/editor/code_font", PROPERTY_HINT_GLOBAL_FILE, "*.ttf,*.otf", PROPERTY_USAGE_DEFAULT); _initial_set("interface/editor/dim_editor_on_dialog_popup", true); _initial_set("interface/editor/low_processor_mode_sleep_usec", 6900); // ~144 FPS - hints["interface/editor/low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT); + hints["interface/editor/low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/unfocused_low_processor_mode_sleep_usec", 50000); // 20 FPS - hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT); + hints["interface/editor/unfocused_low_processor_mode_sleep_usec"] = PropertyInfo(Variant::REAL, "interface/editor/unfocused_low_processor_mode_sleep_usec", PROPERTY_HINT_RANGE, "1,100000,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); _initial_set("interface/editor/separate_distraction_mode", false); _initial_set("interface/editor/automatically_open_screenshots", true); _initial_set("interface/editor/hide_console_window", false); @@ -1451,10 +1451,7 @@ void EditorSettings::add_shortcut(const String &p_name, Ref<ShortCut> &p_shortcu bool EditorSettings::is_shortcut(const String &p_name, const Ref<InputEvent> &p_event) const { const Map<String, Ref<ShortCut> >::Element *E = shortcuts.find(p_name); - if (!E) { - ERR_EXPLAIN("Unknown Shortcut: " + p_name); - ERR_FAIL_V(false); - } + ERR_FAIL_COND_V_MSG(!E, false, "Unknown Shortcut: " + p_name + "."); return E->get()->is_shortcut(p_event); } @@ -1483,10 +1480,8 @@ Ref<ShortCut> ED_GET_SHORTCUT(const String &p_path) { } Ref<ShortCut> sc = EditorSettings::get_singleton()->get_shortcut(p_path); - if (!sc.is_valid()) { - ERR_EXPLAIN("Used ED_GET_SHORTCUT with invalid shortcut: " + p_path); - ERR_FAIL_COND_V(!sc.is_valid(), sc); - } + + ERR_FAIL_COND_V_MSG(!sc.is_valid(), sc, "Used ED_GET_SHORTCUT with invalid shortcut: " + p_path + "."); return sc; } diff --git a/editor/editor_spin_slider.cpp b/editor/editor_spin_slider.cpp index 9966394025..46a30b7554 100644 --- a/editor/editor_spin_slider.cpp +++ b/editor/editor_spin_slider.cpp @@ -47,42 +47,48 @@ void EditorSpinSlider::_gui_input(const Ref<InputEvent> &p_event) { return; Ref<InputEventMouseButton> mb = p_event; - if (mb.is_valid() && mb->get_button_index() == BUTTON_LEFT) { + if (mb.is_valid()) { - if (mb->is_pressed()) { + if (mb->get_button_index() == BUTTON_LEFT) { + if (mb->is_pressed()) { - if (updown_offset != -1 && mb->get_position().x > updown_offset) { - //there is an updown, so use it. - if (mb->get_position().y < get_size().height / 2) { - set_value(get_value() + get_step()); + if (updown_offset != -1 && mb->get_position().x > updown_offset) { + //there is an updown, so use it. + if (mb->get_position().y < get_size().height / 2) { + set_value(get_value() + get_step()); + } else { + set_value(get_value() - get_step()); + } + return; } else { - set_value(get_value() - get_step()); + + grabbing_spinner_attempt = true; + grabbing_spinner_dist_cache = 0; + pre_grab_value = get_value(); + grabbing_spinner = false; + grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position(); } - return; } else { - grabbing_spinner_attempt = true; - grabbing_spinner_dist_cache = 0; - pre_grab_value = get_value(); - grabbing_spinner = false; - grabbing_spinner_mouse_pos = Input::get_singleton()->get_mouse_position(); - } - } else { + if (grabbing_spinner_attempt) { - if (grabbing_spinner_attempt) { + if (grabbing_spinner) { - if (grabbing_spinner) { + Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); + Input::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos); + update(); + } else { + _focus_entered(); + } - Input::get_singleton()->set_mouse_mode(Input::MOUSE_MODE_VISIBLE); - Input::get_singleton()->warp_mouse_position(grabbing_spinner_mouse_pos); - update(); - } else { - _focus_entered(); + grabbing_spinner = false; + grabbing_spinner_attempt = false; } - - grabbing_spinner = false; - grabbing_spinner_attempt = false; } + } else if (mb->get_button_index() == BUTTON_WHEEL_UP || mb->get_button_index() == BUTTON_WHEEL_DOWN) { + + if (grabber->is_visible()) + call_deferred("update"); } } @@ -347,6 +353,11 @@ void EditorSpinSlider::_value_input_closed() { //focus_exited signal void EditorSpinSlider::_value_focus_exited() { + + // discontinue because the focus_exit was caused by right-click context menu + if (value_input->get_menu()->is_visible()) + return; + _evaluate_input_text(); // focus is not on the same element after the vlalue_input was exited // -> focus is on next element diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 97af0d08ea..d962001b38 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -351,6 +351,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_color("dark_color_3", "Editor", dark_color_3); theme->set_color("contrast_color_1", "Editor", contrast_color_1); theme->set_color("contrast_color_2", "Editor", contrast_color_2); + theme->set_color("box_selection_fill_color", "Editor", accent_color * Color(1, 1, 1, 0.3)); + theme->set_color("box_selection_stroke_color", "Editor", accent_color * Color(1, 1, 1, 0.8)); theme->set_color("font_color", "Editor", font_color); theme->set_color("highlighted_font_color", "Editor", font_color_hl); @@ -1064,6 +1066,9 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { // FileDialog theme->set_icon("folder", "FileDialog", theme->get_icon("Folder", "EditorIcons")); + // Use a different color for folder icons to make them easier to distinguish from files. + // On a light theme, the icon will be dark, so we need to lighten it before blending it with the accent color. + theme->set_color("folder", "FileDialog", (dark_theme ? Color(1, 1, 1) : Color(5, 5, 5)).linear_interpolate(accent_color, 0.7)); theme->set_color("files_disabled", "FileDialog", font_color_disabled); // color picker diff --git a/editor/export_template_manager.cpp b/editor/export_template_manager.cpp index ecfad4d146..68e859966c 100644 --- a/editor/export_template_manager.cpp +++ b/editor/export_template_manager.cpp @@ -69,6 +69,9 @@ void ExportTemplateManager::_update_template_list() { memdelete(d); String current_version = VERSION_FULL_CONFIG; + // Downloadable export templates are only available for stable, alpha, beta and RC versions. + // Therefore, don't display download-related features when using a development version + const bool downloads_available = String(VERSION_STATUS) != String("dev"); Label *current = memnew(Label); current->set_h_size_flags(SIZE_EXPAND_FILL); @@ -76,10 +79,14 @@ void ExportTemplateManager::_update_template_list() { if (templates.has(current_version)) { current->add_color_override("font_color", get_color("success_color", "Editor")); - Button *redownload = memnew(Button); - redownload->set_text(TTR("Re-Download")); - current_hb->add_child(redownload); - redownload->connect("pressed", this, "_download_template", varray(current_version)); + + // Only display a redownload button if it can be downloaded in the first place + if (downloads_available) { + Button *redownload = memnew(Button); + redownload->set_text(TTR("Redownload")); + current_hb->add_child(redownload); + redownload->connect("pressed", this, "_download_template", varray(current_version)); + } Button *uninstall = memnew(Button); uninstall->set_text(TTR("Uninstall")); @@ -91,6 +98,12 @@ void ExportTemplateManager::_update_template_list() { current->add_color_override("font_color", get_color("error_color", "Editor")); Button *redownload = memnew(Button); redownload->set_text(TTR("Download")); + + if (!downloads_available) { + redownload->set_disabled(true); + redownload->set_tooltip(TTR("Official export templates aren't available for development builds.")); + } + redownload->connect("pressed", this, "_download_template", varray(current_version)); current_hb->add_child(redownload); current->set_text(current_version + " " + TTR("(Missing)")); @@ -308,8 +321,7 @@ bool ExportTemplateManager::_install_from_file(const String &p_file, bool p_use_ if (!f) { ret = unzGoToNextFile(pkg); fc++; - ERR_EXPLAIN("Can't open file from path: " + String(to_write)); - ERR_CONTINUE(true); + ERR_CONTINUE_MSG(true, "Can't open file from path: " + String(to_write) + "."); } f->store_buffer(data.ptr(), data.size()); @@ -422,14 +434,16 @@ void ExportTemplateManager::_http_download_templates_completed(int p_status, int String path = download_templates->get_download_file(); template_list_state->set_text(TTR("Download Complete.")); template_downloader->hide(); - int ret = _install_from_file(path, false); + bool ret = _install_from_file(path, false); if (ret) { - Error err = OS::get_singleton()->move_to_trash(path); + // Clean up downloaded file. + DirAccessRef da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); + Error err = da->remove(path); if (err != OK) { - EditorNode::get_singleton()->add_io_error(TTR("Cannot remove:") + "\n" + path + "\n"); + EditorNode::get_singleton()->add_io_error(TTR("Cannot remove temporary file:") + "\n" + path + "\n"); } } else { - WARN_PRINTS(vformat(TTR("Templates installation failed. The problematic templates archives can be found at '%s'."), path)); + EditorNode::get_singleton()->add_io_error(vformat(TTR("Templates installation failed.\nThe problematic templates archives can be found at '%s'."), path)); } } } break; @@ -458,7 +472,7 @@ void ExportTemplateManager::_begin_template_download(const String &p_url) { Error err = download_templates->request(p_url); if (err != OK) { - EditorNode::get_singleton()->show_warning(TTR("Error requesting url: ") + p_url); + EditorNode::get_singleton()->show_warning(TTR("Error requesting URL:") + " " + p_url); return; } @@ -576,8 +590,7 @@ Error ExportTemplateManager::install_android_template() { zlib_filefunc_def io = zipio_create_io_from_file(&src_f); unzFile pkg = unzOpen2(source_zip.utf8().get_data(), &io); - ERR_EXPLAIN("Android sources not in zip format"); - ERR_FAIL_COND_V(!pkg, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!pkg, ERR_CANT_OPEN, "Android sources not in zip format."); int ret = unzGoToFirstFile(pkg); diff --git a/editor/file_type_cache.cpp b/editor/file_type_cache.cpp index 1bcbc45d3b..746d38f2b5 100644 --- a/editor/file_type_cache.cpp +++ b/editor/file_type_cache.cpp @@ -83,11 +83,8 @@ void FileTypeCache::save() { GLOBAL_LOCK_FUNCTION String project = ProjectSettings::get_singleton()->get_resource_path(); FileAccess *f = FileAccess::open(project + "/file_type_cache.cch", FileAccess::WRITE); - if (!f) { - ERR_EXPLAIN(TTR("Can't open file_type_cache.cch for writing, not saving file type cache!")); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(!f, "Can't open file_type_cache.cch for writing, not saving file type cache!"); const String *K = NULL; diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp index 8e332ad20e..83904800e9 100644 --- a/editor/filesystem_dock.cpp +++ b/editor/filesystem_dock.cpp @@ -39,6 +39,7 @@ #include "editor_node.h" #include "editor_settings.h" #include "scene/main/viewport.h" +#include "scene/resources/packed_scene.h" Ref<Texture> FileSystemDock::_get_tree_item_icon(EditorFileSystemDirectory *p_dir, int p_idx) { Ref<Texture> file_icon; @@ -63,6 +64,7 @@ bool FileSystemDock::_create_tree(TreeItem *p_parent, EditorFileSystemDirectory subdirectory_item->set_text(0, dname); subdirectory_item->set_icon(0, get_icon("Folder", "EditorIcons")); + subdirectory_item->set_icon_color(0, get_color("folder", "FileDialog")); subdirectory_item->set_selectable(0, true); String lpath = p_dir->get_path(); subdirectory_item->set_metadata(0, lpath); @@ -185,15 +187,19 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo continue; Ref<Texture> folder_icon = get_icon("Folder", "EditorIcons"); + const Color folder_color = get_color("folder", "FileDialog"); String text; Ref<Texture> icon; + Color color; if (fave == "res://") { text = "/"; icon = folder_icon; + color = folder_color; } else if (fave.ends_with("/")) { text = fave.substr(0, fave.length() - 1).get_file(); icon = folder_icon; + color = folder_color; } else { text = fave.get_file(); int index; @@ -203,12 +209,14 @@ void FileSystemDock::_update_tree(const Vector<String> &p_uncollapsed_paths, boo } else { icon = get_icon("File", "EditorIcons"); } + color = Color(1, 1, 1); } if (searched_string.length() == 0 || text.to_lower().find(searched_string) >= 0) { TreeItem *ti = tree->create_item(favorites); ti->set_text(0, text); ti->set_icon(0, icon); + ti->set_icon_color(0, color); ti->set_tooltip(0, fave); ti->set_selectable(0, true); ti->set_metadata(0, fave); @@ -452,8 +460,7 @@ void FileSystemDock::_navigate_to_path(const String &p_path, bool p_select_in_fa path = target_path + "/"; } else { memdelete(dirAccess); - ERR_EXPLAIN(vformat(TTR("Cannot navigate to '%s' as it has not been found in the file system!"), p_path)); - ERR_FAIL(); + ERR_FAIL_MSG(vformat("Cannot navigate to '%s' as it has not been found in the file system!", p_path)); } memdelete(dirAccess); } @@ -639,6 +646,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { } Ref<Texture> folder_icon = (use_thumbnails) ? folder_thumbnail : get_icon("folder", "FileDialog"); + const Color folder_color = get_color("folder", "FileDialog"); // Build the FileInfo list List<FileInfo> filelist; @@ -716,6 +724,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { files->set_item_metadata(files->get_item_count() - 1, bd); files->set_item_selectable(files->get_item_count() - 1, false); + files->set_item_icon_modulate(files->get_item_count() - 1, folder_color); } for (int i = 0; i < efd->get_subdir_count(); i++) { @@ -724,6 +733,7 @@ void FileSystemDock::_update_file_list(bool p_keep_selection) { files->add_item(dname, folder_icon, true); files->set_item_metadata(files->get_item_count() - 1, directory.plus_file(dname) + "/"); + files->set_item_icon_modulate(files->get_item_count() - 1, folder_color); if (cselection.has(dname)) { files->select(files->get_item_count() - 1, false); @@ -1250,6 +1260,48 @@ void FileSystemDock::_make_dir_confirm() { } } +void FileSystemDock::_make_scene_confirm() { + String scene_name = make_scene_dialog_text->get_text().strip_edges(); + + if (scene_name.length() == 0) { + EditorNode::get_singleton()->show_warning(TTR("No name provided.")); + return; + } + + String directory = path; + if (!directory.ends_with("/")) { + directory = directory.get_base_dir(); + } + + String extension = scene_name.get_extension(); + List<String> extensions; + Ref<PackedScene> sd = memnew(PackedScene); + ResourceSaver::get_recognized_extensions(sd, &extensions); + + bool extension_correct = false; + for (List<String>::Element *E = extensions.front(); E; E = E->next()) { + if (E->get() == extension) { + extension_correct = true; + break; + } + } + if (!extension_correct) + scene_name = scene_name.get_basename() + ".tscn"; + + scene_name = directory.plus_file(scene_name); + + DirAccess *da = DirAccess::create(DirAccess::ACCESS_RESOURCES); + if (da->file_exists(scene_name)) { + EditorNode::get_singleton()->show_warning(TTR("A file or folder with this name already exists.")); + memdelete(da); + return; + } + memdelete(da); + + int idx = editor->new_scene(); + editor->get_editor_data().set_scene_path(idx, scene_name); +} + void FileSystemDock::_file_deleted(String p_file) { emit_signal("file_deleted", p_file); } @@ -1698,6 +1750,13 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected make_dir_dialog_text->grab_focus(); } break; + case FILE_NEW_SCENE: { + make_scene_dialog_text->set_text("new scene"); + make_scene_dialog_text->select_all(); + make_scene_dialog->popup_centered_minsize(Size2(250, 80) * EDSCALE); + make_scene_dialog_text->grab_focus(); + } break; + case FILE_NEW_SCRIPT: { // Create a new script String fpath = path; @@ -2157,6 +2216,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str p_popup->add_separator(); if (p_display_path_dependent_options) { p_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); + p_popup->add_item(TTR("New Scene..."), FILE_NEW_SCENE); p_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); p_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); } @@ -2195,6 +2255,7 @@ void FileSystemDock::_tree_rmb_empty(const Vector2 &p_pos) { tree_popup->clear(); tree_popup->set_size(Size2(1, 1)); tree_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); + tree_popup->add_item(TTR("New Scene..."), FILE_NEW_SCENE); tree_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); tree_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); tree_popup->set_position(tree->get_global_position() + p_pos); @@ -2237,6 +2298,7 @@ void FileSystemDock::_file_list_rmb_pressed(const Vector2 &p_pos) { file_list_popup->set_size(Size2(1, 1)); file_list_popup->add_item(TTR("New Folder..."), FILE_NEW_FOLDER); + file_list_popup->add_item(TTR("New Scene..."), FILE_NEW_SCENE); file_list_popup->add_item(TTR("New Script..."), FILE_NEW_SCRIPT); file_list_popup->add_item(TTR("New Resource..."), FILE_NEW_RESOURCE); file_list_popup->add_item(TTR("Show in File Manager"), FILE_SHOW_IN_EXPLORER); @@ -2411,6 +2473,7 @@ void FileSystemDock::_bind_methods() { ClassDB::bind_method(D_METHOD("_fs_changed"), &FileSystemDock::_fs_changed); ClassDB::bind_method(D_METHOD("_tree_multi_selected"), &FileSystemDock::_tree_multi_selected); ClassDB::bind_method(D_METHOD("_make_dir_confirm"), &FileSystemDock::_make_dir_confirm); + ClassDB::bind_method(D_METHOD("_make_scene_confirm"), &FileSystemDock::_make_scene_confirm); ClassDB::bind_method(D_METHOD("_resource_created"), &FileSystemDock::_resource_created); ClassDB::bind_method(D_METHOD("_move_operation_confirm", "to_path", "overwrite"), &FileSystemDock::_move_operation_confirm, DEFVAL(false)); ClassDB::bind_method(D_METHOD("_move_with_overwrite"), &FileSystemDock::_move_with_overwrite); @@ -2626,6 +2689,17 @@ FileSystemDock::FileSystemDock(EditorNode *p_editor) { make_dir_dialog->register_text_enter(make_dir_dialog_text); make_dir_dialog->connect("confirmed", this, "_make_dir_confirm"); + make_scene_dialog = memnew(ConfirmationDialog); + make_scene_dialog->set_title(TTR("Create Scene")); + VBoxContainer *make_scene_dialog_vb = memnew(VBoxContainer); + make_scene_dialog->add_child(make_scene_dialog_vb); + + make_scene_dialog_text = memnew(LineEdit); + make_scene_dialog_vb->add_margin_child(TTR("Name:"), make_scene_dialog_text); + add_child(make_scene_dialog); + make_scene_dialog->register_text_enter(make_scene_dialog_text); + make_scene_dialog->connect("confirmed", this, "_make_scene_confirm"); + make_script_dialog_text = memnew(ScriptCreateDialog); make_script_dialog_text->set_title(TTR("Create Script")); add_child(make_script_dialog_text); diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h index 6de370ad29..cc5ba94b48 100644 --- a/editor/filesystem_dock.h +++ b/editor/filesystem_dock.h @@ -87,6 +87,7 @@ private: FILE_INFO, FILE_NEW_FOLDER, FILE_NEW_SCRIPT, + FILE_NEW_SCENE, FILE_SHOW_IN_EXPLORER, FILE_COPY_PATH, FILE_NEW_RESOURCE, @@ -135,6 +136,8 @@ private: LineEdit *duplicate_dialog_text; ConfirmationDialog *make_dir_dialog; LineEdit *make_dir_dialog_text; + ConfirmationDialog *make_scene_dialog; + LineEdit *make_scene_dialog_text; ConfirmationDialog *overwrite_dialog; ScriptCreateDialog *make_script_dialog_text; CreateDialog *new_resource_dialog; @@ -213,6 +216,7 @@ private: void _resource_created() const; void _make_dir_confirm(); + void _make_scene_confirm(); void _rename_operation_confirm(); void _duplicate_operation_confirm(); void _move_with_overwrite(); diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp index 8665467f2d..cc2efb92ae 100644 --- a/editor/find_in_files.cpp +++ b/editor/find_in_files.cpp @@ -547,6 +547,7 @@ FindInFilesPanel::FindInFilesPanel() { _results_display->connect("item_edited", this, "_on_item_edited"); _results_display->set_hide_root(true); _results_display->set_select_mode(Tree::SELECT_ROW); + _results_display->set_allow_rmb_select(true); _results_display->create_item(); // Root vbc->add_child(_results_display); diff --git a/editor/icons/icon_editor_curve_handle.svg b/editor/icons/icon_editor_curve_handle.svg new file mode 100644 index 0000000000..c405ceab9d --- /dev/null +++ b/editor/icons/icon_editor_curve_handle.svg @@ -0,0 +1 @@ +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><circle cx="5" cy="5" fill="#fefefe" r="2.75" stroke="#000" stroke-linecap="square"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_editor_path_sharp_handle.svg b/editor/icons/icon_editor_path_sharp_handle.svg new file mode 100644 index 0000000000..db160dfeae --- /dev/null +++ b/editor/icons/icon_editor_path_sharp_handle.svg @@ -0,0 +1 @@ +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m-3.035534-10.106602h6.071068v6.071068h-6.071068z" fill="#fefefe" stroke="#000" stroke-linecap="square" transform="matrix(-.70710678 .70710678 -.70710678 -.70710678 0 0)"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_editor_path_smooth_handle.svg b/editor/icons/icon_editor_path_smooth_handle.svg new file mode 100644 index 0000000000..34f3d290bd --- /dev/null +++ b/editor/icons/icon_editor_path_smooth_handle.svg @@ -0,0 +1 @@ +<svg height="10" viewBox="0 0 10 10" width="10" xmlns="http://www.w3.org/2000/svg"><path d="m1.5-8.5h7v7h-7z" fill="#fefefe" stroke="#000" stroke-linecap="square" transform="rotate(90)"/></svg>
\ No newline at end of file diff --git a/editor/icons/icon_timeline_indicator.svg b/editor/icons/icon_timeline_indicator.svg new file mode 100644 index 0000000000..fd18192705 --- /dev/null +++ b/editor/icons/icon_timeline_indicator.svg @@ -0,0 +1 @@ +<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 0h10l-4 4h-2z" fill="#fefefe"/></svg>
\ No newline at end of file diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp index 1c4a8c43a9..449124acec 100644 --- a/editor/import/editor_import_collada.cpp +++ b/editor/import/editor_import_collada.cpp @@ -692,16 +692,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me pre_weights[w_i] = weights; - /* - for(Set<int>::Element *E=vertex_map[w_i].front();E;E=E->next()) { - - int dst = E->get(); - ERR_EXPLAIN("invalid vertex index in array"); - ERR_FAIL_INDEX_V(dst,vertex_array.size(),ERR_INVALID_DATA); - vertex_array[dst].weights=weights; - - }*/ - index_ofs += wstride * amount; } @@ -711,7 +701,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me Set<Collada::Vertex> vertex_set; //vertex set will be the vertices List<int> indices_list; //indices will be the indices - //Map<int,Set<int> > vertex_map; //map vertices (for setting skinning/morph) /**************************/ /* CREATE PRIMITIVE ARRAY */ @@ -834,9 +823,6 @@ Error ColladaImport::_create_mesh_surfaces(bool p_optimize, Ref<ArrayMesh> &p_me vertex_set.insert(vertex); } - /* if (!vertex_map.has(vertex_index)) - vertex_map[vertex_index]=Set<int>(); - vertex_map[vertex_index].insert(index); //should be outside..*/ //build triangles if needed if (j == 0) prev2[0] = index; @@ -1204,10 +1190,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres } } - if (ngsource != "") { - ERR_EXPLAIN("Controller Instance Source '" + ngsource + "' is neither skin or morph!"); - ERR_FAIL_V(ERR_INVALID_DATA); - } + ERR_FAIL_COND_V_MSG(ngsource != "", ERR_INVALID_DATA, "Controller instance source '" + ngsource + "' is neither skin or morph!"); } else { meshid = ng2->source; @@ -1608,7 +1591,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones } if (xform_idx == -1) { - WARN_PRINTS("Collada: Couldn't find matching node " + at.target + " xform for track " + at.param); + WARN_PRINTS("Collada: Couldn't find matching node " + at.target + " xform for track " + at.param + "."); continue; } @@ -1630,8 +1613,7 @@ void ColladaImport::create_animation(int p_clip, bool p_make_tracks_in_all_bones } else if (data.size() == xf.data.size()) { xf.data = data; } else { - ERR_EXPLAIN("Component " + at.component + " has datasize " + itos(data.size()) + ", xfdatasize " + itos(xf.data.size())); - ERR_CONTINUE(data.size() != xf.data.size()); + ERR_CONTINUE_MSG(data.size() != xf.data.size(), "Component " + at.component + " has datasize " + itos(data.size()) + ", xfdatasize " + itos(xf.data.size()) + "."); } } diff --git a/editor/import/editor_scene_importer_gltf.cpp b/editor/import/editor_scene_importer_gltf.cpp index c9c5b3818f..84dd1aa866 100644 --- a/editor/import/editor_scene_importer_gltf.cpp +++ b/editor/import/editor_scene_importer_gltf.cpp @@ -1544,8 +1544,7 @@ Error EditorSceneImporterGLTF::_parse_cameras(GLTFState &state) { camera.fov_size = 10; } } else { - ERR_EXPLAIN("Camera should be in 'orthographic' or 'perspective'"); - ERR_FAIL_V(ERR_PARSE_ERROR); + ERR_FAIL_V_MSG(ERR_PARSE_ERROR, "Camera should be in 'orthographic' or 'perspective'"); } state.cameras.push_back(camera); diff --git a/editor/import/resource_importer_csv_translation.cpp b/editor/import/resource_importer_csv_translation.cpp index cfcdbc8de4..301422a25a 100644 --- a/editor/import/resource_importer_csv_translation.cpp +++ b/editor/import/resource_importer_csv_translation.cpp @@ -101,8 +101,7 @@ Error ResourceImporterCSVTranslation::import(const String &p_source_file, const for (int i = 1; i < line.size(); i++) { String locale = line[i]; - ERR_EXPLAIN("Error importing CSV translation: '" + locale + "' is not a valid locale"); - ERR_FAIL_COND_V(!TranslationServer::is_locale_valid(locale), ERR_PARSE_ERROR); + ERR_FAIL_COND_V_MSG(!TranslationServer::is_locale_valid(locale), ERR_PARSE_ERROR, "Error importing CSV translation: '" + locale + "' is not a valid locale."); locales.push_back(locale); Ref<Translation> translation; diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp index 868f67fd77..9061c92f6e 100644 --- a/editor/import/resource_importer_obj.cpp +++ b/editor/import/resource_importer_obj.cpp @@ -45,8 +45,7 @@ uint32_t EditorOBJImporter::get_import_flags() const { static Error _parse_material_library(const String &p_path, Map<String, Ref<SpatialMaterial> > &material_map, List<String> *r_missing_deps) { FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_EXPLAIN(vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path)); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open MTL file '%s', it may not exist or not be readable.", p_path)); Ref<SpatialMaterial> current; String current_name; @@ -207,8 +206,7 @@ static Error _parse_material_library(const String &p_path, Map<String, Ref<Spati static Error _parse_obj(const String &p_path, List<Ref<Mesh> > &r_meshes, bool p_single_mesh, bool p_generate_tangents, bool p_optimize, Vector3 p_scale_mesh, List<String> *r_missing_deps) { FileAccessRef f = FileAccess::open(p_path, FileAccess::READ); - ERR_EXPLAIN(vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path)); Ref<ArrayMesh> mesh; mesh.instance(); diff --git a/editor/import/resource_importer_wav.cpp b/editor/import/resource_importer_wav.cpp index d267b29224..4fd4ab2f2e 100644 --- a/editor/import/resource_importer_wav.cpp +++ b/editor/import/resource_importer_wav.cpp @@ -123,8 +123,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s file->close(); memdelete(file); - ERR_EXPLAIN("Not a WAV file (no WAVE RIFF Header)"); - ERR_FAIL_V(ERR_FILE_UNRECOGNIZED); + ERR_FAIL_V_MSG(ERR_FILE_UNRECOGNIZED, "Not a WAV file (no WAVE RIFF header)."); } int format_bits = 0; @@ -166,16 +165,14 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s if (compression_code != 1 && compression_code != 3) { file->close(); memdelete(file); - ERR_EXPLAIN("Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead."); - ERR_FAIL_V(ERR_INVALID_DATA); + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Format not supported for WAVE file (not PCM). Save WAVE files as uncompressed PCM instead."); } format_channels = file->get_16(); if (format_channels != 1 && format_channels != 2) { file->close(); memdelete(file); - ERR_EXPLAIN("Format not supported for WAVE file (not stereo or mono)."); - ERR_FAIL_V(ERR_INVALID_DATA); + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Format not supported for WAVE file (not stereo or mono)."); } format_freq = file->get_32(); //sampling rate @@ -187,8 +184,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s if (format_bits % 8 || format_bits == 0) { file->close(); memdelete(file); - ERR_EXPLAIN("Invalid amount of bits in the sample (should be one of 8, 16, 24 or 32)."); - ERR_FAIL_V(ERR_INVALID_DATA); + ERR_FAIL_V_MSG(ERR_INVALID_DATA, "Invalid amount of bits in the sample (should be one of 8, 16, 24 or 32)."); } /* Don't need anything else, continue */ @@ -258,8 +254,7 @@ Error ResourceImporterWAV::import(const String &p_source_file, const String &p_s if (file->eof_reached()) { file->close(); memdelete(file); - ERR_EXPLAIN("Premature end of file."); - ERR_FAIL_V(ERR_FILE_CORRUPT); + ERR_FAIL_V_MSG(ERR_FILE_CORRUPT, "Premature end of file."); } } diff --git a/editor/node_dock.cpp b/editor/node_dock.cpp index 1c0151ed0a..d6df3bd369 100644 --- a/editor/node_dock.cpp +++ b/editor/node_dock.cpp @@ -56,10 +56,7 @@ void NodeDock::_bind_methods() { void NodeDock::_notification(int p_what) { - if (p_what == NOTIFICATION_ENTER_TREE) { - connections_button->set_icon(get_icon("Signals", "EditorIcons")); - groups_button->set_icon(get_icon("Groups", "EditorIcons")); - } else if (p_what == EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED) { + if (p_what == NOTIFICATION_ENTER_TREE || p_what == NOTIFICATION_THEME_CHANGED) { connections_button->set_icon(get_icon("Signals", "EditorIcons")); groups_button->set_icon(get_icon("Groups", "EditorIcons")); } @@ -131,7 +128,7 @@ NodeDock::NodeDock() { groups->hide(); select_a_node = memnew(Label); - select_a_node->set_text(TTR("Select a Node to edit Signals and Groups.")); + select_a_node->set_text(TTR("Select a single node to edit its signals and groups.")); select_a_node->set_v_size_flags(SIZE_EXPAND_FILL); select_a_node->set_valign(Label::VALIGN_CENTER); select_a_node->set_align(Label::ALIGN_CENTER); diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp index 574b47d770..7f023af848 100644 --- a/editor/plugins/abstract_polygon_2d_editor.cpp +++ b/editor/plugins/abstract_polygon_2d_editor.cpp @@ -571,7 +571,8 @@ void AbstractPolygon2DEditor::forward_canvas_draw_over_viewport(Control *p_overl return; Transform2D xform = canvas_item_editor->get_canvas_transform() * _get_node()->get_global_transform(); - const Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); + // All polygon points are sharp, so use the sharp handle icon + const Ref<Texture> handle = get_icon("EditorPathSharpHandle", "EditorIcons"); const Vertex active_point = get_active_point(); const int n_polygons = _get_polygon_count(); diff --git a/editor/plugins/abstract_polygon_2d_editor.h b/editor/plugins/abstract_polygon_2d_editor.h index 97244fa4e9..a00cdd0cf6 100644 --- a/editor/plugins/abstract_polygon_2d_editor.h +++ b/editor/plugins/abstract_polygon_2d_editor.h @@ -36,9 +36,6 @@ #include "scene/2d/polygon_2d.h" #include "scene/gui/tool_button.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class CanvasItemEditor; class AbstractPolygon2DEditor : public HBoxContainer { diff --git a/editor/plugins/animation_blend_space_2d_editor.h b/editor/plugins/animation_blend_space_2d_editor.h index 74186791e1..850a6201bb 100644 --- a/editor/plugins/animation_blend_space_2d_editor.h +++ b/editor/plugins/animation_blend_space_2d_editor.h @@ -40,9 +40,6 @@ #include "scene/gui/graph_edit.h" #include "scene/gui/popup.h" #include "scene/gui/tree.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class AnimationNodeBlendSpace2DEditor : public AnimationTreeNodeEditorPlugin { diff --git a/editor/plugins/animation_blend_tree_editor_plugin.h b/editor/plugins/animation_blend_tree_editor_plugin.h index cb40159a40..77b57a50d0 100644 --- a/editor/plugins/animation_blend_tree_editor_plugin.h +++ b/editor/plugins/animation_blend_tree_editor_plugin.h @@ -40,9 +40,6 @@ #include "scene/gui/graph_edit.h" #include "scene/gui/popup.h" #include "scene/gui/tree.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class AnimationNodeBlendTreeEditor : public AnimationTreeNodeEditorPlugin { diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h index 22152fa8f4..2ab2df68e6 100644 --- a/editor/plugins/animation_player_editor_plugin.h +++ b/editor/plugins/animation_player_editor_plugin.h @@ -39,9 +39,6 @@ #include "scene/gui/spin_box.h" #include "scene/gui/texture_button.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class AnimationTrackEditor; class AnimationPlayerEditorPlugin; diff --git a/editor/plugins/animation_tree_player_editor_plugin.h b/editor/plugins/animation_tree_player_editor_plugin.h index f4bfe58909..03bc559b86 100644 --- a/editor/plugins/animation_tree_player_editor_plugin.h +++ b/editor/plugins/animation_tree_player_editor_plugin.h @@ -38,9 +38,6 @@ #include "scene/gui/button.h" #include "scene/gui/popup.h" #include "scene/gui/tree.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class AnimationTreePlayerEditor : public Control { diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp index 4a2295fab2..132bf3973e 100644 --- a/editor/plugins/asset_library_editor_plugin.cpp +++ b/editor/plugins/asset_library_editor_plugin.cpp @@ -270,10 +270,10 @@ void EditorAssetLibraryItemDescription::add_preview(int p_id, bool p_video, cons if (!p_video) { preview.image = get_icon("ThumbnailWait", "EditorIcons"); } - if (preview_images.size() == 0 && !p_video) { + preview_images.push_back(preview); + if (preview_images.size() == 1 && !p_video) { _preview_click(p_id); } - preview_images.push_back(preview); } EditorAssetLibraryItemDescription::EditorAssetLibraryItemDescription() { @@ -354,16 +354,16 @@ void EditorAssetLibraryItemDownload::_http_download_completed(int p_status, int } break; case HTTPRequest::RESULT_REQUEST_FAILED: { error_text = TTR("Request failed, return code:") + " " + itos(p_code); - status->set_text(TTR("Request Failed.")); + status->set_text(TTR("Request failed.")); } break; case HTTPRequest::RESULT_DOWNLOAD_FILE_CANT_OPEN: case HTTPRequest::RESULT_DOWNLOAD_FILE_WRITE_ERROR: { - error_text = TTR("Cannot save response to") + " " + download->get_download_file(); + error_text = TTR("Cannot save response to:") + " " + download->get_download_file(); status->set_text(TTR("Write error.")); } break; case HTTPRequest::RESULT_REDIRECT_LIMIT_REACHED: { error_text = TTR("Request failed, too many redirects"); - status->set_text(TTR("Redirect Loop.")); + status->set_text(TTR("Redirect loop.")); } break; case HTTPRequest::RESULT_TIMEOUT: { error_text = TTR("Request failed, timeout"); @@ -472,9 +472,8 @@ void EditorAssetLibraryItemDownload::_notification(int p_what) { } void EditorAssetLibraryItemDownload::_close() { - DirAccess *da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM); - da->remove(download->get_download_file()); //clean up removed file - memdelete(da); + // Clean up downloaded file. + DirAccess::remove_file_or_error(download->get_download_file()); queue_delete(); } @@ -759,7 +758,7 @@ void EditorAssetLibrary::_image_update(bool use_cache, bool final, const PoolByt switch (image_queue[p_queue_id].image_type) { case IMAGE_QUEUE_ICON: - image->resize(64 * EDSCALE, 64 * EDSCALE, Image::INTERPOLATE_CUBIC); + image->resize(64 * EDSCALE, 64 * EDSCALE, Image::INTERPOLATE_LANCZOS); break; case IMAGE_QUEUE_THUMBNAIL: { diff --git a/editor/plugins/camera_editor_plugin.h b/editor/plugins/camera_editor_plugin.h index eac9acab93..400aee132d 100644 --- a/editor/plugins/camera_editor_plugin.h +++ b/editor/plugins/camera_editor_plugin.h @@ -35,10 +35,6 @@ #include "editor/editor_plugin.h" #include "scene/3d/camera.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class CameraEditor : public Control { GDCLASS(CameraEditor, Control); diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp index ff134ff2d1..cc707dbf44 100644 --- a/editor/plugins/canvas_item_editor_plugin.cpp +++ b/editor/plugins/canvas_item_editor_plugin.cpp @@ -2918,10 +2918,15 @@ void CanvasItemEditor::_draw_selection() { Point2 bsfrom = transform.xform(drag_from); Point2 bsto = transform.xform(box_selecting_to); - VisualServer::get_singleton()->canvas_item_add_rect( - ci, + viewport->draw_rect( Rect2(bsfrom, bsto - bsfrom), - get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375)); + get_color("box_selection_fill_color", "Editor")); + + viewport->draw_rect( + Rect2(bsfrom, bsto - bsfrom), + get_color("box_selection_stroke_color", "Editor"), + false, + Math::round(EDSCALE)); } if (drag_type == DRAG_ROTATE) { @@ -4998,11 +5003,13 @@ CanvasItemEditor::CanvasItemEditor(EditorNode *p_editor) { p->set_hide_on_checkable_item_selection(false); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_grid", TTR("Snap to Grid")), SNAP_USE_GRID); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_rotation_snap", TTR("Use Rotation Snap")), SNAP_USE_ROTATION); - p->add_shortcut(ED_SHORTCUT("canvas_item_editor/configure_snap", TTR("Configure Snap...")), SNAP_CONFIGURE); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/snap_relative", TTR("Snap Relative")), SNAP_RELATIVE); p->add_check_shortcut(ED_SHORTCUT("canvas_item_editor/use_pixel_snap", TTR("Use Pixel Snap")), SNAP_USE_PIXEL); p->add_submenu_item(TTR("Smart Snapping"), "SmartSnapping"); + p->add_separator(); + p->add_shortcut(ED_SHORTCUT("canvas_item_editor/configure_snap", TTR("Configure Snap...")), SNAP_CONFIGURE); + smartsnap_config_popup = memnew(PopupMenu); p->add_child(smartsnap_config_popup); smartsnap_config_popup->set_name("SmartSnapping"); diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h index 553ded6b14..e6eab57810 100644 --- a/editor/plugins/canvas_item_editor_plugin.h +++ b/editor/plugins/canvas_item_editor_plugin.h @@ -39,9 +39,6 @@ #include "scene/gui/label.h" #include "scene/gui/panel_container.h" #include "scene/gui/spin_box.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class CanvasItemEditorViewport; diff --git a/editor/plugins/collision_polygon_2d_editor_plugin.h b/editor/plugins/collision_polygon_2d_editor_plugin.h index e15360d4e5..3f0734fb19 100644 --- a/editor/plugins/collision_polygon_2d_editor_plugin.h +++ b/editor/plugins/collision_polygon_2d_editor_plugin.h @@ -34,9 +34,6 @@ #include "editor/plugins/abstract_polygon_2d_editor.h" #include "scene/2d/collision_polygon_2d.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class CollisionPolygon2DEditor : public AbstractPolygon2DEditor { GDCLASS(CollisionPolygon2DEditor, AbstractPolygon2DEditor); diff --git a/editor/plugins/collision_polygon_editor_plugin.h b/editor/plugins/collision_polygon_editor_plugin.h index a699641aba..2a904a53ba 100644 --- a/editor/plugins/collision_polygon_editor_plugin.h +++ b/editor/plugins/collision_polygon_editor_plugin.h @@ -38,10 +38,6 @@ #include "scene/3d/mesh_instance.h" #include "scene/gui/tool_button.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class CanvasItemEditor; class Polygon3DEditor : public HBoxContainer { diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp index 7c2116f06b..9d625af959 100644 --- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp +++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp @@ -87,8 +87,7 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { Ref<Image> img; img.instance(); Error err = ImageLoader::load_image(source_emission_file, img); - ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file); - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Error loading image: " + source_emission_file + "."); if (img->is_compressed()) { img->decompress(); @@ -196,8 +195,7 @@ void CPUParticles2DEditorPlugin::_generate_emission_mask() { valid_normals.resize(vpc); } - ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image...")); - ERR_FAIL_COND(valid_positions.size() == 0); + ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image..."); if (capture_colors) { PoolColorArray pca; diff --git a/editor/plugins/item_list_editor_plugin.h b/editor/plugins/item_list_editor_plugin.h index 701632e576..78b176620e 100644 --- a/editor/plugins/item_list_editor_plugin.h +++ b/editor/plugins/item_list_editor_plugin.h @@ -39,10 +39,6 @@ #include "scene/gui/option_button.h" #include "scene/gui/popup_menu.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class ItemListPlugin : public Object { GDCLASS(ItemListPlugin, Object); diff --git a/editor/plugins/light_occluder_2d_editor_plugin.h b/editor/plugins/light_occluder_2d_editor_plugin.h index 633fda7091..95fa0df2c1 100644 --- a/editor/plugins/light_occluder_2d_editor_plugin.h +++ b/editor/plugins/light_occluder_2d_editor_plugin.h @@ -34,9 +34,6 @@ #include "editor/plugins/abstract_polygon_2d_editor.h" #include "scene/2d/light_occluder_2d.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class LightOccluder2DEditor : public AbstractPolygon2DEditor { GDCLASS(LightOccluder2DEditor, AbstractPolygon2DEditor); diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp index d59efe49e7..3ea014a38d 100644 --- a/editor/plugins/multimesh_editor_plugin.cpp +++ b/editor/plugins/multimesh_editor_plugin.cpp @@ -147,9 +147,8 @@ void MultiMeshEditor::_populate() { w.release(); PoolVector<Face3> faces = geometry; - ERR_EXPLAIN(TTR("Parent has no solid faces to populate.")); int facecount = faces.size(); - ERR_FAIL_COND(!facecount); + ERR_FAIL_COND_MSG(!facecount, "Parent has no solid faces to populate."); PoolVector<Face3>::Read r = faces.read(); @@ -164,10 +163,8 @@ void MultiMeshEditor::_populate() { area_accum += area; } - ERR_EXPLAIN(TTR("Couldn't map area.")); - ERR_FAIL_COND(triangle_area_map.size() == 0); - ERR_EXPLAIN(TTR("Couldn't map area.")); - ERR_FAIL_COND(area_accum == 0); + ERR_FAIL_COND_MSG(triangle_area_map.size() == 0, "Couldn't map area."); + ERR_FAIL_COND_MSG(area_accum == 0, "Couldn't map area."); Ref<MultiMesh> multimesh = memnew(MultiMesh); multimesh->set_mesh(mesh); diff --git a/editor/plugins/multimesh_editor_plugin.h b/editor/plugins/multimesh_editor_plugin.h index fe87a2b9cb..5323441bd8 100644 --- a/editor/plugins/multimesh_editor_plugin.h +++ b/editor/plugins/multimesh_editor_plugin.h @@ -36,10 +36,6 @@ #include "scene/3d/multimesh_instance.h" #include "scene/gui/spin_box.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class MultiMeshEditor : public Control { GDCLASS(MultiMeshEditor, Control); diff --git a/editor/plugins/navigation_polygon_editor_plugin.h b/editor/plugins/navigation_polygon_editor_plugin.h index 336c28d642..2a387a8b1e 100644 --- a/editor/plugins/navigation_polygon_editor_plugin.h +++ b/editor/plugins/navigation_polygon_editor_plugin.h @@ -34,9 +34,6 @@ #include "editor/plugins/abstract_polygon_2d_editor.h" #include "scene/2d/navigation_polygon.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class NavigationPolygonEditor : public AbstractPolygon2DEditor { GDCLASS(NavigationPolygonEditor, AbstractPolygon2DEditor); diff --git a/editor/plugins/particles_2d_editor_plugin.cpp b/editor/plugins/particles_2d_editor_plugin.cpp index e68bca55cb..8025e12885 100644 --- a/editor/plugins/particles_2d_editor_plugin.cpp +++ b/editor/plugins/particles_2d_editor_plugin.cpp @@ -160,8 +160,7 @@ void Particles2DEditorPlugin::_generate_emission_mask() { Ref<Image> img; img.instance(); Error err = ImageLoader::load_image(source_emission_file, img); - ERR_EXPLAIN(TTR("Error loading image:") + " " + source_emission_file); - ERR_FAIL_COND(err != OK); + ERR_FAIL_COND_MSG(err != OK, "Error loading image: " + source_emission_file + "."); if (img->is_compressed()) { img->decompress(); @@ -269,8 +268,7 @@ void Particles2DEditorPlugin::_generate_emission_mask() { valid_normals.resize(vpc); } - ERR_EXPLAIN(TTR("No pixels with transparency > 128 in image...")); - ERR_FAIL_COND(valid_positions.size() == 0); + ERR_FAIL_COND_MSG(valid_positions.size() == 0, "No pixels with transparency > 128 in image..."); PoolVector<uint8_t> texdata; diff --git a/editor/plugins/particles_editor_plugin.cpp b/editor/plugins/particles_editor_plugin.cpp index 75d31459e8..31b0539bfe 100644 --- a/editor/plugins/particles_editor_plugin.cpp +++ b/editor/plugins/particles_editor_plugin.cpp @@ -55,8 +55,7 @@ bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vect if (!triangle_area_map.size() || area_accum == 0) { - err_dialog->set_text(TTR("Faces contain no area!")); - err_dialog->popup_centered_minsize(); + EditorNode::get_singleton()->show_warning(TTR("The geometry's faces don't contain any area.")); return false; } @@ -90,8 +89,7 @@ bool ParticlesEditorBase::_generate(PoolVector<Vector3> &points, PoolVector<Vect if (gcount == 0) { - err_dialog->set_text(TTR("No faces!")); - err_dialog->popup_centered_minsize(); + EditorNode::get_singleton()->show_warning(TTR("The geometry doesn't contain any faces.")); return false; } @@ -169,11 +167,16 @@ void ParticlesEditorBase::_node_selected(const NodePath &p_path) { if (!sel) return; + if (!sel->is_class("Spatial")) { + + EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't inherit from Spatial."), sel->get_name())); + return; + } + VisualInstance *vi = Object::cast_to<VisualInstance>(sel); if (!vi) { - err_dialog->set_text(TTR("Node does not contain geometry.")); - err_dialog->popup_centered_minsize(); + EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't contain geometry."), sel->get_name())); return; } @@ -181,8 +184,7 @@ void ParticlesEditorBase::_node_selected(const NodePath &p_path) { if (geometry.size() == 0) { - err_dialog->set_text(TTR("Node does not contain geometry (faces).")); - err_dialog->popup_centered_minsize(); + EditorNode::get_singleton()->show_warning(vformat(TTR("\"%s\" doesn't contain face geometry."), sel->get_name())); return; } @@ -231,9 +233,6 @@ ParticlesEditorBase::ParticlesEditorBase() { emission_dialog->get_ok()->set_text(TTR("Create")); emission_dialog->connect("confirmed", this, "_generate_emission_points"); - err_dialog = memnew(ConfirmationDialog); - add_child(err_dialog); - emission_file_dialog = memnew(EditorFileDialog); add_child(emission_file_dialog); emission_file_dialog->connect("file_selected", this, "_resource_seleted"); diff --git a/editor/plugins/particles_editor_plugin.h b/editor/plugins/particles_editor_plugin.h index 5d05fbd4ac..1b3a1877a4 100644 --- a/editor/plugins/particles_editor_plugin.h +++ b/editor/plugins/particles_editor_plugin.h @@ -36,10 +36,6 @@ #include "scene/3d/particles.h" #include "scene/gui/spin_box.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class ParticlesEditorBase : public Control { GDCLASS(ParticlesEditorBase, Control); @@ -53,8 +49,6 @@ protected: EditorFileDialog *emission_file_dialog; SceneTreeDialog *emission_tree_dialog; - ConfirmationDialog *err_dialog; - ConfirmationDialog *emission_dialog; SpinBox *emission_amount; OptionButton *emission_fill; diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp index b87bd29cbd..f02dc0bd6d 100644 --- a/editor/plugins/path_2d_editor_plugin.cpp +++ b/editor/plugins/path_2d_editor_plugin.cpp @@ -367,18 +367,18 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) { void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { - if (!node) + if (!node || !node->is_visible_in_tree() || !node->get_curve().is_valid()) return; - if (!node->is_visible_in_tree()) - return; + Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); - if (!node->get_curve().is_valid()) - return; + const Ref<Texture> path_sharp_handle = get_icon("EditorPathSharpHandle", "EditorIcons"); + const Ref<Texture> path_smooth_handle = get_icon("EditorPathSmoothHandle", "EditorIcons"); + // Both handle icons must be of the same size + const Size2 handle_size = path_sharp_handle->get_size(); - Transform2D xform = canvas_item_editor->get_canvas_transform() * node->get_global_transform(); - Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); - Size2 handle_size = handle->get_size(); + const Ref<Texture> curve_handle = get_icon("EditorCurveHandle", "EditorIcons"); + const Size2 curve_handle_size = curve_handle->get_size(); Ref<Curve2D> curve = node->get_curve(); @@ -387,19 +387,35 @@ void Path2DEditor::forward_canvas_draw_over_viewport(Control *p_overlay) { for (int i = 0; i < len; i++) { Vector2 point = xform.xform(curve->get_point_position(i)); - vpc->draw_texture_rect(handle, Rect2(point - handle_size * 0.5, handle_size), false, Color(1, 1, 1, 1)); + // Determines the point icon to be used + bool smooth = false; if (i < len - 1) { Vector2 pointout = xform.xform(curve->get_point_position(i) + curve->get_point_out(i)); - vpc->draw_line(point, pointout, Color(0.5, 0.5, 1.0, 0.8), 1.0); - vpc->draw_texture_rect(handle, Rect2(pointout - handle_size * 0.5, handle_size), false, Color(1, 0.5, 1, 0.3)); + if (point != pointout) { + smooth = true; + // Draw the line with a dark and light color to be visible on all backgrounds + vpc->draw_line(point, pointout, Color(0, 0, 0, 0.5), Math::round(EDSCALE), true); + vpc->draw_line(point, pointout, Color(1, 1, 1, 0.5), Math::round(EDSCALE), true); + vpc->draw_texture_rect(curve_handle, Rect2(pointout - curve_handle_size * 0.5, curve_handle_size), false, Color(1, 1, 1, 0.75)); + } } if (i > 0) { Vector2 pointin = xform.xform(curve->get_point_position(i) + curve->get_point_in(i)); - vpc->draw_line(point, pointin, Color(0.5, 0.5, 1.0, 0.8), 1.0); - vpc->draw_texture_rect(handle, Rect2(pointin - handle_size * 0.5, handle_size), false, Color(1, 0.5, 1, 0.3)); + if (point != pointin) { + smooth = true; + // Draw the line with a dark and light color to be visible on all backgrounds + vpc->draw_line(point, pointin, Color(0, 0, 0, 0.5), Math::round(EDSCALE), true); + vpc->draw_line(point, pointin, Color(1, 1, 1, 0.5), Math::round(EDSCALE), true); + vpc->draw_texture_rect(curve_handle, Rect2(pointin - curve_handle_size * 0.5, curve_handle_size), false, Color(1, 1, 1, 0.75)); + } } + + vpc->draw_texture_rect( + smooth ? path_smooth_handle : path_sharp_handle, + Rect2(point - handle_size * 0.5, handle_size), + false); } if (on_edge) { diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h index 44472f7a81..ecec5f5253 100644 --- a/editor/plugins/path_2d_editor_plugin.h +++ b/editor/plugins/path_2d_editor_plugin.h @@ -36,9 +36,6 @@ #include "scene/2d/path_2d.h" #include "scene/gui/tool_button.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class CanvasItemEditor; class Path2DEditor : public HBoxContainer { diff --git a/editor/plugins/path_editor_plugin.cpp b/editor/plugins/path_editor_plugin.cpp index 1ae5acc5ff..2493380585 100644 --- a/editor/plugins/path_editor_plugin.cpp +++ b/editor/plugins/path_editor_plugin.cpp @@ -652,7 +652,6 @@ PathSpatialGizmoPlugin::PathSpatialGizmoPlugin() { Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8)); create_material("path_material", path_color); - path_color.a = 0.4; - create_material("path_thin_material", path_color); + create_material("path_thin_material", Color(0.5, 0.5, 0.5)); create_handle_material("handles"); } diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp index 59004a08c0..bd532a6418 100644 --- a/editor/plugins/polygon_2d_editor_plugin.cpp +++ b/editor/plugins/polygon_2d_editor_plugin.cpp @@ -1045,8 +1045,8 @@ void Polygon2DEditor::_uv_draw() { } } - Ref<Texture> handle = get_icon("EditorHandle", "EditorIcons"); - Ref<Texture> internal_handle = get_icon("EditorInternalHandle", "EditorIcons"); + // All UV points are sharp, so use the sharp handle icon + Ref<Texture> handle = get_icon("EditorPathSharpHandle", "EditorIcons"); Color poly_line_color = Color(0.9, 0.5, 0.5); if (polygons.size() || polygon_create.size()) { @@ -1120,7 +1120,8 @@ void Polygon2DEditor::_uv_draw() { if (i < uv_draw_max) { uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5); } else { - uv_edit_draw->draw_texture(internal_handle, mtx.xform(uvs[i]) - internal_handle->get_size() * 0.5); + // Internal vertex + uv_edit_draw->draw_texture(handle, mtx.xform(uvs[i]) - handle->get_size() * 0.5, Color(0.6, 0.8, 1)); } } } diff --git a/editor/plugins/polygon_2d_editor_plugin.h b/editor/plugins/polygon_2d_editor_plugin.h index 24ca2ea3f4..009501a70c 100644 --- a/editor/plugins/polygon_2d_editor_plugin.h +++ b/editor/plugins/polygon_2d_editor_plugin.h @@ -33,9 +33,7 @@ #include "editor/plugins/abstract_polygon_2d_editor.h" #include "scene/gui/scroll_container.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ + class Polygon2DEditor : public AbstractPolygon2DEditor { GDCLASS(Polygon2DEditor, AbstractPolygon2DEditor); diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index ec391186c3..76c7545874 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -490,9 +490,6 @@ void ScriptEditor::_update_recent_scripts() { Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scripts", Array()); recent_scripts->clear(); - recent_scripts->add_shortcut(ED_SHORTCUT("script_editor/open_recent", TTR("Open Recent"))); - recent_scripts->add_separator(); - String path; for (int i = 0; i < rc.size(); i++) { @@ -515,11 +512,6 @@ void ScriptEditor::_open_recent_script(int p_idx) { return; } - // take two for the open recent button - if (p_idx > 0) { - p_idx -= 2; - } - Array rc = EditorSettings::get_singleton()->get_project_metadata("recent_files", "scripts", Array()); ERR_FAIL_INDEX(p_idx, rc.size()); @@ -1000,7 +992,7 @@ void ScriptEditor::_menu_option(int p_option) { file_dialog->clear_filters(); file_dialog->popup_centered_ratio(); - file_dialog->set_title(TTR("New TextFile...")); + file_dialog->set_title(TTR("New Text File...")); } break; case FILE_OPEN: { file_dialog->set_mode(EditorFileDialog::MODE_OPEN_FILE); @@ -1072,6 +1064,7 @@ void ScriptEditor::_menu_option(int p_option) { save_all_scripts(); } break; case SEARCH_IN_FILES: { + _on_find_in_files_requested(""); } break; case SEARCH_HELP: { @@ -3240,7 +3233,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { file_menu->set_switch_on_hover(true); file_menu->get_popup()->set_hide_on_window_lose_focus(true); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new", TTR("New Script...")), FILE_NEW); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New TextFile...")), FILE_NEW_TEXTFILE); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/new_textfile", TTR("New Text File...")), FILE_NEW_TEXTFILE); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/open", TTR("Open...")), FILE_OPEN); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_T), FILE_REOPEN_CLOSED); file_menu->get_popup()->add_submenu_item(TTR("Open Recent"), "RecentScripts", FILE_OPEN_RECENT); @@ -3273,17 +3266,20 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { theme_submenu->connect("id_pressed", this, "_theme_option"); theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/import_theme", TTR("Import Theme...")), THEME_IMPORT); theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/reload_theme", TTR("Reload Theme")), THEME_RELOAD); + theme_submenu->add_separator(); theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/save_theme", TTR("Save Theme")), THEME_SAVE); theme_submenu->add_shortcut(ED_SHORTCUT("script_editor/save_theme_as", TTR("Save Theme As...")), THEME_SAVE_AS); file_menu->get_popup()->add_separator(); - file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_docs", TTR("Close Docs")), CLOSE_DOCS); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_file", TTR("Close"), KEY_MASK_CMD | KEY_W), FILE_CLOSE); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_all", TTR("Close All")), CLOSE_ALL); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_other_tabs", TTR("Close Other Tabs")), CLOSE_OTHER_TABS); + file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/close_docs", TTR("Close Docs")), CLOSE_DOCS); + file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/run_file", TTR("Run"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_X), FILE_RUN); + file_menu->get_popup()->add_separator(); file_menu->get_popup()->add_shortcut(ED_SHORTCUT("script_editor/toggle_scripts_panel", TTR("Toggle Scripts Panel"), KEY_MASK_CMD | KEY_BACKSLASH), TOGGLE_SCRIPTS_PANEL); file_menu->get_popup()->connect("id_pressed", this, "_menu_option"); @@ -3572,8 +3568,7 @@ ScriptEditorPlugin::ScriptEditorPlugin(EditorNode *p_node) { EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "text_editor/external/exec_flags", PROPERTY_HINT_PLACEHOLDER_TEXT, "Call flags with placeholders: {project}, {file}, {col}, {line}.")); ED_SHORTCUT("script_editor/reopen_closed_script", TTR("Reopen Closed Script"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_T); - ED_SHORTCUT("script_editor/open_recent", TTR("Open Recent")); - ED_SHORTCUT("script_editor/clear_recent", TTR("Clear Recent Files")); + ED_SHORTCUT("script_editor/clear_recent", TTR("Clear Recent Scripts")); } ScriptEditorPlugin::~ScriptEditorPlugin() { diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index 284e0b3d97..bded590351 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -30,6 +30,7 @@ #include "script_text_editor.h" +#include "core/math/expression.h" #include "core/os/keyboard.h" #include "editor/editor_node.h" #include "editor/editor_settings.h" @@ -1147,6 +1148,32 @@ void ScriptTextEditor::_edit_option(int p_op) { _convert_case(CodeTextEditor::CAPITALIZE); } break; + case EDIT_EVALUATE: { + + Expression expression; + Vector<String> lines = code_editor->get_text_edit()->get_selection_text().split("\n"); + PoolStringArray results; + + for (int i = 0; i < lines.size(); i++) { + String line = lines[i]; + String whitespace = line.substr(0, line.size() - line.strip_edges(true, false).size()); //extract the whitespace at the beginning + + if (expression.parse(line) == OK) { + Variant result = expression.execute(Array(), Variant(), false); + if (expression.get_error_text() == "") { + results.append(whitespace + (String)result); + } else { + results.append(line); + } + } else { + results.append(line); + } + } + + code_editor->get_text_edit()->begin_complex_operation(); //prevents creating a two-step undo + code_editor->get_text_edit()->insert_text_at_cursor(results.join("\n")); + code_editor->get_text_edit()->end_complex_operation(); + } break; case SEARCH_FIND: { code_editor->get_find_replace_bar()->popup_search(); @@ -1170,7 +1197,6 @@ void ScriptTextEditor::_edit_option(int p_op) { // Yep, because it doesn't make sense to instance this dialog for every single script open... // So this will be delegated to the ScriptEditor. emit_signal("search_in_files_requested", selected_text); - } break; case SEARCH_LOCATE_FUNCTION: { @@ -1621,23 +1647,26 @@ void ScriptTextEditor::_color_changed(const Color &p_color) { line_with_replaced_args = line_with_replaced_args.insert(color_args_pos, new_args); color_args = new_args; + code_editor->get_text_edit()->begin_complex_operation(); code_editor->get_text_edit()->set_line(color_position.x, line_with_replaced_args); + code_editor->get_text_edit()->end_complex_operation(); code_editor->get_text_edit()->update(); } void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p_foldable, bool p_open_docs, bool p_goto_definition) { context_menu->clear(); - if (p_selection) { - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY); - } + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); + context_menu->add_separator(); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/cut"), EDIT_CUT); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/copy"), EDIT_COPY); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/paste"), EDIT_PASTE); + context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/select_all"), EDIT_SELECT_ALL); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); - context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); + context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_left"), EDIT_INDENT_LEFT); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/indent_right"), EDIT_INDENT_RIGHT); @@ -1648,6 +1677,7 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p context_menu->add_separator(); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE); context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE); + context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE); } if (p_foldable) context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE); @@ -1748,6 +1778,7 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu->get_popup()->add_separator(); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/clone_down"), EDIT_CLONE_DOWN); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE); + edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS); @@ -1873,6 +1904,7 @@ void ScriptTextEditor::register_editor() { ED_SHORTCUT("script_text_editor/clone_down", TTR("Clone Down"), KEY_MASK_CMD | KEY_D); ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CMD | KEY_SPACE); #endif + ED_SHORTCUT("script_text_editor/evaluate_selection", TTR("Evaluate Selection"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_E); ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CMD | KEY_MASK_ALT | KEY_T); ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent to Spaces"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Y); ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent to Tabs"), KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_I); diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 4b2307555b..38c6da5c33 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -120,6 +120,7 @@ class ScriptTextEditor : public ScriptEditorBase { EDIT_TO_UPPERCASE, EDIT_TO_LOWERCASE, EDIT_CAPITALIZE, + EDIT_EVALUATE, EDIT_TOGGLE_FOLD_LINE, EDIT_FOLD_ALL_LINES, EDIT_UNFOLD_ALL_LINES, diff --git a/editor/plugins/spatial_editor_plugin.cpp b/editor/plugins/spatial_editor_plugin.cpp index 58234ba954..2eb3ce1ec3 100644 --- a/editor/plugins/spatial_editor_plugin.cpp +++ b/editor/plugins/spatial_editor_plugin.cpp @@ -2373,16 +2373,22 @@ void SpatialEditorViewport::_draw() { get_stylebox("Focus", "EditorStyles")->draw(surface->get_canvas_item(), r); } - RID ci = surface->get_canvas_item(); - if (cursor.region_select) { + const Rect2 selection_rect = Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin); - VisualServer::get_singleton()->canvas_item_add_rect( - ci, - Rect2(cursor.region_begin, cursor.region_end - cursor.region_begin), - get_color("accent_color", "Editor") * Color(1, 1, 1, 0.375)); + surface->draw_rect( + selection_rect, + get_color("box_selection_fill_color", "Editor")); + + surface->draw_rect( + selection_rect, + get_color("box_selection_stroke_color", "Editor"), + false, + Math::round(EDSCALE)); } + RID ci = surface->get_canvas_item(); + if (message_time > 0) { Ref<Font> font = get_font("font", "Label"); Point2 msgpos = Point2(5, get_size().y - 20); @@ -3551,7 +3557,7 @@ SpatialEditorViewport::SpatialEditorViewport(SpatialEditor *p_spatial_editor, Ed view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_half_resolution", TTR("Half Resolution")), VIEW_HALF_RESOLUTION); view_menu->get_popup()->add_separator(); view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_listener", TTR("Audio Listener")), VIEW_AUDIO_LISTENER); - view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_doppler", TTR("Doppler Enable")), VIEW_AUDIO_DOPPLER); + view_menu->get_popup()->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_audio_doppler", TTR("Enable Doppler")), VIEW_AUDIO_DOPPLER); view_menu->get_popup()->set_item_checked(view_menu->get_popup()->get_item_index(VIEW_GIZMOS), true); view_menu->get_popup()->add_separator(); @@ -5170,7 +5176,7 @@ void SpatialEditor::snap_selected_nodes_to_floor() { // We add a bit of margin to the from position to avoid it from snapping // when the spatial is already on a floor and there's another floor under // it - from = from + Vector3(0.0, 0.1, 0.0); + from = from + Vector3(0.0, 0.2, 0.0); Dictionary d; @@ -5185,31 +5191,56 @@ void SpatialEditor::snap_selected_nodes_to_floor() { Array keys = snap_data.keys(); - if (keys.size()) { - undo_redo->create_action(TTR("Snap Nodes To Floor")); + // The maximum height an object can travel to be snapped + const float max_snap_height = 20.0; + + // Will be set to `true` if at least one node from the selection was sucessfully snapped + bool snapped_to_floor = false; + if (keys.size()) { + // For snapping to be performed, there must be solid geometry under at least one of the selected nodes. + // We need to check this before snapping to register the undo/redo action only if needed. for (int i = 0; i < keys.size(); i++) { Node *node = keys[i]; Spatial *sp = Object::cast_to<Spatial>(node); - Dictionary d = snap_data[node]; Vector3 from = d["from"]; - Vector3 position_offset = d["position_offset"]; - - Vector3 to = from - Vector3(0.0, 10.0, 0.0); + Vector3 to = from - Vector3(0.0, max_snap_height, 0.0); Set<RID> excluded = _get_physics_bodies_rid(sp); if (ss->intersect_ray(from, to, result, excluded)) { - Transform new_transform = sp->get_global_transform(); - new_transform.origin.y = result.position.y; - new_transform.origin = new_transform.origin - position_offset; - - undo_redo->add_do_method(sp, "set_global_transform", new_transform); - undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform()); + snapped_to_floor = true; } } - undo_redo->commit_action(); + if (snapped_to_floor) { + undo_redo->create_action(TTR("Snap Nodes To Floor")); + + // Perform snapping if at least one node can be snapped + for (int i = 0; i < keys.size(); i++) { + Node *node = keys[i]; + Spatial *sp = Object::cast_to<Spatial>(node); + Dictionary d = snap_data[node]; + Vector3 from = d["from"]; + Vector3 to = from - Vector3(0.0, max_snap_height, 0.0); + Set<RID> excluded = _get_physics_bodies_rid(sp); + + if (ss->intersect_ray(from, to, result, excluded)) { + Vector3 position_offset = d["position_offset"]; + Transform new_transform = sp->get_global_transform(); + + new_transform.origin.y = result.position.y; + new_transform.origin = new_transform.origin - position_offset; + + undo_redo->add_do_method(sp, "set_global_transform", new_transform); + undo_redo->add_undo_method(sp, "set_global_transform", sp->get_global_transform()); + } + } + + undo_redo->commit_action(); + } else { + EditorNode::get_singleton()->show_warning(TTR("Couldn't find a solid floor to snap the selection to.")); + } } } @@ -5219,42 +5250,6 @@ void SpatialEditor::_unhandled_key_input(Ref<InputEvent> p_event) { return; snap_key_enabled = Input::get_singleton()->is_key_pressed(KEY_CONTROL); - - Ref<InputEventKey> k = p_event; - - if (k.is_valid()) { - - // 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->is_pressed()) - return; - - 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); - } else if (ED_IS_SHORTCUT("spatial_editor/tool_rotate", p_event)) { - _menu_item_pressed(MENU_TOOL_ROTATE); - } else if (ED_IS_SHORTCUT("spatial_editor/tool_scale", p_event)) { - _menu_item_pressed(MENU_TOOL_SCALE); - } else if (ED_IS_SHORTCUT("spatial_editor/snap_to_floor", p_event)) { - snap_selected_nodes_to_floor(); - } else if (ED_IS_SHORTCUT("spatial_editor/local_coords", p_event)) { - if (are_local_coords_enabled()) { - _menu_item_toggled(false, MENU_TOOL_LOCAL_COORDS); - } else { - _menu_item_toggled(true, MENU_TOOL_LOCAL_COORDS); - } - } else if (ED_IS_SHORTCUT("spatial_editor/snap", p_event)) { - if (is_snap_enabled()) { - _menu_item_toggled(false, MENU_TOOL_USE_SNAP); - } else { - _menu_item_toggled(true, MENU_TOOL_USE_SNAP); - } - } - } - } } void SpatialEditor::_notification(int p_what) { @@ -5528,7 +5523,8 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_SELECT]->set_pressed(true); button_binds.write[0] = MENU_TOOL_SELECT; tool_button[TOOL_MODE_SELECT]->connect("pressed", this, "_menu_item_pressed", button_binds); - tool_button[TOOL_MODE_SELECT]->set_tooltip(TTR("Select Mode (Q)") + "\n" + keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection")); + tool_button[TOOL_MODE_SELECT]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_select", TTR("Select Mode"), KEY_Q)); + tool_button[TOOL_MODE_SELECT]->set_tooltip(keycode_get_string(KEY_MASK_CMD) + TTR("Drag: Rotate\nAlt+Drag: Move\nAlt+RMB: Depth list selection")); hbc_menu->add_child(memnew(VSeparator)); @@ -5538,7 +5534,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_MOVE]->set_flat(true); button_binds.write[0] = MENU_TOOL_MOVE; tool_button[TOOL_MODE_MOVE]->connect("pressed", this, "_menu_item_pressed", button_binds); - tool_button[TOOL_MODE_MOVE]->set_tooltip(TTR("Move Mode (W)")); + tool_button[TOOL_MODE_MOVE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_move", TTR("Move Mode"), KEY_W)); tool_button[TOOL_MODE_ROTATE] = memnew(ToolButton); hbc_menu->add_child(tool_button[TOOL_MODE_ROTATE]); @@ -5546,7 +5542,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_ROTATE]->set_flat(true); button_binds.write[0] = MENU_TOOL_ROTATE; tool_button[TOOL_MODE_ROTATE]->connect("pressed", this, "_menu_item_pressed", button_binds); - tool_button[TOOL_MODE_ROTATE]->set_tooltip(TTR("Rotate Mode (E)")); + tool_button[TOOL_MODE_ROTATE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_rotate", TTR("Rotate Mode"), KEY_E)); tool_button[TOOL_MODE_SCALE] = memnew(ToolButton); hbc_menu->add_child(tool_button[TOOL_MODE_SCALE]); @@ -5554,7 +5550,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_button[TOOL_MODE_SCALE]->set_flat(true); button_binds.write[0] = MENU_TOOL_SCALE; tool_button[TOOL_MODE_SCALE]->connect("pressed", this, "_menu_item_pressed", button_binds); - tool_button[TOOL_MODE_SCALE]->set_tooltip(TTR("Scale Mode (R)")); + tool_button[TOOL_MODE_SCALE]->set_shortcut(ED_SHORTCUT("spatial_editor/tool_scale", TTR("Scale Mode"), KEY_R)); hbc_menu->add_child(memnew(VSeparator)); @@ -5598,9 +5594,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_flat(true); button_binds.write[0] = MENU_TOOL_LOCAL_COORDS; tool_option_button[TOOL_OPT_LOCAL_COORDS]->connect("toggled", this, "_menu_item_toggled", button_binds); - ED_SHORTCUT("spatial_editor/local_coords", TTR("Local Coords"), KEY_T); - sct = ED_GET_SHORTCUT("spatial_editor/local_coords").ptr()->get_as_text(); - tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_tooltip(vformat(TTR("Local Space Mode (%s)"), sct)); + tool_option_button[TOOL_OPT_LOCAL_COORDS]->set_shortcut(ED_SHORTCUT("spatial_editor/local_coords", TTR("Use Local Space"), KEY_T)); tool_option_button[TOOL_OPT_USE_SNAP] = memnew(ToolButton); hbc_menu->add_child(tool_option_button[TOOL_OPT_USE_SNAP]); @@ -5608,9 +5602,7 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { tool_option_button[TOOL_OPT_USE_SNAP]->set_flat(true); button_binds.write[0] = MENU_TOOL_USE_SNAP; tool_option_button[TOOL_OPT_USE_SNAP]->connect("toggled", this, "_menu_item_toggled", button_binds); - ED_SHORTCUT("spatial_editor/snap", TTR("Snap"), KEY_Y); - sct = ED_GET_SHORTCUT("spatial_editor/snap").ptr()->get_as_text(); - tool_option_button[TOOL_OPT_USE_SNAP]->set_tooltip(vformat(TTR("Snap Mode (%s)"), sct)); + tool_option_button[TOOL_OPT_USE_SNAP]->set_shortcut(ED_SHORTCUT("spatial_editor/snap", TTR("Use Snap"), KEY_Y)); hbc_menu->add_child(memnew(VSeparator)); @@ -5630,12 +5622,6 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { ED_SHORTCUT("spatial_editor/focus_selection", TTR("Focus Selection"), KEY_F); ED_SHORTCUT("spatial_editor/align_transform_with_view", TTR("Align Transform with View"), KEY_MASK_ALT + KEY_MASK_CMD + KEY_M); ED_SHORTCUT("spatial_editor/align_rotation_with_view", TTR("Align Rotation 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/freelook_toggle", TTR("Toggle Freelook"), KEY_MASK_SHIFT + KEY_F); PopupMenu *p; @@ -5647,10 +5633,11 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { p = transform_menu->get_popup(); p->add_shortcut(ED_SHORTCUT("spatial_editor/snap_to_floor", TTR("Snap Object to Floor"), KEY_PAGEDOWN), MENU_SNAP_TO_FLOOR); - p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap...")), MENU_TRANSFORM_CONFIGURE_SNAP); - p->add_separator(); p->add_shortcut(ED_SHORTCUT("spatial_editor/transform_dialog", TTR("Transform Dialog...")), MENU_TRANSFORM_DIALOG); + p->add_separator(); + p->add_shortcut(ED_SHORTCUT("spatial_editor/configure_snap", TTR("Configure Snap...")), MENU_TRANSFORM_CONFIGURE_SNAP); + p->connect("id_pressed", this, "_menu_item_pressed"); view_menu = memnew(MenuButton); @@ -5674,11 +5661,11 @@ SpatialEditor::SpatialEditor(EditorNode *p_editor) { p->add_submenu_item(TTR("Gizmos"), "GizmosMenu"); p->add_separator(); - p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_origin", TTR("View Origin")), MENU_VIEW_ORIGIN); p->add_check_shortcut(ED_SHORTCUT("spatial_editor/view_grid", TTR("View Grid")), MENU_VIEW_GRID); + p->add_separator(); - p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings")), MENU_VIEW_CAMERA_SETTINGS); + p->add_shortcut(ED_SHORTCUT("spatial_editor/settings", TTR("Settings...")), MENU_VIEW_CAMERA_SETTINGS); p->set_item_checked(p->get_item_index(MENU_VIEW_ORIGIN), true); p->set_item_checked(p->get_item_index(MENU_VIEW_GRID), true); diff --git a/editor/plugins/spatial_editor_plugin.h b/editor/plugins/spatial_editor_plugin.h index 523573333b..728b67f6fa 100644 --- a/editor/plugins/spatial_editor_plugin.h +++ b/editor/plugins/spatial_editor_plugin.h @@ -37,9 +37,6 @@ #include "scene/3d/light.h" #include "scene/3d/visual_instance.h" #include "scene/gui/panel_container.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class Camera; class SpatialEditor; diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index a8fbadb773..89e419ede8 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -221,19 +221,19 @@ void TextEditor::_validate_script() { void TextEditor::_update_bookmark_list() { - bookmarks_menu->get_popup()->clear(); + bookmarks_menu->clear(); - bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); - bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL); - bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); - bookmarks_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); + bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_bookmark"), BOOKMARK_TOGGLE); + bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/remove_all_bookmarks"), BOOKMARK_REMOVE_ALL); + bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_next_bookmark"), BOOKMARK_GOTO_NEXT); + bookmarks_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_previous_bookmark"), BOOKMARK_GOTO_PREV); Array bookmark_list = code_editor->get_text_edit()->get_bookmarks_array(); if (bookmark_list.size() == 0) { return; } - bookmarks_menu->get_popup()->add_separator(); + bookmarks_menu->add_separator(); for (int i = 0; i < bookmark_list.size(); i++) { String line = code_editor->get_text_edit()->get_line(bookmark_list[i]).strip_edges(); @@ -242,17 +242,17 @@ void TextEditor::_update_bookmark_list() { line = line.substr(0, 50); } - bookmarks_menu->get_popup()->add_item(String::num((int)bookmark_list[i] + 1) + " - \"" + line + "\""); - bookmarks_menu->get_popup()->set_item_metadata(bookmarks_menu->get_popup()->get_item_count() - 1, bookmark_list[i]); + bookmarks_menu->add_item(String::num((int)bookmark_list[i] + 1) + " - \"" + line + "\""); + bookmarks_menu->set_item_metadata(bookmarks_menu->get_item_count() - 1, bookmark_list[i]); } } void TextEditor::_bookmark_item_pressed(int p_idx) { if (p_idx < 4) { // Any item before the separator. - _edit_option(bookmarks_menu->get_popup()->get_item_id(p_idx)); + _edit_option(bookmarks_menu->get_item_id(p_idx)); } else { - code_editor->goto_line(bookmarks_menu->get_popup()->get_item_metadata(p_idx)); + code_editor->goto_line(bookmarks_menu->get_item_metadata(p_idx)); } } @@ -482,6 +482,14 @@ void TextEditor::_edit_option(int p_op) { code_editor->get_find_replace_bar()->popup_replace(); } break; + case SEARCH_IN_FILES: { + + String selected_text = code_editor->get_text_edit()->get_selection_text(); + + // Yep, because it doesn't make sense to instance this dialog for every single script open... + // So this will be delegated to the ScriptEditor. + emit_signal("search_in_files_requested", selected_text); + } break; case SEARCH_GOTO_LINE: { goto_line_dialog->popup_find_line(tx); @@ -558,7 +566,7 @@ void TextEditor::_text_edit_gui_input(const Ref<InputEvent> &ev) { int to_column = tx->get_selection_to_column(); if (row < from_line || row > to_line || (row == from_line && col < from_column) || (row == to_line && col > to_column)) { - // Right click is outside the selected text + // Right click is outside the selected text. tx->deselect(); } } @@ -637,17 +645,14 @@ TextEditor::TextEditor() { search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); search_menu->get_popup()->add_separator(); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); - - goto_line_dialog = memnew(GotoLineDialog); - add_child(goto_line_dialog); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES); edit_menu = memnew(MenuButton); + edit_hb->add_child(edit_menu); edit_menu->set_text(TTR("Edit")); edit_menu->set_switch_on_hover(true); edit_menu->get_popup()->connect("id_pressed", this, "_edit_option"); - edit_hb->add_child(edit_menu); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/undo"), EDIT_UNDO); edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/redo"), EDIT_REDO); edit_menu->get_popup()->add_separator(); @@ -689,13 +694,25 @@ TextEditor::TextEditor() { highlighter_menu->add_radio_check_item(TTR("Standard")); highlighter_menu->connect("id_pressed", this, "_change_syntax_highlighter"); - bookmarks_menu = memnew(MenuButton); - edit_hb->add_child(bookmarks_menu); - bookmarks_menu->set_text(TTR("Bookmarks")); - bookmarks_menu->set_switch_on_hover(true); + MenuButton *goto_menu = memnew(MenuButton); + edit_hb->add_child(goto_menu); + goto_menu->set_text(TTR("Go To")); + goto_menu->set_switch_on_hover(true); + goto_menu->get_popup()->connect("id_pressed", this, "_edit_option"); + + goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); + goto_menu->get_popup()->add_separator(); + + bookmarks_menu = memnew(PopupMenu); + bookmarks_menu->set_name(TTR("Bookmarks")); + goto_menu->get_popup()->add_child(bookmarks_menu); + goto_menu->get_popup()->add_submenu_item(TTR("Bookmarks"), "Bookmarks"); _update_bookmark_list(); bookmarks_menu->connect("about_to_show", this, "_update_bookmark_list"); - bookmarks_menu->get_popup()->connect("index_pressed", this, "_bookmark_item_pressed"); + bookmarks_menu->connect("index_pressed", this, "_bookmark_item_pressed"); + + goto_line_dialog = memnew(GotoLineDialog); + add_child(goto_line_dialog); code_editor->get_text_edit()->set_drag_forwarding(this); } diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index c0d4052646..c8b49a61e0 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -46,7 +46,7 @@ private: MenuButton *edit_menu; PopupMenu *highlighter_menu; MenuButton *search_menu; - MenuButton *bookmarks_menu; + PopupMenu *bookmarks_menu; PopupMenu *context_menu; GotoLineDialog *goto_line_dialog; @@ -87,6 +87,7 @@ private: SEARCH_FIND_NEXT, SEARCH_FIND_PREV, SEARCH_REPLACE, + SEARCH_IN_FILES, SEARCH_GOTO_LINE, BOOKMARK_TOGGLE, BOOKMARK_GOTO_NEXT, diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp index 5b67d259ba..3055a9382c 100644 --- a/editor/plugins/theme_editor_plugin.cpp +++ b/editor/plugins/theme_editor_plugin.cpp @@ -36,6 +36,7 @@ void ThemeEditor::edit(const Ref<Theme> &p_theme) { theme = p_theme; + main_panel->set_theme(p_theme); main_container->set_theme(p_theme); } @@ -53,6 +54,7 @@ void ThemeEditor::_propagate_redraw(Control *p_at) { void ThemeEditor::_refresh_interval() { + _propagate_redraw(main_panel); _propagate_redraw(main_container); } @@ -130,14 +132,14 @@ void ThemeEditor::_save_template_cbk(String fname) { Map<String, _TECategory> categories; - //fill types + // Fill types. List<StringName> type_list; Theme::get_default()->get_type_list(&type_list); for (List<StringName>::Element *E = type_list.front(); E; E = E->next()) { categories.insert(E->get(), _TECategory()); } - //fill default theme + // Fill default theme. for (Map<String, _TECategory>::Element *E = categories.front(); E; E = E->next()) { _TECategory &tc = E->get(); @@ -189,11 +191,9 @@ void ThemeEditor::_save_template_cbk(String fname) { } FileAccess *file = FileAccess::open(filename, FileAccess::WRITE); - if (!file) { - ERR_EXPLAIN(TTR("Can't save theme to file:") + " " + filename); - return; - } + ERR_FAIL_COND_MSG(!file, "Can't save theme to file: " + filename + "."); + file->store_line("; ******************* "); file->store_line("; Template Theme File "); file->store_line("; ******************* "); @@ -256,7 +256,7 @@ void ThemeEditor::_save_template_cbk(String fname) { file->store_line(""); file->store_line(""); - //write default theme + // Write default theme. for (Map<String, _TECategory>::Element *E = categories.front(); E; E = E->next()) { _TECategory &tc = E->get(); @@ -501,7 +501,7 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { type_select_label->show(); type_select->show(); - if (p_option == POPUP_ADD) { //add + if (p_option == POPUP_ADD) { // Add. add_del_dialog->set_title(TTR("Add Item")); add_del_dialog->get_ok()->set_text(TTR("Add")); @@ -509,7 +509,7 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { base_theme = Theme::get_default(); - } else if (p_option == POPUP_CLASS_ADD) { //add + } else if (p_option == POPUP_CLASS_ADD) { // Add. add_del_dialog->set_title(TTR("Add All Items")); add_del_dialog->get_ok()->set_text(TTR("Add All")); @@ -552,12 +552,10 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { type_menu->get_popup()->clear(); - if (p_option == 0 || p_option == 1) { //add + if (p_option == 0 || p_option == 1) { // Add. List<StringName> new_types; theme->get_type_list(&new_types); - - //uh kind of sucks for (List<StringName>::Element *F = new_types.front(); F; F = F->next()) { bool found = false; @@ -583,15 +581,17 @@ void ThemeEditor::_theme_menu_cbk(int p_option) { void ThemeEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_PROCESS) { - - time_left -= get_process_delta_time(); - if (time_left < 0) { - time_left = 1.5; - _refresh_interval(); - } - } else if (p_what == NOTIFICATION_THEME_CHANGED) { - theme_menu->set_icon(get_icon("Theme", "EditorIcons")); + switch (p_what) { + case NOTIFICATION_PROCESS: { + time_left -= get_process_delta_time(); + if (time_left < 0) { + time_left = 1.5; + _refresh_interval(); + } + } break; + case NOTIFICATION_THEME_CHANGED: { + theme_menu->set_icon(get_icon("Theme", "EditorIcons")); + } break; } } @@ -629,35 +629,34 @@ ThemeEditor::ThemeEditor() { top_menu->add_child(theme_menu); theme_menu->get_popup()->connect("id_pressed", this, "_theme_menu_cbk"); - scroll = memnew(ScrollContainer); + ScrollContainer *scroll = memnew(ScrollContainer); add_child(scroll); - scroll->set_theme(Theme::get_default()); scroll->set_enable_v_scroll(true); scroll->set_enable_h_scroll(false); scroll->set_v_size_flags(SIZE_EXPAND_FILL); - main_container = memnew(MarginContainer); - scroll->add_child(main_container); - main_container->set_theme(Theme::get_default()); - main_container->set_clip_contents(true); - main_container->set_custom_minimum_size(Size2(700, 0) * EDSCALE); - main_container->set_v_size_flags(SIZE_EXPAND_FILL); - main_container->set_h_size_flags(SIZE_EXPAND_FILL); + MarginContainer *root_container = memnew(MarginContainer); + scroll->add_child(root_container); + root_container->set_theme(Theme::get_default()); + root_container->set_clip_contents(true); + root_container->set_custom_minimum_size(Size2(700, 0) * EDSCALE); + root_container->set_v_size_flags(SIZE_EXPAND_FILL); + root_container->set_h_size_flags(SIZE_EXPAND_FILL); //// Preview Controls //// - Panel *panel = memnew(Panel); - main_container->add_child(panel); + main_panel = memnew(Panel); + root_container->add_child(main_panel); - MarginContainer *mc = memnew(MarginContainer); - main_container->add_child(mc); - mc->add_constant_override("margin_right", 4 * EDSCALE); - mc->add_constant_override("margin_top", 4 * EDSCALE); - mc->add_constant_override("margin_left", 4 * EDSCALE); - mc->add_constant_override("margin_bottom", 4 * EDSCALE); + main_container = memnew(MarginContainer); + root_container->add_child(main_container); + main_container->add_constant_override("margin_right", 4 * EDSCALE); + main_container->add_constant_override("margin_top", 4 * EDSCALE); + main_container->add_constant_override("margin_left", 4 * EDSCALE); + main_container->add_constant_override("margin_bottom", 4 * EDSCALE); HBoxContainer *main_hb = memnew(HBoxContainer); - mc->add_child(main_hb); + main_container->add_child(main_hb); VBoxContainer *first_vb = memnew(VBoxContainer); main_hb->add_child(first_vb); @@ -695,19 +694,19 @@ ThemeEditor::ThemeEditor() { test_menu_button->get_popup()->add_separator(); test_menu_button->get_popup()->add_check_item(TTR("Check Item")); test_menu_button->get_popup()->add_check_item(TTR("Checked Item")); - test_menu_button->get_popup()->set_item_checked(3, true); + test_menu_button->get_popup()->set_item_checked(4, true); test_menu_button->get_popup()->add_separator(); test_menu_button->get_popup()->add_radio_check_item(TTR("Radio Item")); test_menu_button->get_popup()->add_radio_check_item(TTR("Checked Radio Item")); - test_menu_button->get_popup()->set_item_checked(6, true); + test_menu_button->get_popup()->set_item_checked(7, true); test_menu_button->get_popup()->add_separator(TTR("Named Sep.")); PopupMenu *test_submenu = memnew(PopupMenu); test_menu_button->get_popup()->add_child(test_submenu); test_submenu->set_name("submenu"); test_menu_button->get_popup()->add_submenu_item(TTR("Submenu"), "submenu"); - test_submenu->add_item(TTR("Item 1")); - test_submenu->add_item(TTR("Item 2")); + test_submenu->add_item(TTR("Subitem 1")); + test_submenu->add_item(TTR("Subitem 2")); first_vb->add_child(test_menu_button); OptionButton *test_option_button = memnew(OptionButton); diff --git a/editor/plugins/theme_editor_plugin.h b/editor/plugins/theme_editor_plugin.h index cc236907a9..6ffee46569 100644 --- a/editor/plugins/theme_editor_plugin.h +++ b/editor/plugins/theme_editor_plugin.h @@ -45,7 +45,7 @@ class ThemeEditor : public VBoxContainer { GDCLASS(ThemeEditor, VBoxContainer); - ScrollContainer *scroll; + Panel *main_panel; MarginContainer *main_container; Ref<Theme> theme; diff --git a/editor/plugins/tile_map_editor_plugin.cpp b/editor/plugins/tile_map_editor_plugin.cpp index b2f06ca41f..b4cce9745e 100644 --- a/editor/plugins/tile_map_editor_plugin.cpp +++ b/editor/plugins/tile_map_editor_plugin.cpp @@ -2006,7 +2006,7 @@ TileMapEditor::TileMapEditor(EditorNode *p_editor) { // Tools paint_button = memnew(ToolButton); paint_button->set_shortcut(ED_SHORTCUT("tile_map_editor/paint_tile", TTR("Paint Tile"), KEY_P)); - paint_button->set_tooltip(TTR("Shift+RMB: Line Draw\nShift+Ctrl+RMB: Rectangle Paint")); + paint_button->set_tooltip(TTR("Shift+LMB: Line Draw\nShift+Ctrl+LMB: Rectangle Paint")); paint_button->connect("pressed", this, "_button_tool_select", make_binds(TOOL_NONE)); paint_button->set_toggle_mode(true); toolbar->add_child(paint_button); diff --git a/editor/plugins/tile_map_editor_plugin.h b/editor/plugins/tile_map_editor_plugin.h index 3331fb971f..c841eb1f98 100644 --- a/editor/plugins/tile_map_editor_plugin.h +++ b/editor/plugins/tile_map_editor_plugin.h @@ -41,10 +41,6 @@ #include "scene/gui/menu_button.h" #include "scene/gui/tool_button.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class TileMapEditor : public VBoxContainer { GDCLASS(TileMapEditor, VBoxContainer); diff --git a/editor/plugins/tile_set_editor_plugin.cpp b/editor/plugins/tile_set_editor_plugin.cpp index 1a27e749e2..c1e85788f8 100644 --- a/editor/plugins/tile_set_editor_plugin.cpp +++ b/editor/plugins/tile_set_editor_plugin.cpp @@ -646,8 +646,7 @@ void TileSetEditor::_on_textures_added(const PoolStringArray &p_paths) { for (int i = 0; i < p_paths.size(); i++) { Ref<Texture> t = Ref<Texture>(ResourceLoader::load(p_paths[i])); - ERR_EXPLAIN("'" + p_paths[i] + "' is not a valid texture."); - ERR_CONTINUE(!t.is_valid()); + ERR_CONTINUE_MSG(!t.is_valid(), "'" + p_paths[i] + "' is not a valid texture."); if (texture_map.has(t->get_rid())) { invalid_count++; diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index 863cf75a93..589964f620 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -69,8 +69,16 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { } } visual_shader = Ref<VisualShader>(p_visual_shader); + if (!visual_shader->is_connected("changed", this, "_update_preview")) { + visual_shader->connect("changed", this, "_update_preview"); + } visual_shader->set_graph_offset(graph->get_scroll_ofs() / EDSCALE); } else { + if (visual_shader.is_valid()) { + if (visual_shader->is_connected("changed", this, "")) { + visual_shader->disconnect("changed", this, "_update_preview"); + } + } visual_shader.unref(); } @@ -79,7 +87,9 @@ void VisualShaderEditor::edit(VisualShader *p_visual_shader) { } else { if (changed) { // to avoid tree collapse _clear_buffer(); + _update_custom_nodes(); _update_options_menu(); + _update_preview(); } _update_graph(); } @@ -95,31 +105,36 @@ void VisualShaderEditor::remove_plugin(const Ref<VisualShaderNodePlugin> &p_plug plugins.erase(p_plugin); } -void VisualShaderEditor::add_custom_type(const String &p_name, const String &p_category, const Ref<Script> &p_script) { - +void VisualShaderEditor::clear_custom_types() { for (int i = 0; i < add_options.size(); i++) { - ERR_FAIL_COND(add_options[i].script == p_script); + if (add_options[i].is_custom) { + add_options.remove(i); + } } - - AddOption ao; - ao.name = p_name; - ao.script = p_script; - ao.category = p_category; - add_options.push_back(ao); - - _update_options_menu(); } -void VisualShaderEditor::remove_custom_type(const Ref<Script> &p_script) { +void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_sub_category) { + + ERR_FAIL_COND(!p_name.is_valid_identifier()); + ERR_FAIL_COND(!p_script.is_valid()); for (int i = 0; i < add_options.size(); i++) { - if (add_options[i].script == p_script) { - add_options.remove(i); - return; + if (add_options[i].is_custom) { + if (add_options[i].script == p_script) + return; } } - _update_options_menu(); + AddOption ao; + ao.name = p_name; + ao.script = p_script; + ao.return_type = p_return_icon_type; + ao.description = p_description; + ao.category = p_category; + ao.sub_category = p_sub_category; + ao.is_custom = true; + + add_options.push_back(ao); } bool VisualShaderEditor::_is_available(int p_mode) { @@ -162,6 +177,58 @@ bool VisualShaderEditor::_is_available(int p_mode) { return (p_mode == -1 || (p_mode & current_mode) != 0); } +void VisualShaderEditor::_update_custom_nodes() { + clear_custom_types(); + List<StringName> class_list; + ScriptServer::get_global_class_list(&class_list); + for (int i = 0; i < class_list.size(); i++) { + if (ScriptServer::get_global_class_native_base(class_list[i]) == "VisualShaderNodeCustom") { + + String script_path = ScriptServer::get_global_class_path(class_list[i]); + Ref<Resource> res = ResourceLoader::load(script_path); + ERR_FAIL_COND(res.is_null()); + ERR_FAIL_COND(!res->is_class("Script")); + Ref<Script> script = Ref<Script>(res); + + Ref<VisualShaderNodeCustom> ref; + ref.instance(); + ref->set_script(script.get_ref_ptr()); + + String name; + if (ref->has_method("_get_name")) { + name = (String)ref->call("_get_name"); + } else { + name = "Unnamed"; + } + + String description = ""; + if (ref->has_method("_get_description")) { + description = (String)ref->call("_get_description"); + } + + int return_icon_type = -1; + if (ref->has_method("_get_return_icon_type")) { + return_icon_type = (int)ref->call("_get_return_icon_type"); + } + + String category = ""; + if (ref->has_method("_get_category")) { + category = (String)ref->call("_get_category"); + } + if (category == "") { + category = "Custom"; + } + + String sub_category = ""; + if (ref->has_method("_get_subcategory")) { + sub_category = (String)ref->call("_get_subcategory"); + } + + add_custom_type(name, script, description, return_icon_type, category, sub_category); + } + } +} + void VisualShaderEditor::_update_options_menu() { node_desc->set_text(""); @@ -284,7 +351,7 @@ void VisualShaderEditor::_update_options_menu() { case VisualShaderNode::PORT_TYPE_TRANSFORM: item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Transform", "EditorIcons")); break; - case VisualShaderNode::PORT_TYPE_COLOR: + case VisualShaderNode::PORT_TYPE_ICON_COLOR: item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_icon("Color", "EditorIcons")); break; default: @@ -466,21 +533,23 @@ void VisualShaderEditor::_update_graph() { offset->set_custom_minimum_size(Size2(0, 6 * EDSCALE)); node->add_child(offset); - HBoxContainer *hb2 = memnew(HBoxContainer); + if (group_node->is_editable()) { + HBoxContainer *hb2 = memnew(HBoxContainer); - Button *add_input_btn = memnew(Button); - add_input_btn->set_text(TTR("Add input +")); - add_input_btn->connect("pressed", this, "_add_input_port", varray(nodes[n_i], group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "input" + itos(group_node->get_free_input_port_id())), CONNECT_DEFERRED); - hb2->add_child(add_input_btn); + Button *add_input_btn = memnew(Button); + add_input_btn->set_text(TTR("Add input +")); + add_input_btn->connect("pressed", this, "_add_input_port", varray(nodes[n_i], group_node->get_free_input_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "input" + itos(group_node->get_free_input_port_id())), CONNECT_DEFERRED); + hb2->add_child(add_input_btn); - hb2->add_spacer(); + hb2->add_spacer(); - Button *add_output_btn = memnew(Button); - add_output_btn->set_text(TTR("Add output +")); - add_output_btn->connect("pressed", this, "_add_output_port", varray(nodes[n_i], group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "output" + itos(group_node->get_free_output_port_id())), CONNECT_DEFERRED); - hb2->add_child(add_output_btn); + Button *add_output_btn = memnew(Button); + add_output_btn->set_text(TTR("Add output +")); + add_output_btn->connect("pressed", this, "_add_output_port", varray(nodes[n_i], group_node->get_free_output_port_id(), VisualShaderNode::PORT_TYPE_VECTOR, "output" + itos(group_node->get_free_output_port_id())), CONNECT_DEFERRED); + hb2->add_child(add_output_btn); - node->add_child(hb2); + node->add_child(hb2); + } } for (int i = 0; i < MAX(vsnode->get_input_port_count(), vsnode->get_output_port_count()); i++) { @@ -942,8 +1011,10 @@ void VisualShaderEditor::_expression_focus_out(Object *text_edit, int p_node) { } void VisualShaderEditor::_rebuild() { - EditorNode::get_singleton()->get_log()->clear(); - visual_shader->rebuild(); + if (visual_shader != NULL) { + EditorNode::get_singleton()->get_log()->clear(); + visual_shader->rebuild(); + } } void VisualShaderEditor::_set_node_size(int p_type, int p_node, const Vector2 &p_size) { @@ -1139,7 +1210,9 @@ void VisualShaderEditor::_add_node(int p_idx, int p_op_idx) { Ref<VisualShaderNode> vsnode; - if (add_options[p_idx].type != String()) { + bool is_custom = add_options[p_idx].is_custom; + + if (!is_custom && add_options[p_idx].type != String()) { VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instance(add_options[p_idx].type)); ERR_FAIL_COND(!vsn); @@ -1504,6 +1577,29 @@ void VisualShaderEditor::_notification(int p_what) { node_filter->set_right_icon(Control::get_icon("Search", "EditorIcons")); + preview_shader->set_icon(Control::get_icon("Shader", "EditorIcons")); + + { + Color background_color = EDITOR_GET("text_editor/highlighting/background_color"); + Color text_color = EDITOR_GET("text_editor/highlighting/text_color"); + Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); + Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); + Color symbol_color = EDITOR_GET("text_editor/highlighting/symbol_color"); + + preview_text->add_color_override("background_color", background_color); + + for (List<String>::Element *E = keyword_list.front(); E; E = E->next()) { + + preview_text->add_keyword_color(E->get(), keyword_color); + } + + preview_text->add_font_override("font", get_font("expression", "EditorFonts")); + preview_text->add_color_override("font_color", text_color); + preview_text->add_color_override("symbol_color", symbol_color); + preview_text->add_color_region("/*", "*/", comment_color, false); + preview_text->add_color_region("//", "", comment_color, false); + } + tools->set_icon(EditorNode::get_singleton()->get_gui_base()->get_icon("Tools", "EditorIcons")); if (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree()) @@ -1954,6 +2050,15 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da } } +void VisualShaderEditor::_show_preview_text() { + preview_showed = !preview_showed; + preview_text->set_visible(preview_showed); +} + +void VisualShaderEditor::_update_preview() { + preview_text->set_text(visual_shader->get_code()); +} + void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_rebuild", &VisualShaderEditor::_rebuild); ClassDB::bind_method("_update_graph", &VisualShaderEditor::_update_graph); @@ -1993,6 +2098,8 @@ void VisualShaderEditor::_bind_methods() { ClassDB::bind_method("_node_resized", &VisualShaderEditor::_node_resized); ClassDB::bind_method("_set_node_size", &VisualShaderEditor::_set_node_size); ClassDB::bind_method("_clear_buffer", &VisualShaderEditor::_clear_buffer); + ClassDB::bind_method("_show_preview_text", &VisualShaderEditor::_show_preview_text); + ClassDB::bind_method("_update_preview", &VisualShaderEditor::_update_preview); ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw); ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw); @@ -2019,13 +2126,23 @@ VisualShaderEditor::VisualShaderEditor() { saved_node_pos = Point2(0, 0); ShaderLanguage::get_keyword_list(&keyword_list); + preview_showed = false; + to_node = -1; to_slot = -1; from_node = -1; from_slot = -1; + main_box = memnew(HSplitContainer); + main_box->set_v_size_flags(SIZE_EXPAND_FILL); + main_box->set_h_size_flags(SIZE_EXPAND_FILL); + add_child(main_box); + graph = memnew(GraphEdit); - add_child(graph); + graph->get_zoom_hbox()->set_h_size_flags(SIZE_EXPAND_FILL); + graph->set_v_size_flags(SIZE_EXPAND_FILL); + graph->set_h_size_flags(SIZE_EXPAND_FILL); + main_box->add_child(graph); graph->set_drag_forwarding(this); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_SCALAR); graph->add_valid_right_disconnect_type(VisualShaderNode::PORT_TYPE_BOOLEAN); @@ -2074,6 +2191,25 @@ VisualShaderEditor::VisualShaderEditor() { graph->get_zoom_hbox()->move_child(add_node, 0); add_node->connect("pressed", this, "_show_members_dialog", varray(false)); + preview_shader = memnew(ToolButton); + preview_shader->set_toggle_mode(true); + preview_shader->set_tooltip(TTR("Show resulted shader code.")); + graph->get_zoom_hbox()->add_child(preview_shader); + preview_shader->connect("pressed", this, "_show_preview_text"); + + /////////////////////////////////////// + // PREVIEW PANEL + /////////////////////////////////////// + + preview_text = memnew(TextEdit); + main_box->add_child(preview_text); + preview_text->set_h_size_flags(SIZE_EXPAND_FILL); + preview_text->set_v_size_flags(SIZE_EXPAND_FILL); + preview_text->set_visible(preview_showed); + preview_text->set_custom_minimum_size(Size2(400 * EDSCALE, 0)); + preview_text->set_syntax_coloring(true); + preview_text->set_readonly(true); + /////////////////////////////////////// // SHADER NODES TREE /////////////////////////////////////// @@ -2164,8 +2300,8 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Screen", "Color", "Operators", "VisualShaderNodeColorOp", TTR("Screen operator."), VisualShaderNodeColorOp::OP_SCREEN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("SoftLight", "Color", "Operators", "VisualShaderNodeColorOp", TTR("SoftLight operator."), VisualShaderNodeColorOp::OP_SOFT_LIGHT, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("ColorConstant", "Color", "Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), -1, VisualShaderNode::PORT_TYPE_COLOR)); - add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), -1, VisualShaderNode::PORT_TYPE_COLOR)); + add_options.push_back(AddOption("ColorConstant", "Color", "Variables", "VisualShaderNodeColorConstant", TTR("Color constant."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR)); + add_options.push_back(AddOption("ColorUniform", "Color", "Variables", "VisualShaderNodeColorUniform", TTR("Color uniform."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR)); // CONDITIONAL @@ -2351,8 +2487,8 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Sin", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("SinH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeScalarFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Sqrt", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeScalarFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); - add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), VisualShaderNodeScalarOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("SmoothStep", "Scalar", "Functions", "VisualShaderNodeScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if x is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("Step", "Scalar", "Functions", "VisualShaderNodeScalarOp", TTR("Step function( scalar(edge), scalar(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeScalarOp::OP_STEP, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Tan", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("TanH", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeScalarFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_SCALAR)); add_options.push_back(AddOption("Trunc", "Scalar", "Functions", "VisualShaderNodeScalarFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeScalarFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_SCALAR)); @@ -2368,12 +2504,12 @@ VisualShaderEditor::VisualShaderEditor() { // TEXTURES - add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubeMap", TTR("Perform the cubic texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR)); - add_options.push_back(AddOption("Texture", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the texture lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR)); + add_options.push_back(AddOption("CubeMap", "Textures", "Functions", "VisualShaderNodeCubeMap", TTR("Perform the cubic texture lookup."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR)); + add_options.push_back(AddOption("Texture", "Textures", "Functions", "VisualShaderNodeTexture", TTR("Perform the texture lookup."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR)); - add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubeMapUniform", TTR("Cubic texture uniform lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR)); - add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, VisualShaderNode::PORT_TYPE_COLOR)); - add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, VisualShaderNode::PORT_TYPE_COLOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); + add_options.push_back(AddOption("CubeMapUniform", "Textures", "Variables", "VisualShaderNodeCubeMapUniform", TTR("Cubic texture uniform lookup."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR)); + add_options.push_back(AddOption("TextureUniform", "Textures", "Variables", "VisualShaderNodeTextureUniform", TTR("2D texture uniform lookup."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR)); + add_options.push_back(AddOption("TextureUniformTriplanar", "Textures", "Variables", "VisualShaderNodeTextureUniformTriplanar", TTR("2D texture uniform lookup with triplanar."), -1, VisualShaderNode::PORT_TYPE_ICON_COLOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, Shader::MODE_SPATIAL)); // TRANSFORM @@ -2445,10 +2581,10 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Sin", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SIN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("SinH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic sine of the parameter."), VisualShaderNodeVectorFunc::FUNC_SINH, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Sqrt", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the square root of the parameter."), VisualShaderNodeVectorFunc::FUNC_SQRT, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeVectorSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeVectorScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), VisualShaderNodeVectorOp::OP_STEP, VisualShaderNode::PORT_TYPE_VECTOR)); - add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeVectorScalarStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller then 'edge' and otherwise 1.0."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("SmoothStep", "Vector", "Functions", "VisualShaderNodeVectorSmoothStep", TTR("SmoothStep function( vector(edge0), vector(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("SmoothStepS", "Vector", "Functions", "VisualShaderNodeVectorScalarSmoothStep", TTR("SmoothStep function( scalar(edge0), scalar(edge1), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge0' and 1.0 if 'x' is larger than 'edge1'. Otherwise the return value is interpolated between 0.0 and 1.0 using Hermite polynomials."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("Step", "Vector", "Functions", "VisualShaderNodeVectorOp", TTR("Step function( vector(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), VisualShaderNodeVectorOp::OP_STEP, VisualShaderNode::PORT_TYPE_VECTOR)); + add_options.push_back(AddOption("StepS", "Vector", "Functions", "VisualShaderNodeVectorScalarStep", TTR("Step function( scalar(edge), vector(x) ).\n\nReturns 0.0 if 'x' is smaller than 'edge' and otherwise 1.0."), -1, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Tan", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TAN, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("TanH", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Returns the hyperbolic tangent of the parameter."), VisualShaderNodeVectorFunc::FUNC_TANH, VisualShaderNode::PORT_TYPE_VECTOR)); add_options.push_back(AddOption("Trunc", "Vector", "Functions", "VisualShaderNodeVectorFunc", TTR("Finds the truncated value of the parameter."), VisualShaderNodeVectorFunc::FUNC_TRUNC, VisualShaderNode::PORT_TYPE_VECTOR)); @@ -2466,6 +2602,7 @@ VisualShaderEditor::VisualShaderEditor() { add_options.push_back(AddOption("Expression", "Special", "", "VisualShaderNodeExpression", TTR("Custom Godot Shader Language expression, with custom amount of input and output ports. This is a direct injection of code into the vertex/fragment/light function, do not use it to write the function declarations inside."))); add_options.push_back(AddOption("Fresnel", "Special", "", "VisualShaderNodeFresnel", TTR("Returns falloff based on the dot product of surface normal and view direction of camera (pass associated inputs to it)."), -1, VisualShaderNode::PORT_TYPE_SCALAR)); + add_options.push_back(AddOption("GlobalExpression", "Special", "", "VisualShaderNodeGlobalExpression", TTR("Custom Godot Shader Language expression, which placed on top of the resulted shader. You can place various function definitions inside and call it later in the Expressions. You can also declare varyings, uniforms and constants."))); add_options.push_back(AddOption("ScalarDerivativeFunc", "Special", "Common", "VisualShaderNodeScalarDerivativeFunc", TTR("(Fragment/Light mode only) Scalar derivative function."), -1, VisualShaderNode::PORT_TYPE_SCALAR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); add_options.push_back(AddOption("VectorDerivativeFunc", "Special", "Common", "VisualShaderNodeVectorDerivativeFunc", TTR("(Fragment/Light mode only) Vector derivative function."), -1, VisualShaderNode::PORT_TYPE_VECTOR, VisualShader::TYPE_FRAGMENT | VisualShader::TYPE_LIGHT, -1, -1, true)); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index d2b1e8bc45..1556c7cd43 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -60,14 +60,18 @@ class VisualShaderEditor : public VBoxContainer { int editing_port; Ref<VisualShader> visual_shader; + HSplitContainer *main_box; GraphEdit *graph; ToolButton *add_node; + ToolButton *preview_shader; OptionButton *edit_type; PanelContainer *error_panel; Label *error_label; + TextEdit *preview_text; + UndoRedo *undo_redo; Point2 saved_node_pos; bool saved_node_pos_dirty; @@ -75,6 +79,8 @@ class VisualShaderEditor : public VBoxContainer { ConfirmationDialog *members_dialog; MenuButton *tools; + bool preview_showed; + enum ToolsMenuOptions { EXPAND_ALL, COLLAPSE_ALL @@ -104,6 +110,7 @@ class VisualShaderEditor : public VBoxContainer { int func; float value; bool highend; + bool is_custom; AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_sub_category = String(), const String &p_type = String(), const String &p_description = String(), int p_sub_func = -1, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1, bool p_highend = false) { name = p_name; @@ -117,6 +124,7 @@ class VisualShaderEditor : public VBoxContainer { func = p_func; value = p_value; highend = p_highend; + is_custom = false; } AddOption(const String &p_name, const String &p_category, const String &p_sub_category, const String &p_type, const String &p_description, const String &p_sub_func, int p_return_type = -1, int p_mode = -1, int p_func = -1, float p_value = -1, bool p_highend = false) { @@ -131,6 +139,7 @@ class VisualShaderEditor : public VBoxContainer { func = p_func; value = p_value; highend = p_highend; + is_custom = false; } }; @@ -140,8 +149,12 @@ class VisualShaderEditor : public VBoxContainer { void _draw_color_over_button(Object *obj, Color p_color); void _add_node(int p_idx, int p_op_idx = -1); + void _update_custom_nodes(); void _update_options_menu(); + void _show_preview_text(); + void _update_preview(); + static VisualShaderEditor *singleton; void _node_dragged(const Vector2 &p_from, const Vector2 &p_to, int p_node); @@ -240,8 +253,8 @@ public: static VisualShaderEditor *get_singleton() { return singleton; } - void add_custom_type(const String &p_name, const String &p_category, const Ref<Script> &p_script); - void remove_custom_type(const Ref<Script> &p_script); + void clear_custom_types(); + void add_custom_type(const String &p_name, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, const String &p_sub_category); virtual Size2 get_minimum_size() const; void edit(VisualShader *p_visual_shader); diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp index feb2cdd071..2b62482550 100644 --- a/editor/project_manager.cpp +++ b/editor/project_manager.cpp @@ -1109,7 +1109,7 @@ void ProjectList::load_project_icon(int p_index) { Error err = img->load(item.icon.replace_first("res://", item.path + "/")); if (err == OK) { - img->resize(default_icon->get_width(), default_icon->get_height()); + img->resize(default_icon->get_width(), default_icon->get_height(), Image::INTERPOLATE_LANCZOS); Ref<ImageTexture> it = memnew(ImageTexture); it->create_from_image(img); icon = it; @@ -1312,7 +1312,7 @@ void ProjectList::set_filter_option(ProjectListFilter::FilterOption p_option) { void ProjectList::set_order_option(ProjectListFilter::FilterOption p_option) { if (_order_option != p_option) { _order_option = p_option; - EditorSettings::get_singleton()->set("project_manager/sorting_order", (int)_filter_option); + EditorSettings::get_singleton()->set("project_manager/sorting_order", (int)_order_option); EditorSettings::get_singleton()->save(); } } @@ -2075,10 +2075,12 @@ void ProjectManager::_rename_project() { void ProjectManager::_erase_project_confirm() { _project_list->erase_selected_projects(); + _update_project_buttons(); } void ProjectManager::_erase_missing_projects_confirm() { _project_list->erase_missing_projects(); + _update_project_buttons(); } void ProjectManager::_erase_project() { @@ -2268,6 +2270,9 @@ ProjectManager::ProjectManager() { } break; } + // Define a minimum window size to prevent UI elements from overlapping or being cut off + OS::get_singleton()->set_min_window_size(Size2(750, 420) * EDSCALE); + #ifndef OSX_ENABLED // The macOS platform implementation uses its own hiDPI window resizing code // TODO: Resize windows on hiDPI displays on Windows and Linux and remove the line below diff --git a/editor/property_editor.h b/editor/property_editor.h index a8ef1d6fc1..029c2211d5 100644 --- a/editor/property_editor.h +++ b/editor/property_editor.h @@ -46,10 +46,6 @@ #include "scene/gui/texture_rect.h" #include "scene/gui/tree.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class PropertyValueEvaluator; class CreateDialog; class PropertySelector; diff --git a/editor/pvrtc_compress.cpp b/editor/pvrtc_compress.cpp index 84cd6da3d9..7cdd900d25 100644 --- a/editor/pvrtc_compress.cpp +++ b/editor/pvrtc_compress.cpp @@ -32,6 +32,7 @@ #include "core/io/resource_loader.h" #include "core/io/resource_saver.h" +#include "core/os/dir_access.h" #include "core/os/file_access.h" #include "core/os/os.h" #include "editor_settings.h" @@ -52,57 +53,75 @@ static void _compress_image(Image::CompressMode p_mode, Image *p_image) { _base_image_compress_pvrtc2_func(p_image); else if (_base_image_compress_pvrtc4_func) _base_image_compress_pvrtc4_func(p_image); - break; case Image::COMPRESS_PVRTC4: if (_base_image_compress_pvrtc4_func) _base_image_compress_pvrtc4_func(p_image); - break; - default: ERR_FAIL(); + default: + ERR_FAIL_MSG("Unsupported Image compress mode used in PVRTC module."); } return; } - String tmppath = EditorSettings::get_singleton()->get_cache_dir(); - - List<String> args; + String tmppath = EditorSettings::get_singleton()->get_cache_dir(); String src_img = tmppath.plus_file("_tmp_src_img.png"); String dst_img = tmppath.plus_file("_tmp_dst_img.pvr"); + List<String> args; args.push_back("-i"); args.push_back(src_img); args.push_back("-o"); args.push_back(dst_img); args.push_back("-f"); - switch (p_mode) { - case Image::COMPRESS_PVRTC2: args.push_back("PVRTC2"); break; - case Image::COMPRESS_PVRTC4: args.push_back("PVRTC4"); break; - case Image::COMPRESS_ETC: args.push_back("ETC"); break; - default: ERR_FAIL(); + switch (p_mode) { + case Image::COMPRESS_PVRTC2: + args.push_back("PVRTC2"); + break; + case Image::COMPRESS_PVRTC4: + args.push_back("PVRTC4"); + break; + case Image::COMPRESS_ETC: + args.push_back("ETC"); + break; + default: + ERR_FAIL_MSG("Unsupported Image compress mode used in PVRTC module."); } if (EditorSettings::get_singleton()->get("filesystem/import/pvrtc_fast_conversion").operator bool()) { args.push_back("-pvrtcfast"); } - if (p_image->has_mipmaps()) + if (p_image->has_mipmaps()) { args.push_back("-m"); + } + // Save source PNG. Ref<ImageTexture> t = memnew(ImageTexture); t->create_from_image(Ref<Image>(p_image), 0); ResourceSaver::save(src_img, t); Error err = OS::get_singleton()->execute(ttpath, args, true); - ERR_EXPLAIN(TTR("Could not execute PVRTC tool:") + " " + ttpath); - ERR_FAIL_COND(err != OK); + if (err != OK) { + // Clean up generated files. + DirAccess::remove_file_or_error(src_img); + DirAccess::remove_file_or_error(dst_img); + ERR_FAIL_MSG("Could not execute PVRTC tool: " + ttpath); + } t = ResourceLoader::load(dst_img, "Texture"); - - ERR_EXPLAIN(TTR("Can't load back converted image using PVRTC tool:") + " " + dst_img); - ERR_FAIL_COND(t.is_null()); + if (t.is_null()) { + // Clean up generated files. + DirAccess::remove_file_or_error(src_img); + DirAccess::remove_file_or_error(dst_img); + ERR_FAIL_MSG("Can't load back converted image using PVRTC tool."); + } p_image->copy_internals_from(t->get_data()); + + // Clean up generated files. + DirAccess::remove_file_or_error(src_img); + DirAccess::remove_file_or_error(dst_img); } static void _compress_pvrtc2(Image *p_image) { diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp index aeee829de2..f1eb7adbd2 100644 --- a/editor/scene_tree_dock.cpp +++ b/editor/scene_tree_dock.cpp @@ -399,6 +399,9 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } Node *selected = scene_tree->get_selected(); + if (!selected && !editor_selection->get_selected_node_list().empty()) + selected = editor_selection->get_selected_node_list().front()->get(); + if (selected) create_dialog->popup_create(false, true, selected->get_class()); @@ -983,9 +986,10 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) { } else { new_node = Object::cast_to<Node>(ClassDB::instance(selected_favorite_root)); } + if (!new_node) { - ERR_EXPLAIN("Creating root from favorite '" + selected_favorite_root + "' failed. Creating 'Node' instead."); new_node = memnew(Node); + ERR_PRINTS("Creating root from favorite '" + selected_favorite_root + "' failed. Creating 'Node' instead."); } } else { switch (p_tool) { @@ -1534,10 +1538,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V Node *validate = new_parent; while (validate) { - if (p_nodes.find(validate) != -1) { - ERR_EXPLAIN("Selection changed at some point.. can't reparent"); - ERR_FAIL(); - } + ERR_FAIL_COND_MSG(p_nodes.find(validate) != -1, "Selection changed at some point.. can't reparent."); validate = validate->get_parent(); } //ok all valid @@ -1983,6 +1984,10 @@ void SceneTreeDock::_create() { } else if (current_option == TOOL_REPLACE) { List<Node *> selection = editor_selection->get_selected_node_list(); ERR_FAIL_COND(selection.size() <= 0); + + UndoRedo *ur = EditorNode::get_singleton()->get_undo_redo(); + ur->create_action(TTR("Change type of node(s)")); + for (List<Node *>::Element *E = selection.front(); E; E = E->next()) { Node *n = E->get(); ERR_FAIL_COND(!n); @@ -1993,8 +1998,13 @@ void SceneTreeDock::_create() { Node *newnode = Object::cast_to<Node>(c); ERR_FAIL_COND(!newnode); - replace_node(n, newnode); + ur->add_do_method(this, "replace_node", n, newnode, true, false); + ur->add_do_reference(newnode); + ur->add_undo_method(this, "replace_node", newnode, n, false, false); + ur->add_undo_reference(n); } + + ur->commit_action(); } else if (current_option == TOOL_REPARENT_TO_NEW_NODE) { List<Node *> selection = editor_selection->get_selected_node_list(); ERR_FAIL_COND(selection.size() <= 0); @@ -2241,8 +2251,7 @@ void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) { //drop at above selected node if (to_node == EditorNode::get_singleton()->get_edited_scene()) { to_node = NULL; - ERR_EXPLAIN("Cannot perform drop above the root node!"); - ERR_FAIL(); + ERR_FAIL_MSG("Cannot perform drop above the root node!"); } to_pos = to_node->get_index(); diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp index 2d9accc3d8..43f540e688 100644 --- a/editor/scene_tree_editor.cpp +++ b/editor/scene_tree_editor.cpp @@ -270,15 +270,30 @@ bool SceneTreeEditor::_add_nodes(Node *p_node, TreeItem *p_parent) { item->add_button(0, get_icon("NodeWarning", "EditorIcons"), BUTTON_WARNING, false, TTR("Node configuration warning:") + "\n" + p_node->get_configuration_warning()); } - bool has_connections = p_node->has_persistent_signal_connections(); - bool has_groups = p_node->has_persistent_groups(); - - if (has_connections && has_groups) { - item->add_button(0, get_icon("SignalsAndGroups", "EditorIcons"), BUTTON_SIGNALS, false, TTR("Node has connection(s) and group(s).\nClick to show signals dock.")); - } else if (has_connections) { - item->add_button(0, get_icon("Signals", "EditorIcons"), BUTTON_SIGNALS, false, TTR("Node has connections.\nClick to show signals dock.")); - } else if (has_groups) { - item->add_button(0, get_icon("Groups", "EditorIcons"), BUTTON_GROUPS, false, TTR("Node is in group(s).\nClick to show groups dock.")); + int num_connections = p_node->get_persistent_signal_connection_count(); + int num_groups = p_node->get_persistent_group_count(); + + if (num_connections >= 1 && num_groups >= 1) { + item->add_button( + 0, + get_icon("SignalsAndGroups", "EditorIcons"), + BUTTON_SIGNALS, + false, + vformat(TTR("Node has %s connection(s) and %s group(s).\nClick to show signals dock."), num_connections, num_groups)); + } else if (num_connections >= 1) { + item->add_button( + 0, + get_icon("Signals", "EditorIcons"), + BUTTON_SIGNALS, + false, + vformat(TTR("Node has %s connection(s).\nClick to show signals dock."), num_connections)); + } else if (num_groups >= 1) { + item->add_button( + 0, + get_icon("Groups", "EditorIcons"), + BUTTON_GROUPS, + false, + vformat(TTR("Node is in %s group(s).\nClick to show groups dock."), num_groups)); } } @@ -995,6 +1010,17 @@ bool SceneTreeEditor::can_drop_data_fw(const Point2 &p_point, const Variant &p_d return true; } + if (String(d["type"]) == "script_list_element") { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(d["script_list_element"]); + if (se) { + String sp = se->get_edited_resource()->get_path(); + if (_is_script_type(EditorFileSystem::get_singleton()->get_file_type(sp))) { + tree->set_drop_mode_flags(Tree::DROP_MODE_ON_ITEM); + return true; + } + } + } + return String(d["type"]) == "nodes"; } void SceneTreeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) { @@ -1032,6 +1058,16 @@ void SceneTreeEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data, emit_signal("files_dropped", files, np, section); } } + + if (String(d["type"]) == "script_list_element") { + ScriptEditorBase *se = Object::cast_to<ScriptEditorBase>(d["script_list_element"]); + if (se) { + String sp = se->get_edited_resource()->get_path(); + if (_is_script_type(EditorFileSystem::get_singleton()->get_file_type(sp))) { + emit_signal("script_dropped", sp, np); + } + } + } } void SceneTreeEditor::_rmb_select(const Vector2 &p_pos) { diff --git a/editor/scene_tree_editor.h b/editor/scene_tree_editor.h index 61cb59ce6f..b216be3b59 100644 --- a/editor/scene_tree_editor.h +++ b/editor/scene_tree_editor.h @@ -37,9 +37,7 @@ #include "scene/gui/button.h" #include "scene/gui/dialogs.h" #include "scene/gui/tree.h" -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ + class SceneTreeEditor : public Control { GDCLASS(SceneTreeEditor, Control); diff --git a/editor/script_create_dialog.cpp b/editor/script_create_dialog.cpp index ed9a24311d..7d0f40fe91 100644 --- a/editor/script_create_dialog.cpp +++ b/editor/script_create_dialog.cpp @@ -44,6 +44,23 @@ void ScriptCreateDialog::_notification(int p_what) { switch (p_what) { case NOTIFICATION_THEME_CHANGED: case NOTIFICATION_ENTER_TREE: { + for (int i = 0; i < ScriptServer::get_language_count(); i++) { + String lang = ScriptServer::get_language(i)->get_name(); + Ref<Texture> lang_icon = get_icon(lang, "EditorIcons"); + if (lang_icon.is_valid()) { + language_menu->set_item_icon(i, lang_icon); + } + } + String last_lang = EditorSettings::get_singleton()->get_project_metadata("script_setup", "last_selected_language", ""); + Ref<Texture> last_lang_icon; + if (!last_lang.empty()) { + last_lang_icon = get_icon(last_lang, "EditorIcons"); + } else { + last_lang_icon = language_menu->get_item_icon(default_language); + } + if (last_lang_icon.is_valid()) { + language_menu->set_icon(last_lang_icon); + } path_button->set_icon(get_icon("Folder", "EditorIcons")); parent_browse_button->set_icon(get_icon("Folder", "EditorIcons")); parent_search_button->set_icon(get_icon("ClassList", "EditorIcons")); @@ -671,13 +688,13 @@ ScriptCreateDialog::ScriptCreateDialog() { gc->add_child(l); gc->add_child(language_menu); - int default_lang = 0; + default_language = 0; for (int i = 0; i < ScriptServer::get_language_count(); i++) { String lang = ScriptServer::get_language(i)->get_name(); language_menu->add_item(lang); if (lang == "GDScript") { - default_lang = i; + default_language = i; } } @@ -691,8 +708,8 @@ ScriptCreateDialog::ScriptCreateDialog() { } } } else { - language_menu->select(default_lang); - current_language = default_lang; + language_menu->select(default_language); + current_language = default_language; } language_menu->connect("item_selected", this, "_lang_changed"); diff --git a/editor/script_create_dialog.h b/editor/script_create_dialog.h index 288b8f604b..202846fd3c 100644 --- a/editor/script_create_dialog.h +++ b/editor/script_create_dialog.h @@ -76,6 +76,7 @@ class ScriptCreateDialog : public ConfirmationDialog { bool is_built_in; bool built_in_enabled; int current_language; + int default_language; bool re_check_path; String script_template; Vector<String> template_list; |
