diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index ebe96ddb7b6..12a975b75c0 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -510,10 +510,6 @@ The custom theme resource to use for the editor. Must be a Godot theme resource in [code].tres[/code] or [code].res[/code] format. - - If [code]true[/code], increases the touch area for the UI elements to improve usability on touchscreen devices. - [b]Note:[/b] Defaults to [code]true[/code] on touchscreen devices. - If [code]true[/code], makes the background of selected tabs more contrasted in the editor theme (brighter on dark themes, darker on light themes). @@ -532,6 +528,22 @@ If [code]true[/code], use colored header backgrounds for individual [GraphNode]s in the visual script and visual shader editors. This can improve usability when frequently using these editors at low zoom levels. + + If [code]true[/code], long press on touchscreen is treated as right click. + [b]Note:[/b] Defaults to [code]true[/code] on touchscreen devices. + + + If [code]true[/code], enable two finger pan and scale gestures on touchscreen devices. + [b]Note:[/b] Defaults to [code]true[/code] on touchscreen devices. + + + If [code]true[/code], increases the scrollbar touch area to improve usability on touchscreen devices. + [b]Note:[/b] Defaults to [code]true[/code] on touchscreen devices. + + + Specify the multiplier to apply to the scale for the editor gizmo handles to improve usability on touchscreen devices. + [b]Note:[/b] Defaults to [code]1[/code] on non-touchscreen devices. + The address to listen to when starting the remote debugger. This can be set to [code]0.0.0.0[/code] to allow external clients to connect to the remote debugger (instead of restricting the remote debugger to connections from [code]localhost[/code]). diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 3b302baf4b2..059359991b8 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -348,7 +348,6 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { // Theme _initial_set("interface/theme/preset", "Default"); hints["interface/theme/preset"] = PropertyInfo(Variant::STRING, "interface/theme/preset", PROPERTY_HINT_ENUM, "Default,Alien,Arc,Godot 2,Grey,Light,Solarized (Dark),Solarized (Light),Custom", PROPERTY_USAGE_DEFAULT); - _initial_set("interface/theme/enable_touchscreen_touch_area", OS::get_singleton()->has_touchscreen_ui_hint()); _initial_set("interface/theme/icon_and_font_color", 0); hints["interface/theme/icon_and_font_color"] = PropertyInfo(Variant::INT, "interface/theme/icon_and_font_color", PROPERTY_HINT_ENUM, "Auto,Dark,Light", PROPERTY_USAGE_DEFAULT); _initial_set("interface/theme/base_color", Color(0.2, 0.23, 0.31)); @@ -368,6 +367,16 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { _initial_set("interface/theme/custom_theme", ""); hints["interface/theme/custom_theme"] = PropertyInfo(Variant::STRING, "interface/theme/custom_theme", PROPERTY_HINT_GLOBAL_FILE, "*.res,*.tres,*.theme", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_RESTART_IF_CHANGED); + // Touchscreen + bool has_touchscreen_ui = OS::get_singleton()->has_touchscreen_ui_hint(); + _initial_set("interface/touchscreen/increase_scrollbar_touch_area", has_touchscreen_ui); + _initial_set("interface/touchscreen/enable_long_press_as_right_click", has_touchscreen_ui); + set_restart_if_changed("interface/touchscreen/enable_long_press_as_right_click", true); + _initial_set("interface/touchscreen/enable_pan_and_scale_gestures", has_touchscreen_ui); + set_restart_if_changed("interface/touchscreen/enable_pan_and_scale_gestures", true); + _initial_set("interface/touchscreen/scale_gizmo_handles", has_touchscreen_ui ? 3 : 1); + hints["interface/touchscreen/scale_gizmo_handles"] = PropertyInfo(Variant::REAL, "interface/touchscreen/scale_gizmo_handles", PROPERTY_HINT_RANGE, "1,5,1"); + // Scene tabs _initial_set("interface/scene_tabs/show_thumbnail_on_hover", true); _initial_set("interface/scene_tabs/resize_if_many_tabs", true); @@ -613,7 +622,7 @@ void EditorSettings::_load_defaults(Ref p_extra_config) { _initial_set("editors/2d/pan_speed", 20); // Polygon editor - _initial_set("editors/poly_editor/point_grab_radius", 8); + _initial_set("editors/poly_editor/point_grab_radius", has_touchscreen_ui ? 32 : 8); _initial_set("editors/poly_editor/show_previous_outline", true); // Animation diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index b1206f96cef..7f6cfcfa9e3 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -134,6 +134,27 @@ static Ref editor_generate_icon(int p_index, bool p_convert_color, #define ADD_CONVERT_COLOR(dictionary, old_color, new_color) dictionary[Color::html(old_color)] = Color::html(new_color) #endif +float get_gizmo_handle_scale(const String &gizmo_handle_name = "") { + const float scale_gizmo_handles_for_touch = EDITOR_GET("interface/touchscreen/scale_gizmo_handles"); + if (scale_gizmo_handles_for_touch > 1.0f) { + // The names of the icons that require custom scaling. + static Set gizmo_to_scale; + if (gizmo_to_scale.empty()) { + gizmo_to_scale.insert("EditorHandle"); + gizmo_to_scale.insert("EditorHandleAdd"); + gizmo_to_scale.insert("EditorCurveHandle"); + gizmo_to_scale.insert("EditorPathSharpHandle"); + gizmo_to_scale.insert("EditorPathSmoothHandle"); + } + + if (gizmo_to_scale.has(gizmo_handle_name)) { + return EDSCALE * scale_gizmo_handles_for_touch; + } + } + + return EDSCALE; +} + void editor_register_and_generate_icons(Ref p_theme, bool p_dark_theme = true, int p_thumb_size = 32, bool p_only_thumbs = false) { OS::get_singleton()->benchmark_begin_measure("editor_register_and_generate_icons_" + String((p_only_thumbs ? "with_only_thumbs" : "all"))); #ifdef MODULE_SVG_ENABLED @@ -258,10 +279,11 @@ void editor_register_and_generate_icons(Ref p_theme, bool p_dark_theme = // Generate icons. if (!p_only_thumbs) { for (int i = 0; i < editor_icons_count; i++) { - const int is_exception = exceptions.has(editor_icons_names[i]); - const Ref icon = editor_generate_icon(i, !is_exception); + const String &editor_icon_name = editor_icons_names[i]; + const int is_exception = exceptions.has(editor_icon_name); + const Ref icon = editor_generate_icon(i, !is_exception, get_gizmo_handle_scale(editor_icon_name)); - p_theme->set_icon(editor_icons_names[i], "EditorIcons", icon); + p_theme->set_icon(editor_icon_name, "EditorIcons", icon); } } @@ -309,7 +331,8 @@ Ref create_editor_theme(const Ref p_theme) { String preset = EDITOR_GET("interface/theme/preset"); - bool enable_touchscreen_touch_area = EDITOR_GET("interface/theme/enable_touchscreen_touch_area"); + bool increase_scrollbar_touch_area = EDITOR_GET("interface/touchscreen/increase_scrollbar_touch_area"); + const float gizmo_handle_scale = EDITOR_GET("interface/touchscreen/scale_gizmo_handles"); bool highlight_tabs = EDITOR_GET("interface/theme/highlight_tabs"); int border_size = EDITOR_GET("interface/theme/border_size"); @@ -450,11 +473,18 @@ Ref create_editor_theme(const Ref p_theme) { theme->set_constant("scale", "Editor", EDSCALE); theme->set_constant("thumb_size", "Editor", thumb_size); theme->set_constant("dark_theme", "Editor", dark_theme); + theme->set_constant("gizmo_handle_scale", "Editor", gizmo_handle_scale); //Register icons + font + bool keep_old_icons = false; + if (p_theme != nullptr) { + keep_old_icons = fabs(p_theme->get_constant("scale", "Editor") - EDSCALE) < 0.00001 && + fabs(p_theme->get_constant("gizmo_handle_scale", "Editor") - gizmo_handle_scale) < 0.00001 && + (bool)p_theme->get_constant("dark_theme", "Editor") == dark_theme; + } // the resolution and the icon color (dark_theme bool) has not changed, so we do not regenerate the icons - if (p_theme != nullptr && fabs(p_theme->get_constant("scale", "Editor") - EDSCALE) < 0.00001 && (bool)p_theme->get_constant("dark_theme", "Editor") == dark_theme) { + if (keep_old_icons) { // register already generated icons for (int i = 0; i < editor_icons_count; i++) { theme->set_icon(editor_icons_names[i], "EditorIcons", p_theme->get_icon(editor_icons_names[i], "EditorIcons")); @@ -1054,7 +1084,7 @@ Ref create_editor_theme(const Ref p_theme) { // HScrollBar Ref empty_icon = memnew(ImageTexture); - if (enable_touchscreen_touch_area) { + if (increase_scrollbar_touch_area) { theme->set_stylebox("scroll", "HScrollBar", make_line_stylebox(separator_color, 50)); } else { theme->set_stylebox("scroll", "HScrollBar", make_stylebox(theme->get_icon("GuiScrollBg", "EditorIcons"), 5, 5, 5, 5, 0, 0, 0, 0)); @@ -1072,7 +1102,7 @@ Ref create_editor_theme(const Ref p_theme) { theme->set_icon("decrement_pressed", "HScrollBar", empty_icon); // VScrollBar - if (enable_touchscreen_touch_area) { + if (increase_scrollbar_touch_area) { theme->set_stylebox("scroll", "VScrollBar", make_line_stylebox(separator_color, 50, 1, 1, true)); } else { theme->set_stylebox("scroll", "VScrollBar", make_stylebox(theme->get_icon("GuiScrollBg", "EditorIcons"), 5, 5, 5, 5, 0, 0, 0, 0)); diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index 95a3b1c782d..824cd6ef784 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -343,7 +343,7 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref &p_e if (mb->get_button_index() == BUTTON_LEFT) { if (mb->is_pressed()) { for (int i = 0; i < handles.size(); i++) { - if (xform.xform(handles[i]).distance_to(gpoint) < 8) { + if (xform.xform(handles[i]).distance_to(gpoint) < grab_threshold) { edit_handle = i; break; @@ -557,6 +557,10 @@ void CollisionShape2DEditor::_notification(int p_what) { case NOTIFICATION_EXIT_TREE: { get_tree()->disconnect("node_removed", this, "_node_removed"); } break; + + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); + } break; } } @@ -594,6 +598,7 @@ CollisionShape2DEditor::CollisionShape2DEditor(EditorNode *p_editor) { edit_handle = -1; pressed = false; + grab_threshold = EDITOR_GET("editors/poly_editor/point_grab_radius"); } void CollisionShape2DEditorPlugin::edit(Object *p_obj) { diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h index d952620d2a4..978216981b5 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.h +++ b/editor/plugins/collision_shape_2d_editor_plugin.h @@ -75,6 +75,7 @@ class CollisionShape2DEditor : public Control { int shape_type; int edit_handle; bool pressed; + real_t grab_threshold = 8; Variant original; Transform2D original_transform; Point2 last_point; diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index cfd90f88f67..7ac1a64efa5 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -44,6 +44,7 @@ CurveEditor::CurveEditor() { _tangents_length = 40; _dragging = false; _has_undo_data = false; + _gizmo_handle_scale = EDITOR_GET("interface/touchscreen/scale_gizmo_handles"); set_focus_mode(FOCUS_ALL); set_clip_contents(true); @@ -96,8 +97,13 @@ Size2 CurveEditor::get_minimum_size() const { } void CurveEditor::_notification(int p_what) { - if (p_what == NOTIFICATION_DRAW) { - _draw(); + switch (p_what) { + case NOTIFICATION_DRAW: { + _draw(); + } break; + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + _gizmo_handle_scale = EDITOR_GET("interface/touchscreen/scale_gizmo_handles"); + } break; } } @@ -391,7 +397,7 @@ int CurveEditor::get_point_at(Vector2 pos) const { } const Curve &curve = **_curve_ref; - const float true_hover_radius = Math::round(_hover_radius * EDSCALE); + const float true_hover_radius = Math::round(_hover_radius * _gizmo_handle_scale * EDSCALE); const float r = true_hover_radius * true_hover_radius; for (int i = 0; i < curve.get_point_count(); ++i) { @@ -411,14 +417,14 @@ CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const { if (_selected_point != 0) { Vector2 control_pos = get_tangent_view_pos(_selected_point, TANGENT_LEFT); - if (control_pos.distance_to(pos) < _hover_radius) { + if (control_pos.distance_to(pos) < _hover_radius * _gizmo_handle_scale) { return TANGENT_LEFT; } } if (_selected_point != _curve_ref->get_point_count() - 1) { Vector2 control_pos = get_tangent_view_pos(_selected_point, TANGENT_RIGHT); - if (control_pos.distance_to(pos) < _hover_radius) { + if (control_pos.distance_to(pos) < _hover_radius * _gizmo_handle_scale) { return TANGENT_RIGHT; } } @@ -555,7 +561,7 @@ Vector2 CurveEditor::get_tangent_view_pos(int i, TangentIndex tangent) const { Vector2 point_pos = get_view_pos(_curve_ref->get_point_position(i)); Vector2 control_pos = get_view_pos(_curve_ref->get_point_position(i) + dir); - return point_pos + Math::round(_tangents_length * EDSCALE) * (control_pos - point_pos).normalized(); + return point_pos + Math::round(_tangents_length * _gizmo_handle_scale * EDSCALE) * (control_pos - point_pos).normalized(); } Vector2 CurveEditor::get_view_pos(Vector2 world_pos) const { @@ -699,13 +705,13 @@ void CurveEditor::_draw() { if (i != 0) { Vector2 control_pos = get_tangent_view_pos(i, TANGENT_LEFT); draw_line(get_view_pos(pos), control_pos, tangent_color, Math::round(EDSCALE), true); - draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(Math::round(2 * EDSCALE)), tangent_color); + draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(Math::round(2 * _gizmo_handle_scale * EDSCALE)), tangent_color); } if (i != curve.get_point_count() - 1) { Vector2 control_pos = get_tangent_view_pos(i, TANGENT_RIGHT); draw_line(get_view_pos(pos), control_pos, tangent_color, Math::round(EDSCALE), true); - draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(Math::round(2 * EDSCALE)), tangent_color); + draw_rect(Rect2(control_pos, Vector2(1, 1)).grow(Math::round(2 * _gizmo_handle_scale * EDSCALE)), tangent_color); } } @@ -728,7 +734,7 @@ void CurveEditor::_draw() { for (int i = 0; i < curve.get_point_count(); ++i) { Vector2 pos = curve.get_point_position(i); - draw_rect(Rect2(get_view_pos(pos), Vector2(1, 1)).grow(Math::round(3 * EDSCALE)), i == _selected_point ? selected_point_color : point_color); + draw_rect(Rect2(get_view_pos(pos), Vector2(1, 1)).grow(Math::round(3 * _gizmo_handle_scale * EDSCALE)), i == _selected_point ? selected_point_color : point_color); // TODO Circles are prettier. Needs a fix! Or a texture //draw_circle(pos, 2, point_color); } @@ -738,7 +744,7 @@ void CurveEditor::_draw() { if (_hover_point != -1) { const Color hover_color = line_color; Vector2 pos = curve.get_point_position(_hover_point); - draw_rect(Rect2(get_view_pos(pos), Vector2(1, 1)).grow(Math::round(_hover_radius * EDSCALE)), hover_color, false, Math::round(EDSCALE)); + draw_rect(Rect2(get_view_pos(pos), Vector2(1, 1)).grow(Math::round(_hover_radius * _gizmo_handle_scale * EDSCALE)), hover_color, false, Math::round(EDSCALE)); } // Help text diff --git a/editor/plugins/curve_editor_plugin.h b/editor/plugins/curve_editor_plugin.h index 819e4d95df4..8ffe9b478bf 100644 --- a/editor/plugins/curve_editor_plugin.h +++ b/editor/plugins/curve_editor_plugin.h @@ -117,6 +117,7 @@ private: // Constant float _hover_radius; float _tangents_length; + float _gizmo_handle_scale = 1.0; }; class EditorInspectorPluginCurve : public EditorInspectorPlugin { diff --git a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt index 239047f2c83..8b6efd572f6 100644 --- a/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt +++ b/platform/android/java/editor/src/main/java/org/godotengine/editor/GodotEditor.kt @@ -40,6 +40,7 @@ import android.util.Log import android.widget.Toast import androidx.window.layout.WindowMetricsCalculator import org.godotengine.godot.FullScreenGodotApp +import org.godotengine.godot.GodotLib import org.godotengine.godot.utils.PermissionsUtil import org.godotengine.godot.utils.ProcessPhoenix import java.util.* @@ -90,11 +91,19 @@ open class GodotEditor : FullScreenGodotApp() { } super.onCreate(savedInstanceState) + } - // Enable long press, panning and scaling gestures - godotFragment?.renderView?.inputHandler?.apply { - enableLongPress(enableLongPressGestures()) - enablePanningAndScalingGestures(enablePanAndScaleGestures()) + override fun onGodotSetupCompleted() { + super.onGodotSetupCompleted() + val longPressEnabled = enableLongPressGestures() + val panScaleEnabled = enablePanAndScaleGestures() + + runOnUiThread { + // Enable long press, panning and scaling gestures + godotFragment?.renderView?.inputHandler?.apply { + enableLongPress(longPressEnabled) + enablePanningAndScalingGestures(panScaleEnabled) + } } } @@ -213,12 +222,14 @@ open class GodotEditor : FullScreenGodotApp() { /** * Enable long press gestures for the Godot Android editor. */ - protected open fun enableLongPressGestures() = true + protected open fun enableLongPressGestures() = + java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/enable_long_press_as_right_click")) /** * Enable pan and scale gestures for the Godot Android editor. */ - protected open fun enablePanAndScaleGestures() = true + protected open fun enablePanAndScaleGestures() = + java.lang.Boolean.parseBoolean(GodotLib.getEditorSetting("interface/touchscreen/enable_pan_and_scale_gestures")) override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index f03f918dd3f..40eed7ec781 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -179,6 +179,13 @@ public class GodotLib { */ public static native String getGlobal(String p_key); + /** + * Used to access Godot's editor settings. + * @param settingKey Setting key + * @return String value of the setting + */ + public static native String getEditorSetting(String settingKey); + /** * Invoke method |p_method| on the Godot object specified by |p_id| * @param p_id Id of the Godot object to invoke diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp index 04c221e74c3..f8179170c1d 100644 --- a/platform/android/java_godot_lib_jni.cpp +++ b/platform/android/java_godot_lib_jni.cpp @@ -53,6 +53,10 @@ #include #include +#ifdef TOOLS_ENABLED +#include "editor/editor_settings.h" +#endif + static JavaClassWrapper *java_class_wrapper = nullptr; static OS_Android *os_android = nullptr; static AndroidInputHandler *input_handler = nullptr; @@ -449,6 +453,18 @@ JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv * return env->NewStringUTF(ProjectSettings::get_singleton()->get(js).operator String().utf8().get_data()); } +JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getEditorSetting(JNIEnv *env, jclass clazz, jstring p_setting_key) { + String editor_setting = ""; +#ifdef TOOLS_ENABLED + String godot_setting_key = jstring_to_string(p_setting_key, env); + editor_setting = EDITOR_GET(godot_setting_key).operator String(); +#else + WARN_PRINT("Access to the Editor Settings in only available on Editor builds"); +#endif + + return env->NewStringUTF(editor_setting.utf8().get_data()); +} + JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params) { Object *obj = ObjectDB::get_instance(ID); ERR_FAIL_NULL(obj); diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h index cc1f2450a9e..c699efdef9d 100644 --- a/platform/android/java_godot_lib_jni.h +++ b/platform/android/java_godot_lib_jni.h @@ -61,6 +61,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_gyroscope(JNIEnv *env JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusin(JNIEnv *env, jclass clazz); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_focusout(JNIEnv *env, jclass clazz); JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getGlobal(JNIEnv *env, jclass clazz, jstring path); +JNIEXPORT jstring JNICALL Java_org_godotengine_godot_GodotLib_getEditorSetting(JNIEnv *env, jclass clazz, jstring p_setting_key); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_callobject(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_calldeferred(JNIEnv *env, jclass clazz, jlong ID, jstring method, jobjectArray params); JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_setVirtualKeyboardHeight(JNIEnv *env, jclass clazz, jint p_height);