diff options
-rw-r--r-- | SConstruct | 6 | ||||
-rw-r--r-- | doc/classes/TileSet.xml | 12 | ||||
-rw-r--r-- | drivers/vulkan/SCsub | 11 | ||||
-rw-r--r-- | editor/code_editor.cpp | 2 | ||||
-rw-r--r-- | editor/plugins/script_editor_plugin.cpp | 61 | ||||
-rw-r--r-- | editor/plugins/script_editor_plugin.h | 1 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.cpp | 228 | ||||
-rw-r--r-- | editor/plugins/script_text_editor.h | 43 | ||||
-rw-r--r-- | editor/plugins/shader_editor_plugin.cpp | 25 | ||||
-rw-r--r-- | editor/plugins/text_editor.cpp | 42 | ||||
-rw-r--r-- | editor/plugins/text_editor.h | 21 | ||||
-rw-r--r-- | main/SCsub | 21 | ||||
-rw-r--r-- | modules/visual_script/visual_script_editor.cpp | 5 | ||||
-rw-r--r-- | modules/visual_script/visual_script_editor.h | 1 | ||||
-rw-r--r-- | platform/iphone/SCsub | 1 | ||||
-rw-r--r-- | platform/iphone/godot_view.mm | 25 | ||||
-rw-r--r-- | platform/iphone/godot_view_gesture_recognizer.h | 44 | ||||
-rw-r--r-- | platform/iphone/godot_view_gesture_recognizer.m | 171 | ||||
-rw-r--r-- | platform/osx/display_server_osx.mm | 18 | ||||
-rw-r--r-- | tests/SCsub | 10 |
20 files changed, 547 insertions, 201 deletions
diff --git a/SConstruct b/SConstruct index 98438d2c60..857daf7b0e 100644 --- a/SConstruct +++ b/SConstruct @@ -593,8 +593,6 @@ if selected_platform in platform_list: env.Append(CPPDEFINES=["PTRCALL_ENABLED"]) if env["tools"]: env.Append(CPPDEFINES=["TOOLS_ENABLED"]) - if env["tests"]: - env.Append(CPPDEFINES=["TESTS_ENABLED"]) if env["disable_3d"]: if env["tools"]: print( @@ -650,10 +648,6 @@ if selected_platform in platform_list: } ) - # Enable test framework globally and inform it of configuration method. - if env["tests"]: - env.Append(CPPDEFINES=["DOCTEST_CONFIG_IMPLEMENT"]) - scons_cache_path = os.environ.get("SCONS_CACHE") if scons_cache_path != None: CacheDir(scons_cache_path) diff --git a/doc/classes/TileSet.xml b/doc/classes/TileSet.xml index 9a78e45d46..4991a1e58b 100644 --- a/doc/classes/TileSet.xml +++ b/doc/classes/TileSet.xml @@ -478,7 +478,17 @@ <argument index="0" name="id" type="int"> </argument> <description> - Returns an array of the tile's shapes. + Returns an array of dictionaries describing the tile's shapes. + [b]Dictionary structure in the array returned by this method:[/b] + [codeblock] + { + "autotile_coord": Vector2, + "one_way": bool, + "one_way_margin": int, + "shape": CollisionShape2D, + "shape_transform": Transform2D, + } + [/codeblock] </description> </method> <method name="tile_get_texture" qualifiers="const"> diff --git a/drivers/vulkan/SCsub b/drivers/vulkan/SCsub index 436f513d72..61d91711da 100644 --- a/drivers/vulkan/SCsub +++ b/drivers/vulkan/SCsub @@ -4,6 +4,7 @@ Import("env") env.add_source_files(env.drivers_sources, "*.cpp") +# FIXME: Refactor all this to reduce code duplication. if env["platform"] == "android": # Use NDK Vulkan headers thirdparty_dir = env["ANDROID_NDK_ROOT"] + "/sources/third_party/vulkan/src" @@ -100,3 +101,13 @@ elif env["builtin_vulkan"]: loader_sources = [thirdparty_dir + "/loader/" + file for file in loader_sources] env_thirdparty.add_source_files(env.drivers_sources, loader_sources) env_thirdparty.add_source_files(env.drivers_sources, vma_sources) +else: # Always build VMA. + thirdparty_dir = "#thirdparty/vulkan" + env.Prepend(CPPPATH=[thirdparty_dir]) + + # Build Vulkan loader library + env_thirdparty = env.Clone() + env_thirdparty.disable_warnings() + vma_sources = [thirdparty_dir + "/vk_mem_alloc.cpp"] + + env_thirdparty.add_source_files(env.drivers_sources, vma_sources) diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp index 9a87d6d38c..37db3ba780 100644 --- a/editor/code_editor.cpp +++ b/editor/code_editor.cpp @@ -1456,8 +1456,6 @@ void CodeTextEditor::set_edit_state(const Variant &p_state) { text_editor->set_line_as_bookmark(bookmarks[i], true); } } - - text_editor->grab_focus(); } void CodeTextEditor::set_error(const String &p_error) { diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp index 00fee90841..6b844ec0d0 100644 --- a/editor/plugins/script_editor_plugin.cpp +++ b/editor/plugins/script_editor_plugin.cpp @@ -696,7 +696,7 @@ void ScriptEditor::_close_tab(int p_idx, bool p_save, bool p_history_back) { Node *tselected = tab_container->get_child(selected); - ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tab_container->get_child(selected)); + ScriptEditorBase *current = Object::cast_to<ScriptEditorBase>(tselected); if (current) { Ref<Script> script = current->get_edited_resource(); if (p_save) { @@ -779,8 +779,10 @@ void ScriptEditor::_close_docs_tab() { void ScriptEditor::_copy_script_path() { ScriptEditorBase *se = _get_current_editor(); - RES script = se->get_edited_resource(); - DisplayServer::get_singleton()->clipboard_set(script->get_path()); + if (se) { + RES script = se->get_edited_resource(); + DisplayServer::get_singleton()->clipboard_set(script->get_path()); + } } void ScriptEditor::_close_other_tabs() { @@ -1038,17 +1040,19 @@ void ScriptEditor::_file_dialog_action(String p_file) { } break; case FILE_SAVE_AS: { ScriptEditorBase *current = _get_current_editor(); + if (current) { + RES resource = current->get_edited_resource(); + String path = ProjectSettings::get_singleton()->localize_path(p_file); + Error err = _save_text_file(resource, path); - String path = ProjectSettings::get_singleton()->localize_path(p_file); - Error err = _save_text_file(current->get_edited_resource(), path); + if (err != OK) { + editor->show_accept(TTR("Error saving file!"), TTR("OK")); + return; + } - if (err != OK) { - editor->show_accept(TTR("Error saving file!"), TTR("OK")); - return; + resource->set_path(path); + _update_script_names(); } - - ((Resource *)current->get_edited_resource().ptr())->set_path(path); - _update_script_names(); } break; case THEME_SAVE_AS: { if (!EditorSettings::get_singleton()->save_text_editor_theme_as(p_file)) { @@ -1240,13 +1244,14 @@ void ScriptEditor::_menu_option(int p_option) { } } - Ref<TextFile> text_file = current->get_edited_resource(); + RES resource = current->get_edited_resource(); + Ref<TextFile> text_file = resource; if (text_file != nullptr) { current->apply_code(); _save_text_file(text_file, text_file->get_path()); break; } - editor->save_resource(current->get_edited_resource()); + editor->save_resource(resource); } break; case FILE_SAVE_AS: { @@ -1264,7 +1269,8 @@ void ScriptEditor::_menu_option(int p_option) { } } - Ref<TextFile> text_file = current->get_edited_resource(); + RES resource = current->get_edited_resource(); + Ref<TextFile> text_file = resource; if (text_file != nullptr) { file_dialog->set_file_mode(EditorFileDialog::FILE_MODE_SAVE_FILE); file_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM); @@ -1280,8 +1286,8 @@ void ScriptEditor::_menu_option(int p_option) { break; } - editor->push_item(Object::cast_to<Object>(current->get_edited_resource().ptr())); - editor->save_resource_as(current->get_edited_resource()); + editor->push_item(resource.ptr()); + editor->save_resource_as(resource); } break; @@ -1632,6 +1638,8 @@ void ScriptEditor::ensure_select_current() { if (tab_container->get_child_count() && tab_container->get_current_tab() >= 0) { ScriptEditorBase *se = _get_current_editor(); if (se) { + se->enable_editor(); + if (!grab_focus_block && is_visible_in_tree()) { se->ensure_focus(); } @@ -1976,6 +1984,11 @@ void ScriptEditor::_update_script_names() { script_list->select(index); script_name_label->set_text(sedata_filtered[i].name); script_icon->set_texture(sedata_filtered[i].icon); + ScriptEditorBase *se = _get_current_editor(); + if (se) { + se->enable_editor(); + _update_selected_editor_menu(); + } } } @@ -2150,6 +2163,8 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra if ((script != nullptr && se->get_edited_resource() == p_resource) || se->get_edited_resource()->get_path() == p_resource->get_path()) { if (should_open) { + se->enable_editor(); + if (tab_container->get_current_tab() != i) { _go_to_tab(i); _update_script_names(); @@ -2180,6 +2195,8 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra } ERR_FAIL_COND_V(!se, false); + se->set_edited_resource(p_resource); + if (p_resource->get_class_name() != StringName("VisualScript")) { bool highlighter_set = false; for (int i = 0; i < syntax_highlighters.size(); i++) { @@ -2200,7 +2217,11 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra } tab_container->add_child(se); - se->set_edited_resource(p_resource); + + if (p_grab_focus) { + se->enable_editor(); + } + se->set_tooltip_request_func("_get_debug_tooltip", this); if (se->get_edit_menu()) { se->get_edit_menu()->hide(); @@ -2210,6 +2231,7 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra if (p_grab_focus) { _go_to_tab(tab_container->get_tab_count() - 1); + _add_recent_script(p_resource->get_path()); } _sort_list_on_update = true; @@ -2234,7 +2256,6 @@ bool ScriptEditor::edit(const RES &p_resource, int p_line, int p_col, bool p_gra } notify_script_changed(p_resource); - _add_recent_script(p_resource->get_path()); return true; } @@ -2706,7 +2727,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { if (!scr.is_valid()) { continue; } - if (!edit(scr)) { + if (!edit(scr, false)) { continue; } } else { @@ -2715,7 +2736,7 @@ void ScriptEditor::set_window_layout(Ref<ConfigFile> p_layout) { if (error != OK || !text_file.is_valid()) { continue; } - if (!edit(text_file)) { + if (!edit(text_file, false)) { continue; } } diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h index 3891af4091..74376d692f 100644 --- a/editor/plugins/script_editor_plugin.h +++ b/editor/plugins/script_editor_plugin.h @@ -134,6 +134,7 @@ public: virtual RES get_edited_resource() const = 0; virtual Vector<String> get_functions() = 0; virtual void set_edited_resource(const RES &p_res) = 0; + virtual void enable_editor() = 0; virtual void reload_text() = 0; virtual String get_name() = 0; virtual Ref<Texture2D> get_theme_icon() = 0; diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp index f4fdf8ccb0..f728974dd7 100644 --- a/editor/plugins/script_text_editor.cpp +++ b/editor/plugins/script_text_editor.cpp @@ -140,10 +140,10 @@ RES ScriptTextEditor::get_edited_resource() const { } void ScriptTextEditor::set_edited_resource(const RES &p_res) { - ERR_FAIL_COND(!script.is_null()); + ERR_FAIL_COND(script.is_valid()); + ERR_FAIL_COND(p_res.is_null()); script = p_res; - _set_theme_for_script(); code_editor->get_text_edit()->set_text(script->get_source_code()); code_editor->get_text_edit()->clear_undo_history(); @@ -151,6 +151,17 @@ void ScriptTextEditor::set_edited_resource(const RES &p_res) { emit_signal("name_changed"); code_editor->update_line_and_column(); +} + +void ScriptTextEditor::enable_editor() { + if (editor_enabled) { + return; + } + + editor_enabled = true; + + _enable_code_editor(); + _set_theme_for_script(); _validate_script(); } @@ -301,14 +312,6 @@ void ScriptTextEditor::reload_text() { code_editor->update_line_and_column(); } -void ScriptTextEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: - _load_theme_settings(); - break; - } -} - void ScriptTextEditor::add_callback(const String &p_function, PackedStringArray p_args) { String code = code_editor->get_text_edit()->get_text(); int pos = script->get_language()->find_function(p_function, code); @@ -352,6 +355,10 @@ void ScriptTextEditor::set_edit_state(const Variant &p_state) { _change_syntax_highlighter(idx); } } + + if (editor_enabled) { + ensure_focus(); + } } void ScriptTextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) { @@ -1274,23 +1281,28 @@ void ScriptTextEditor::_edit_option_toggle_inline_comment() { } void ScriptTextEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { + ERR_FAIL_COND(p_highlighter.is_null()); + highlighters[p_highlighter->_get_name()] = p_highlighter; highlighter_menu->add_radio_check_item(p_highlighter->_get_name()); } void ScriptTextEditor::set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { + ERR_FAIL_COND(p_highlighter.is_null()); + + Map<String, Ref<EditorSyntaxHighlighter>>::Element *el = highlighters.front(); + while (el != nullptr) { + int highlighter_index = highlighter_menu->get_item_idx_from_text(el->key()); + highlighter_menu->set_item_checked(highlighter_index, el->value() == p_highlighter); + el = el->next(); + } + TextEdit *te = code_editor->get_text_edit(); p_highlighter->_set_edited_resource(script); te->set_syntax_highlighter(p_highlighter); - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->_get_name()), true); } void ScriptTextEditor::_change_syntax_highlighter(int p_idx) { - Map<String, Ref<EditorSyntaxHighlighter>>::Element *el = highlighters.front(); - while (el != nullptr) { - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false); - el = el->next(); - } set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]); } @@ -1606,64 +1618,40 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p context_menu->popup(); } -ScriptTextEditor::ScriptTextEditor() { - theme_loaded = false; - script_is_valid = false; +void ScriptTextEditor::_enable_code_editor() { + ERR_FAIL_COND(code_editor->get_parent()); VSplitContainer *editor_box = memnew(VSplitContainer); add_child(editor_box); editor_box->set_anchors_and_margins_preset(Control::PRESET_WIDE); editor_box->set_v_size_flags(SIZE_EXPAND_FILL); - code_editor = memnew(CodeTextEditor); editor_box->add_child(code_editor); - code_editor->add_theme_constant_override("separation", 2); - code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel)); code_editor->connect("validate_script", callable_mp(this, &ScriptTextEditor::_validate_script)); code_editor->connect("load_theme_settings", callable_mp(this, &ScriptTextEditor::_load_theme_settings)); - code_editor->set_code_complete_func(_code_complete_scripts, this); code_editor->get_text_edit()->connect("breakpoint_toggled", callable_mp(this, &ScriptTextEditor::_breakpoint_toggled)); code_editor->get_text_edit()->connect("symbol_lookup", callable_mp(this, &ScriptTextEditor::_lookup_symbol)); code_editor->get_text_edit()->connect("symbol_validate", callable_mp(this, &ScriptTextEditor::_validate_symbol)); - code_editor->get_text_edit()->connect("info_clicked", callable_mp(this, &ScriptTextEditor::_lookup_connections)); - code_editor->set_v_size_flags(SIZE_EXPAND_FILL); + code_editor->get_text_edit()->connect("gui_input", callable_mp(this, &ScriptTextEditor::_text_edit_gui_input)); code_editor->show_toggle_scripts_button(); - warnings_panel = memnew(RichTextLabel); editor_box->add_child(warnings_panel); warnings_panel->add_theme_font_override( "normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font("main", "EditorFonts")); - warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); - warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL); - warnings_panel->set_meta_underline(true); - warnings_panel->set_selection_enabled(true); - warnings_panel->set_focus_mode(FOCUS_CLICK); - warnings_panel->hide(); - - code_editor->connect("show_warnings_panel", callable_mp(this, &ScriptTextEditor::_show_warnings_panel)); warnings_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_warning_clicked)); - update_settings(); - - code_editor->get_text_edit()->set_callhint_settings( - EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"), - EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset")); - - code_editor->get_text_edit()->set_select_identifiers_on_hover(true); - code_editor->get_text_edit()->set_context_menu_enabled(false); - code_editor->get_text_edit()->connect("gui_input", callable_mp(this, &ScriptTextEditor::_text_edit_gui_input)); - - context_menu = memnew(PopupMenu); add_child(context_menu); context_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); - color_panel = memnew(PopupPanel); add_child(color_panel); + color_picker = memnew(ColorPicker); color_picker->set_deferred_mode(true); - color_panel->add_child(color_picker); color_picker->connect("color_changed", callable_mp(this, &ScriptTextEditor::_color_changed)); + color_panel->add_child(color_picker); + // get default color picker mode from editor settings int default_color_mode = EDITOR_GET("interface/inspector/default_color_picker_mode"); if (default_color_mode == 1) { @@ -1672,12 +1660,27 @@ ScriptTextEditor::ScriptTextEditor() { color_picker->set_raw_mode(true); } - edit_hb = memnew(HBoxContainer); + quick_open = memnew(ScriptEditorQuickOpen); + quick_open->connect("goto_line", callable_mp(this, &ScriptTextEditor::_goto_line)); + add_child(quick_open); - edit_menu = memnew(MenuButton); - edit_menu->set_text(TTR("Edit")); - edit_menu->set_switch_on_hover(true); + goto_line_dialog = memnew(GotoLineDialog); + add_child(goto_line_dialog); + + add_child(connection_info_dialog); + + edit_hb->add_child(search_menu); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); + search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES); + search_menu->get_popup()->add_separator(); + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL); + search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_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(); @@ -1707,8 +1710,6 @@ ScriptTextEditor::ScriptTextEditor() { edit_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); edit_menu->get_popup()->add_separator(); - PopupMenu *convert_case = memnew(PopupMenu); - convert_case->set_name("convert_case"); edit_menu->get_popup()->add_child(convert_case); edit_menu->get_popup()->add_submenu_item(TTR("Convert Case"), "convert_case"); convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/convert_to_uppercase", TTR("Uppercase"), KEY_MASK_SHIFT | KEY_F4), EDIT_TO_UPPERCASE); @@ -1716,12 +1717,73 @@ ScriptTextEditor::ScriptTextEditor() { convert_case->add_shortcut(ED_SHORTCUT("script_text_editor/capitalize", TTR("Capitalize"), KEY_MASK_SHIFT | KEY_F6), EDIT_CAPITALIZE); convert_case->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); - highlighter_menu = memnew(PopupMenu); - highlighter_menu->set_name("highlighter_menu"); edit_menu->get_popup()->add_child(highlighter_menu); edit_menu->get_popup()->add_submenu_item(TTR("Syntax Highlighter"), "highlighter_menu"); highlighter_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_change_syntax_highlighter)); + _load_theme_settings(); + + search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES); + edit_hb->add_child(goto_menu); + goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_function"), SEARCH_LOCATE_FUNCTION); + goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_line"), SEARCH_GOTO_LINE); + goto_menu->get_popup()->add_separator(); + + 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_popup", callable_mp(this, &ScriptTextEditor::_update_bookmark_list)); + bookmarks_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_bookmark_item_pressed)); + + goto_menu->get_popup()->add_child(breakpoints_menu); + goto_menu->get_popup()->add_submenu_item(TTR("Breakpoints"), "Breakpoints"); + _update_breakpoint_list(); + breakpoints_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_breakpoint_list)); + breakpoints_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_breakpoint_item_pressed)); + + goto_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); +} + +ScriptTextEditor::ScriptTextEditor() { + code_editor = memnew(CodeTextEditor); + code_editor->add_theme_constant_override("separation", 2); + code_editor->set_anchors_and_margins_preset(Control::PRESET_WIDE); + code_editor->set_code_complete_func(_code_complete_scripts, this); + code_editor->set_v_size_flags(SIZE_EXPAND_FILL); + + warnings_panel = memnew(RichTextLabel); + warnings_panel->set_custom_minimum_size(Size2(0, 100 * EDSCALE)); + warnings_panel->set_h_size_flags(SIZE_EXPAND_FILL); + warnings_panel->set_meta_underline(true); + warnings_panel->set_selection_enabled(true); + warnings_panel->set_focus_mode(FOCUS_CLICK); + warnings_panel->hide(); + + update_settings(); + + code_editor->get_text_edit()->set_callhint_settings( + EditorSettings::get_singleton()->get("text_editor/completion/put_callhint_tooltip_below_current_line"), + EditorSettings::get_singleton()->get("text_editor/completion/callhint_tooltip_offset")); + + code_editor->get_text_edit()->set_select_identifiers_on_hover(true); + code_editor->get_text_edit()->set_context_menu_enabled(false); + + context_menu = memnew(PopupMenu); + + color_panel = memnew(PopupPanel); + + edit_hb = memnew(HBoxContainer); + + edit_menu = memnew(MenuButton); + edit_menu->set_text(TTR("Edit")); + edit_menu->set_switch_on_hover(true); + + convert_case = memnew(PopupMenu); + convert_case->set_name("convert_case"); + + highlighter_menu = memnew(PopupMenu); + highlighter_menu->set_name("highlighter_menu"); + Ref<EditorPlainTextSyntaxHighlighter> plain_highlighter; plain_highlighter.instance(); add_syntax_highlighter(plain_highlighter); @@ -1732,64 +1794,42 @@ ScriptTextEditor::ScriptTextEditor() { set_syntax_highlighter(highlighter); search_menu = memnew(MenuButton); - edit_hb->add_child(search_menu); search_menu->set_text(TTR("Search")); search_menu->set_switch_on_hover(true); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find"), SEARCH_FIND); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_next"), SEARCH_FIND_NEXT); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_previous"), SEARCH_FIND_PREV); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace"), SEARCH_REPLACE); - search_menu->get_popup()->add_separator(); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/find_in_files"), SEARCH_IN_FILES); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/replace_in_files"), REPLACE_IN_FILES); - search_menu->get_popup()->add_separator(); - search_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/contextual_help"), HELP_CONTEXTUAL); - search_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); - - edit_hb->add_child(edit_menu); - - MenuButton *goto_menu = memnew(MenuButton); - edit_hb->add_child(goto_menu); + goto_menu = memnew(MenuButton); goto_menu->set_text(TTR("Go To")); goto_menu->set_switch_on_hover(true); - goto_menu->get_popup()->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option)); - - goto_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/goto_function"), SEARCH_LOCATE_FUNCTION); - 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("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_popup", callable_mp(this, &ScriptTextEditor::_update_bookmark_list)); - bookmarks_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_bookmark_item_pressed)); breakpoints_menu = memnew(PopupMenu); breakpoints_menu->set_name("Breakpoints"); - goto_menu->get_popup()->add_child(breakpoints_menu); - goto_menu->get_popup()->add_submenu_item(TTR("Breakpoints"), "Breakpoints"); - _update_breakpoint_list(); - breakpoints_menu->connect("about_to_popup", callable_mp(this, &ScriptTextEditor::_update_breakpoint_list)); - breakpoints_menu->connect("index_pressed", callable_mp(this, &ScriptTextEditor::_breakpoint_item_pressed)); - - quick_open = memnew(ScriptEditorQuickOpen); - add_child(quick_open); - quick_open->connect("goto_line", callable_mp(this, &ScriptTextEditor::_goto_line)); - - goto_line_dialog = memnew(GotoLineDialog); - add_child(goto_line_dialog); connection_info_dialog = memnew(ConnectionInfoDialog); - add_child(connection_info_dialog); code_editor->get_text_edit()->set_drag_forwarding(this); } ScriptTextEditor::~ScriptTextEditor() { highlighters.clear(); + + if (!editor_enabled) { + memdelete(code_editor); + memdelete(warnings_panel); + memdelete(context_menu); + memdelete(color_panel); + memdelete(edit_hb); + memdelete(edit_menu); + memdelete(convert_case); + memdelete(highlighter_menu); + memdelete(search_menu); + memdelete(goto_menu); + memdelete(bookmarks_menu); + memdelete(breakpoints_menu); + memdelete(connection_info_dialog); + } } static ScriptEditorBase *create_editor(const RES &p_resource) { diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h index 6d7f84d746..e931c9fdc6 100644 --- a/editor/plugins/script_text_editor.h +++ b/editor/plugins/script_text_editor.h @@ -39,8 +39,8 @@ class ConnectionInfoDialog : public AcceptDialog { GDCLASS(ConnectionInfoDialog, AcceptDialog); - Label *method; - Tree *tree; + Label *method = nullptr; + Tree *tree = nullptr; virtual void ok_pressed() override; @@ -53,11 +53,12 @@ public: class ScriptTextEditor : public ScriptEditorBase { GDCLASS(ScriptTextEditor, ScriptEditorBase); - CodeTextEditor *code_editor; - RichTextLabel *warnings_panel; + CodeTextEditor *code_editor = nullptr; + RichTextLabel *warnings_panel = nullptr; Ref<Script> script; - bool script_is_valid; + bool script_is_valid = false; + bool editor_enabled = false; Vector<String> functions; @@ -65,25 +66,27 @@ class ScriptTextEditor : public ScriptEditorBase { Vector<String> member_keywords; - HBoxContainer *edit_hb; + HBoxContainer *edit_hb = nullptr; - MenuButton *edit_menu; - MenuButton *search_menu; - PopupMenu *bookmarks_menu; - PopupMenu *breakpoints_menu; - PopupMenu *highlighter_menu; - PopupMenu *context_menu; + MenuButton *edit_menu = nullptr; + MenuButton *search_menu = nullptr; + MenuButton *goto_menu = nullptr; + PopupMenu *bookmarks_menu = nullptr; + PopupMenu *breakpoints_menu = nullptr; + PopupMenu *highlighter_menu = nullptr; + PopupMenu *context_menu = nullptr; + PopupMenu *convert_case = nullptr; - GotoLineDialog *goto_line_dialog; - ScriptEditorQuickOpen *quick_open; - ConnectionInfoDialog *connection_info_dialog; + GotoLineDialog *goto_line_dialog = nullptr; + ScriptEditorQuickOpen *quick_open = nullptr; + ConnectionInfoDialog *connection_info_dialog = nullptr; - PopupPanel *color_panel; - ColorPicker *color_picker; + PopupPanel *color_panel = nullptr; + ColorPicker *color_picker = nullptr; Vector2 color_position; String color_args; - bool theme_loaded; + bool theme_loaded = false; enum { EDIT_UNDO, @@ -132,6 +135,8 @@ class ScriptTextEditor : public ScriptEditorBase { LOOKUP_SYMBOL, }; + void _enable_code_editor(); + protected: void _update_breakpoint_list(); void _breakpoint_item_pressed(int p_idx); @@ -149,7 +154,6 @@ protected: void _show_warnings_panel(bool p_show); void _warning_clicked(Variant p_line); - void _notification(int p_what); static void _bind_methods(); Map<String, Ref<EditorSyntaxHighlighter>> highlighters; @@ -185,6 +189,7 @@ public: virtual void apply_code() override; virtual RES get_edited_resource() const override; virtual void set_edited_resource(const RES &p_res) override; + virtual void enable_editor() override; virtual Vector<String> get_functions() override; virtual void reload_text() override; virtual String get_name() override; diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp index 60ba3802fb..dc2abe15ee 100644 --- a/editor/plugins/shader_editor_plugin.cpp +++ b/editor/plugins/shader_editor_plugin.cpp @@ -136,28 +136,39 @@ void ShaderTextEditor::_load_theme_settings() { syntax_highlighter->set_function_color(EDITOR_GET("text_editor/highlighting/function_color")); syntax_highlighter->set_member_variable_color(EDITOR_GET("text_editor/highlighting/member_variable_color")); + syntax_highlighter->clear_keyword_colors(); + List<String> keywords; ShaderLanguage::get_keyword_list(&keywords); + const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); + + for (List<String>::Element *E = keywords.front(); E; E = E->next()) { + syntax_highlighter->add_keyword_color(E->get(), keyword_color); + } + // Colorize built-ins like `COLOR` differently to make them easier + // to distinguish from keywords at a quick glance. + + List<String> built_ins; if (shader.is_valid()) { for (const Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = ShaderTypes::get_singleton()->get_functions(RenderingServer::ShaderMode(shader->get_mode())).front(); E; E = E->next()) { for (const Map<StringName, ShaderLanguage::BuiltInInfo>::Element *F = E->get().built_ins.front(); F; F = F->next()) { - keywords.push_back(F->key()); + built_ins.push_back(F->key()); } } for (int i = 0; i < ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode())).size(); i++) { - keywords.push_back(ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()))[i]); + built_ins.push_back(ShaderTypes::get_singleton()->get_modes(RenderingServer::ShaderMode(shader->get_mode()))[i]); } } - const Color keyword_color = EDITOR_GET("text_editor/highlighting/keyword_color"); - syntax_highlighter->clear_keyword_colors(); - for (List<String>::Element *E = keywords.front(); E; E = E->next()) { - syntax_highlighter->add_keyword_color(E->get(), keyword_color); + const Color member_variable_color = EDITOR_GET("text_editor/highlighting/member_variable_color"); + + for (List<String>::Element *E = built_ins.front(); E; E = E->next()) { + syntax_highlighter->add_keyword_color(E->get(), member_variable_color); } - //colorize comments + // Colorize comments. const Color comment_color = EDITOR_GET("text_editor/highlighting/comment_color"); syntax_highlighter->clear_color_regions(); syntax_highlighter->add_color_region("/*", "*/", comment_color, false); diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp index d602d152fe..6d64e3b3cd 100644 --- a/editor/plugins/text_editor.cpp +++ b/editor/plugins/text_editor.cpp @@ -34,22 +34,27 @@ #include "editor/editor_node.h" void TextEditor::add_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { + ERR_FAIL_COND(p_highlighter.is_null()); + highlighters[p_highlighter->_get_name()] = p_highlighter; highlighter_menu->add_radio_check_item(p_highlighter->_get_name()); } void TextEditor::set_syntax_highlighter(Ref<EditorSyntaxHighlighter> p_highlighter) { - TextEdit *te = code_editor->get_text_edit(); - te->set_syntax_highlighter(p_highlighter); - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(p_highlighter->_get_name()), true); -} + ERR_FAIL_COND(p_highlighter.is_null()); -void TextEditor::_change_syntax_highlighter(int p_idx) { Map<String, Ref<EditorSyntaxHighlighter>>::Element *el = highlighters.front(); while (el != nullptr) { - highlighter_menu->set_item_checked(highlighter_menu->get_item_idx_from_text(el->key()), false); + int highlighter_index = highlighter_menu->get_item_idx_from_text(el->key()); + highlighter_menu->set_item_checked(highlighter_index, el->value() == p_highlighter); el = el->next(); } + + TextEdit *te = code_editor->get_text_edit(); + te->set_syntax_highlighter(p_highlighter); +} + +void TextEditor::_change_syntax_highlighter(int p_idx) { set_syntax_highlighter(highlighters[highlighter_menu->get_item_text(p_idx)]); } @@ -126,7 +131,7 @@ String TextEditor::get_name() { } Ref<Texture2D> TextEditor::get_theme_icon() { - return EditorNode::get_singleton()->get_object_icon(text_file.operator->(), ""); + return EditorNode::get_singleton()->get_object_icon(text_file.ptr(), ""); } RES TextEditor::get_edited_resource() const { @@ -134,7 +139,8 @@ RES TextEditor::get_edited_resource() const { } void TextEditor::set_edited_resource(const RES &p_res) { - ERR_FAIL_COND(!text_file.is_null()); + ERR_FAIL_COND(text_file.is_valid()); + ERR_FAIL_COND(p_res.is_null()); text_file = p_res; @@ -146,6 +152,16 @@ void TextEditor::set_edited_resource(const RES &p_res) { code_editor->update_line_and_column(); } +void TextEditor::enable_editor() { + if (editor_enabled) { + return; + } + + editor_enabled = true; + + _load_theme_settings(); +} + void TextEditor::add_callback(const String &p_function, PackedStringArray p_args) { } @@ -237,6 +253,8 @@ void TextEditor::set_edit_state(const Variant &p_state) { _change_syntax_highlighter(idx); } } + + ensure_focus(); } void TextEditor::trim_trailing_whitespace() { @@ -303,14 +321,6 @@ void TextEditor::clear_edit_menu() { memdelete(edit_hb); } -void TextEditor::_notification(int p_what) { - switch (p_what) { - case NOTIFICATION_READY: - _load_theme_settings(); - break; - } -} - void TextEditor::_edit_option(int p_op) { TextEdit *tx = code_editor->get_text_edit(); diff --git a/editor/plugins/text_editor.h b/editor/plugins/text_editor.h index 5299776b56..f3e9e599cf 100644 --- a/editor/plugins/text_editor.h +++ b/editor/plugins/text_editor.h @@ -37,18 +37,19 @@ class TextEditor : public ScriptEditorBase { GDCLASS(TextEditor, ScriptEditorBase); private: - CodeTextEditor *code_editor; + CodeTextEditor *code_editor = nullptr; Ref<TextFile> text_file; + bool editor_enabled = false; - HBoxContainer *edit_hb; - MenuButton *edit_menu; - PopupMenu *highlighter_menu; - MenuButton *search_menu; - PopupMenu *bookmarks_menu; - PopupMenu *context_menu; + HBoxContainer *edit_hb = nullptr; + MenuButton *edit_menu = nullptr; + PopupMenu *highlighter_menu = nullptr; + MenuButton *search_menu = nullptr; + PopupMenu *bookmarks_menu = nullptr; + PopupMenu *context_menu = nullptr; - GotoLineDialog *goto_line_dialog; + GotoLineDialog *goto_line_dialog = nullptr; enum { EDIT_UNDO, @@ -88,8 +89,6 @@ private: protected: static void _bind_methods(); - void _notification(int p_what); - void _edit_option(int p_op); void _make_context_menu(bool p_selection, bool p_can_fold, bool p_is_folded, Vector2 p_position); void _text_edit_gui_input(const Ref<InputEvent> &ev); @@ -113,7 +112,7 @@ public: virtual Ref<Texture2D> get_theme_icon() override; virtual RES get_edited_resource() const override; virtual void set_edited_resource(const RES &p_res) override; - void set_edited_file(const Ref<TextFile> &p_file); + virtual void enable_editor() override; virtual void reload_text() override; virtual void apply_code() override; virtual bool is_unsaved() override; diff --git a/main/SCsub b/main/SCsub index 152d0c4d03..97f77840f1 100644 --- a/main/SCsub +++ b/main/SCsub @@ -7,18 +7,23 @@ import main_builders env.main_sources = [] -env.add_source_files(env.main_sources, "*.cpp") +env_main = env.Clone() -env.Depends("#main/splash.gen.h", "#main/splash.png") -env.CommandNoCache("#main/splash.gen.h", "#main/splash.png", run_in_subprocess(main_builders.make_splash)) +env_main.add_source_files(env.main_sources, "*.cpp") -env.Depends("#main/splash_editor.gen.h", "#main/splash_editor.png") -env.CommandNoCache( +if env["tests"]: + env_main.Append(CPPDEFINES=["TESTS_ENABLED"]) + +env_main.Depends("#main/splash.gen.h", "#main/splash.png") +env_main.CommandNoCache("#main/splash.gen.h", "#main/splash.png", run_in_subprocess(main_builders.make_splash)) + +env_main.Depends("#main/splash_editor.gen.h", "#main/splash_editor.png") +env_main.CommandNoCache( "#main/splash_editor.gen.h", "#main/splash_editor.png", run_in_subprocess(main_builders.make_splash_editor) ) -env.Depends("#main/app_icon.gen.h", "#main/app_icon.png") -env.CommandNoCache("#main/app_icon.gen.h", "#main/app_icon.png", run_in_subprocess(main_builders.make_app_icon)) +env_main.Depends("#main/app_icon.gen.h", "#main/app_icon.png") +env_main.CommandNoCache("#main/app_icon.gen.h", "#main/app_icon.png", run_in_subprocess(main_builders.make_app_icon)) -lib = env.add_library("main", env.main_sources) +lib = env_main.add_library("main", env.main_sources) env.Prepend(LIBS=[lib]) diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp index 2fcd9332a1..a1c7dca9d2 100644 --- a/modules/visual_script/visual_script_editor.cpp +++ b/modules/visual_script/visual_script_editor.cpp @@ -2513,6 +2513,8 @@ RES VisualScriptEditor::get_edited_resource() const { } void VisualScriptEditor::set_edited_resource(const RES &p_res) { + ERR_FAIL_COND(script.is_valid()); + ERR_FAIL_COND(p_res.is_null()); script = p_res; signal_editor->script = script; signal_editor->undo_redo = undo_redo; @@ -2533,6 +2535,9 @@ void VisualScriptEditor::set_edited_resource(const RES &p_res) { _update_members(); } +void VisualScriptEditor::enable_editor() { +} + Vector<String> VisualScriptEditor::get_functions() { return Vector<String>(); } diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h index e59618e120..0c5665cee8 100644 --- a/modules/visual_script/visual_script_editor.h +++ b/modules/visual_script/visual_script_editor.h @@ -294,6 +294,7 @@ public: virtual void apply_code() override; virtual RES get_edited_resource() const override; virtual void set_edited_resource(const RES &p_res) override; + virtual void enable_editor() override; virtual Vector<String> get_functions() override; virtual void reload_text() override; virtual String get_name() override; diff --git a/platform/iphone/SCsub b/platform/iphone/SCsub index db64a14635..49c77468ed 100644 --- a/platform/iphone/SCsub +++ b/platform/iphone/SCsub @@ -18,6 +18,7 @@ iphone_lib = [ "godot_view.mm", "display_layer.mm", "godot_view_renderer.mm", + "godot_view_gesture_recognizer.m", ] env_ios = env.Clone() diff --git a/platform/iphone/godot_view.mm b/platform/iphone/godot_view.mm index cd17ff5430..c0a31549c4 100644 --- a/platform/iphone/godot_view.mm +++ b/platform/iphone/godot_view.mm @@ -33,6 +33,7 @@ #include "core/ustring.h" #import "display_layer.h" #include "display_server_iphone.h" +#import "godot_view_gesture_recognizer.h" #import "godot_view_renderer.h" #import <CoreMotion/CoreMotion.h> @@ -57,6 +58,8 @@ static const int max_touches = 8; @property(strong, nonatomic) CMMotionManager *motionManager; +@property(strong, nonatomic) GodotViewGestureRecognizer *delayGestureRecognizer; + @end @implementation GodotView @@ -139,6 +142,10 @@ static const int max_touches = 8; self.animationTimer = nil; } + if (self.delayGestureRecognizer) { + self.delayGestureRecognizer = nil; + } + [super dealloc]; } @@ -157,6 +164,12 @@ static const int max_touches = 8; self.motionManager = nil; } } + + // Initialize delay gesture recognizer + GodotViewGestureRecognizer *gestureRecognizer = [[GodotViewGestureRecognizer alloc] init]; + self.delayGestureRecognizer = gestureRecognizer; + [self addGestureRecognizer:self.delayGestureRecognizer]; + [gestureRecognizer release]; } - (void)stopRendering { @@ -359,9 +372,6 @@ static const int max_touches = 8; for (unsigned int i = 0; i < [tlist count]; i++) { if ([touchesSet containsObject:[tlist objectAtIndex:i]]) { UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseBegan) { - continue; - } int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); CGPoint touchPoint = [touch locationInView:self]; @@ -375,9 +385,6 @@ static const int max_touches = 8; for (unsigned int i = 0; i < [tlist count]; i++) { if ([touches containsObject:[tlist objectAtIndex:i]]) { UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseMoved) { - continue; - } int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); CGPoint touchPoint = [touch locationInView:self]; @@ -392,9 +399,6 @@ static const int max_touches = 8; for (unsigned int i = 0; i < [tlist count]; i++) { if ([touches containsObject:[tlist objectAtIndex:i]]) { UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseEnded) { - continue; - } int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); [self removeTouch:touch]; @@ -409,9 +413,6 @@ static const int max_touches = 8; for (unsigned int i = 0; i < [tlist count]; i++) { if ([touches containsObject:[tlist objectAtIndex:i]]) { UITouch *touch = [tlist objectAtIndex:i]; - if (touch.phase != UITouchPhaseCancelled) { - continue; - } int tid = [self getTouchIDForTouch:touch]; ERR_FAIL_COND(tid == -1); DisplayServerIPhone::get_singleton()->touches_cancelled(tid); diff --git a/platform/iphone/godot_view_gesture_recognizer.h b/platform/iphone/godot_view_gesture_recognizer.h new file mode 100644 index 0000000000..ca3bd808d1 --- /dev/null +++ b/platform/iphone/godot_view_gesture_recognizer.h @@ -0,0 +1,44 @@ +/*************************************************************************/ +/* godot_view_gesture_recognizer.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +// GLViewGestureRecognizer allows iOS gestures to work currectly by +// emulating UIScrollView's UIScrollViewDelayedTouchesBeganGestureRecognizer. +// It catches all gestures incoming to UIView and delays them for 150ms +// (the same value used by UIScrollViewDelayedTouchesBeganGestureRecognizer) +// If touch cancelation or end message is fired it fires delayed +// begin touch immediately as well as last touch signal + +#import <UIKit/UIKit.h> + +@interface GodotViewGestureRecognizer : UIGestureRecognizer + +- (instancetype)init; + +@end diff --git a/platform/iphone/godot_view_gesture_recognizer.m b/platform/iphone/godot_view_gesture_recognizer.m new file mode 100644 index 0000000000..377ccd52a5 --- /dev/null +++ b/platform/iphone/godot_view_gesture_recognizer.m @@ -0,0 +1,171 @@ +/*************************************************************************/ +/* godot_view_gesture_recognizer.m */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#import "godot_view_gesture_recognizer.h" + +// Using same delay interval that is used for `UIScrollView` +const NSTimeInterval kGLGestureDelayInterval = 0.150; + +// Minimum distance for touches to move to fire +// a delay timer before scheduled time. +// Should be the low enough to not cause issues with dragging +// but big enough to allow click to work. +const CGFloat kGLGestureMovementDistance = 0.5; + +@interface GodotViewGestureRecognizer () + +// Timer used to delay begin touch message. +// Should work as simple emulation of UIDelayedAction +@property(strong, nonatomic) NSTimer *delayTimer; + +// Delayed touch parameters +@property(strong, nonatomic) NSSet *delayedTouches; +@property(strong, nonatomic) UIEvent *delayedEvent; + +@end + +@implementation GodotViewGestureRecognizer + +- (instancetype)init { + self = [super init]; + + self.cancelsTouchesInView = YES; + self.delaysTouchesBegan = YES; + self.delaysTouchesEnded = YES; + + return self; +} + +- (void)dealloc { + if (self.delayTimer) { + [self.delayTimer invalidate]; + self.delayTimer = nil; + } + + if (self.delayedTouches) { + self.delayedTouches = nil; + } + + if (self.delayedEvent) { + self.delayedEvent = nil; + } + + [super dealloc]; +} + +- (void)delayTouches:(NSSet *)touches andEvent:(UIEvent *)event { + [self.delayTimer fire]; + + self.delayedTouches = touches; + self.delayedEvent = event; + + self.delayTimer = [NSTimer + scheduledTimerWithTimeInterval:kGLGestureDelayInterval + target:self + selector:@selector(fireDelayedTouches:) + userInfo:nil + repeats:NO]; +} + +- (void)fireDelayedTouches:(id)timer { + [self.delayTimer invalidate]; + self.delayTimer = nil; + + if (self.delayedTouches) { + [self.view touchesBegan:self.delayedTouches withEvent:self.delayedEvent]; + } + + self.delayedTouches = nil; + self.delayedEvent = nil; +} + +- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { + NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseBegan]; + [self delayTouches:cleared andEvent:event]; + [cleared release]; +} + +- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event { + NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseMoved]; + + if (self.delayTimer) { + // We should check if movement was significant enough to fire an event + // for dragging to work correctly. + for (UITouch *touch in cleared) { + CGPoint from = [touch locationInView:self.view]; + CGPoint to = [touch previousLocationInView:self.view]; + CGFloat xDistance = from.x - to.x; + CGFloat yDistance = from.y - to.y; + + CGFloat distance = sqrt(xDistance * xDistance + yDistance * yDistance); + + // Early exit, since one of touches has moved enough to fire a drag event. + if (distance > kGLGestureMovementDistance) { + [self.delayTimer fire]; + [self.view touchesMoved:cleared withEvent:event]; + [cleared release]; + return; + } + } + + [cleared release]; + return; + } + + [self.view touchesMoved:cleared withEvent:event]; + [cleared release]; +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { + [self.delayTimer fire]; + + NSSet *cleared = [self copyClearedTouches:touches phase:UITouchPhaseEnded]; + [self.view touchesEnded:cleared withEvent:event]; + [cleared release]; +} + +- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event { + [self.delayTimer fire]; + [self.view touchesCancelled:touches withEvent:event]; +}; + +- (NSSet *)copyClearedTouches:(NSSet *)touches phase:(UITouchPhase)phaseToSave { + NSMutableSet *cleared = [touches mutableCopy]; + + for (UITouch *touch in touches) { + if (touch.phase != phaseToSave) { + [cleared removeObject:touch]; + } + } + + return cleared; +} + +@end diff --git a/platform/osx/display_server_osx.mm b/platform/osx/display_server_osx.mm index 5e209a6e6b..ffe60ad582 100644 --- a/platform/osx/display_server_osx.mm +++ b/platform/osx/display_server_osx.mm @@ -2793,7 +2793,9 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo } break; case WINDOW_FLAG_BORDERLESS: { // OrderOut prevents a lose focus bug with the window - [wd.window_object orderOut:nil]; + if ([wd.window_object isVisible]) { + [wd.window_object orderOut:nil]; + } wd.borderless = p_enabled; if (p_enabled) { [wd.window_object setStyleMask:NSWindowStyleMaskBorderless]; @@ -2807,7 +2809,13 @@ void DisplayServerOSX::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo [wd.window_object setFrame:frameRect display:NO]; } _update_window(wd); - [wd.window_object makeKeyAndOrderFront:nil]; + if ([wd.window_object isVisible]) { + if (wd.no_focus) { + [wd.window_object orderFront:nil]; + } else { + [wd.window_object makeKeyAndOrderFront:nil]; + } + } } break; case WINDOW_FLAG_ALWAYS_ON_TOP: { wd.on_top = p_enabled; @@ -2875,7 +2883,11 @@ void DisplayServerOSX::window_move_to_foreground(WindowID p_window) { const WindowData &wd = windows[p_window]; [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; - [wd.window_object makeKeyAndOrderFront:nil]; + if (wd.no_focus) { + [wd.window_object orderFront:nil]; + } else { + [wd.window_object makeKeyAndOrderFront:nil]; + } } bool DisplayServerOSX::window_can_draw(WindowID p_window) const { diff --git a/tests/SCsub b/tests/SCsub index cb1d35b12f..9c32eb8ec3 100644 --- a/tests/SCsub +++ b/tests/SCsub @@ -3,7 +3,13 @@ Import("env") env.tests_sources = [] -env.add_source_files(env.tests_sources, "*.cpp") -lib = env.add_library("tests", env.tests_sources) +env_tests = env.Clone() + +# Enable test framework and inform it of configuration method. +env_tests.Append(CPPDEFINES=["DOCTEST_CONFIG_IMPLEMENT"]) + +env_tests.add_source_files(env.tests_sources, "*.cpp") + +lib = env_tests.add_library("tests", env.tests_sources) env.Prepend(LIBS=[lib]) |