1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-04 12:00:25 +00:00

Merge pull request #105518 from syntaxerror247/fixed-panel

Embed TouchActionsPanel directly into the Android editor UI
This commit is contained in:
Thaddeus Crews
2025-04-21 08:24:18 -05:00
6 changed files with 156 additions and 54 deletions

View File

@@ -1105,10 +1105,6 @@
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.
</member>
<member name="interface/touchscreen/enable_touch_actions_panel" type="bool" setter="" getter="">
If [code]true[/code], enables the TouchActionsPanel to provide easy access to keyboard shortcuts on touchscreen devices.
[b]Note:[/b] Only available in the Android editor.
</member>
<member name="interface/touchscreen/increase_scrollbar_touch_area" type="bool" setter="" getter="">
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.
@@ -1117,6 +1113,10 @@
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.
</member>
<member name="interface/touchscreen/touch_actions_panel" type="int" setter="" getter="">
A touch-friendly panel that provides easy access to common actions such as save, delete, undo, and redo without requiring a keyboard.
[b]Note:[/b] Only available in the Android and XR editor.
</member>
<member name="network/connection/check_for_updates" type="int" setter="" getter="">
Specifies how the engine should check for updates.
- [b]Disable Update Checks[/b] will block the engine from checking updates (see also [member network/connection/network_mode]).

View File

@@ -940,6 +940,11 @@ void EditorNode::_notification(int p_what) {
if (EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/theme/highlighting")) {
EditorHelpHighlighter::get_singleton()->reset_cache();
}
#endif
#ifdef ANDROID_ENABLED
if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/touchscreen/touch_actions_panel")) {
_touch_actions_panel_mode_changed();
}
#endif
} break;
}
@@ -7063,6 +7068,34 @@ void EditorNode::set_unfocused_low_processor_usage_mode_enabled(bool p_enabled)
unfocused_low_processor_usage_mode_enabled = p_enabled;
}
#ifdef ANDROID_ENABLED
void EditorNode::_touch_actions_panel_mode_changed() {
int panel_mode = EDITOR_GET("interface/touchscreen/touch_actions_panel");
switch (panel_mode) {
case 1:
if (touch_actions_panel != nullptr) {
touch_actions_panel->queue_free();
}
touch_actions_panel = memnew(TouchActionsPanel);
main_hbox->call_deferred("add_child", touch_actions_panel);
break;
case 2:
if (touch_actions_panel != nullptr) {
touch_actions_panel->queue_free();
}
touch_actions_panel = memnew(TouchActionsPanel);
call_deferred("add_child", touch_actions_panel);
break;
case 0:
if (touch_actions_panel != nullptr) {
touch_actions_panel->queue_free();
touch_actions_panel = nullptr;
}
break;
}
}
#endif
EditorNode::EditorNode() {
DEV_ASSERT(!singleton);
singleton = this;
@@ -7368,7 +7401,20 @@ EditorNode::EditorNode() {
gui_base->set_end(Point2(0, 0));
main_vbox = memnew(VBoxContainer);
#ifdef ANDROID_ENABLED
main_hbox = memnew(HBoxContainer);
main_hbox->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
main_hbox->add_child(main_vbox);
main_vbox->set_h_size_flags(Control::SIZE_EXPAND_FILL);
_touch_actions_panel_mode_changed();
gui_base->add_child(main_hbox);
#else
gui_base->add_child(main_vbox);
#endif
title_bar = memnew(EditorTitleBar);
main_vbox->add_child(title_bar);
@@ -7952,14 +7998,6 @@ EditorNode::EditorNode() {
_update_layouts_menu();
#ifdef ANDROID_ENABLED
// Add TouchActionsPanel node.
bool is_enabled = EDITOR_GET("interface/touchscreen/enable_touch_actions_panel");
if (is_enabled) {
add_child(memnew(TouchActionsPanel));
}
#endif
// Bottom panels.
bottom_panel = memnew(EditorBottomPanel);

View File

@@ -99,6 +99,11 @@ class ProjectSettingsEditor;
class SceneImportSettingsDialog;
class ProjectUpgradeTool;
#ifdef ANDROID_ENABLED
class HBoxContainer;
class TouchActionsPanel;
#endif
struct EditorProgress {
String task;
bool force_background = false;
@@ -276,6 +281,12 @@ private:
VBoxContainer *main_vbox = nullptr;
OptionButton *renderer = nullptr;
#ifdef ANDROID_ENABLED
HBoxContainer *main_hbox = nullptr; // Only created on Android for TouchActionsPanel.
TouchActionsPanel *touch_actions_panel = nullptr;
void _touch_actions_panel_mode_changed();
#endif
ConfirmationDialog *video_restart_dialog = nullptr;
int renderer_current = 0;

View File

@@ -584,10 +584,6 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/touchscreen/scale_gizmo_handles", has_touchscreen_ui ? 3 : 1, "1,5,1")
set_restart_if_changed("interface/touchscreen/scale_gizmo_handles", true);
// Only available in the Android editor.
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/enable_touch_actions_panel", true, "")
set_restart_if_changed("interface/touchscreen/enable_touch_actions_panel", true);
// Disable some touchscreen settings by default for the XR Editor.
bool is_native_touchscreen = has_touchscreen_ui && !OS::get_singleton()->has_feature("xr_editor");
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/enable_long_press_as_right_click", is_native_touchscreen, "")
@@ -595,6 +591,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/increase_scrollbar_touch_area", is_native_touchscreen, "")
set_restart_if_changed("interface/touchscreen/increase_scrollbar_touch_area", true);
// Only available in the Android editor.
String touch_actions_panel_hints = "Disabled:0,Embedded Panel:1,Floating Panel:2";
EDITOR_SETTING_BASIC(Variant::INT, PROPERTY_HINT_ENUM, "interface/touchscreen/touch_actions_panel", 1, touch_actions_panel_hints)
// Scene tabs
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/scene_tabs/display_close_button", 1, "Never,If Tab Active,Always"); // TabBar::CloseButtonDisplayPolicy
_initial_set("interface/scene_tabs/show_thumbnail_on_hover", true);

View File

@@ -44,14 +44,25 @@ void TouchActionsPanel::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
DisplayServer::get_singleton()->set_hardware_keyboard_connection_change_callback(callable_mp(this, &TouchActionsPanel::_hardware_keyboard_connected));
_hardware_keyboard_connected(DisplayServer::get_singleton()->has_hardware_keyboard());
if (!is_floating) {
get_parent()->move_child(this, embedded_panel_index);
}
} break;
case NOTIFICATION_VISIBILITY_CHANGED: {
set_process_input(is_visible_in_tree());
} break;
case NOTIFICATION_THEME_CHANGED: {
drag_handle->set_texture(get_editor_theme_icon(SNAME("DragHandle")));
layout_toggle_button->set_button_icon(get_editor_theme_icon(SNAME("Orientation")));
lock_panel_button->set_button_icon(get_editor_theme_icon(SNAME("Lock")));
if (is_floating) {
drag_handle->set_texture(get_editor_theme_icon(SNAME("DragHandle")));
layout_toggle_button->set_button_icon(get_editor_theme_icon(SNAME("Orientation")));
lock_panel_button->set_button_icon(get_editor_theme_icon(SNAME("Lock")));
} else {
if (embedded_panel_index == 1) {
panel_pos_button->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignLeftWide")));
} else {
panel_pos_button->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignRightWide")));
}
}
save_button->set_button_icon(get_editor_theme_icon(SNAME("Save")));
delete_button->set_button_icon(get_editor_theme_icon(SNAME("Remove")));
undo_button->set_button_icon(get_editor_theme_icon(SNAME("UndoRedo")));
@@ -154,7 +165,7 @@ void TouchActionsPanel::_add_new_modifier_button(Modifier p_modifier) {
}
void TouchActionsPanel::_on_drag_handle_gui_input(const Ref<InputEvent> &p_event) {
if (lock_panel_position) {
if (locked_panel) {
return;
}
Ref<InputEventMouseButton> mouse_button_event = p_event;
@@ -191,50 +202,87 @@ void TouchActionsPanel::_switch_layout() {
}
void TouchActionsPanel::_lock_panel_toggled(bool p_pressed) {
lock_panel_position = p_pressed;
layout_toggle_button->set_disabled(p_pressed);
locked_panel = p_pressed;
layout_toggle_button->set_visible(!p_pressed);
drag_handle->set_visible(!p_pressed);
reset_size();
queue_redraw();
}
void TouchActionsPanel::_switch_embedded_panel_side() {
if (embedded_panel_index == 0) {
embedded_panel_index = 1;
panel_pos_button->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignLeftWide")));
} else {
embedded_panel_index = 0;
panel_pos_button->set_button_icon(get_editor_theme_icon(SNAME("ControlAlignRightWide")));
}
get_parent()->move_child(this, embedded_panel_index); // Parent is a hbox with only two children -- TouchActionsPanel and main Editor UI.
EditorSettings::get_singleton()->set("_touch_actions_panel_embed_index", embedded_panel_index);
EditorSettings::get_singleton()->save();
}
TouchActionsPanel::TouchActionsPanel() {
Ref<StyleBoxFlat> panel_style;
panel_style.instantiate();
panel_style->set_bg_color(Color(0.1, 0.1, 0.1, 1));
panel_style->set_border_color(Color(0.3, 0.3, 0.3, 1));
panel_style->set_border_width_all(3);
panel_style->set_corner_radius_all(10);
panel_style->set_content_margin_all(12);
add_theme_style_override(SceneStringName(panel), panel_style);
int panel_mode = EDITOR_GET("interface/touchscreen/touch_actions_panel");
is_floating = panel_mode == 2;
set_position(EDITOR_DEF("_touch_actions_panel_position", Point2(480, 480))); // Dropped it here for no good reason — users can move it anyway.
if (is_floating) {
Ref<StyleBoxFlat> panel_style;
panel_style.instantiate();
panel_style->set_bg_color(Color(0.1, 0.1, 0.1, 1));
panel_style->set_border_color(Color(0.3, 0.3, 0.3, 1));
panel_style->set_border_width_all(3);
panel_style->set_corner_radius_all(10);
panel_style->set_content_margin_all(12);
add_theme_style_override(SceneStringName(panel), panel_style);
set_position(EDITOR_DEF("_touch_actions_panel_position", Point2(480, 480))); // Dropped it here for no good reason — users can move it anyway.
}
box = memnew(BoxContainer);
box->set_alignment(BoxContainer::ALIGNMENT_CENTER);
box->add_theme_constant_override("separation", 20);
box->set_vertical(EDITOR_DEF("_touch_actions_panel_vertical_layout", false));
if (is_floating) {
box->set_vertical(EDITOR_DEF("_touch_actions_panel_vertical_layout", false));
} else {
box->set_vertical(true);
}
add_child(box);
drag_handle = memnew(TextureRect);
drag_handle->set_custom_minimum_size(Size2(40, 40));
drag_handle->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
drag_handle->connect(SceneStringName(gui_input), callable_mp(this, &TouchActionsPanel::_on_drag_handle_gui_input));
box->add_child(drag_handle);
if (is_floating) {
drag_handle = memnew(TextureRect);
drag_handle->set_custom_minimum_size(Size2(40, 40));
drag_handle->set_stretch_mode(TextureRect::STRETCH_KEEP_CENTERED);
drag_handle->connect(SceneStringName(gui_input), callable_mp(this, &TouchActionsPanel::_on_drag_handle_gui_input));
box->add_child(drag_handle);
layout_toggle_button = memnew(Button);
layout_toggle_button->set_theme_type_variation("FlatMenuButton");
layout_toggle_button->set_accessibility_name(TTRC("Switch Layout"));
layout_toggle_button->set_focus_mode(FOCUS_NONE);
layout_toggle_button->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
layout_toggle_button->connect(SceneStringName(pressed), callable_mp(this, &TouchActionsPanel::_switch_layout));
box->add_child(layout_toggle_button);
layout_toggle_button = memnew(Button);
layout_toggle_button->set_theme_type_variation("FlatMenuButton");
layout_toggle_button->set_accessibility_name(TTRC("Switch Layout"));
layout_toggle_button->set_focus_mode(FOCUS_NONE);
layout_toggle_button->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
layout_toggle_button->connect(SceneStringName(pressed), callable_mp(this, &TouchActionsPanel::_switch_layout));
box->add_child(layout_toggle_button);
lock_panel_button = memnew(Button);
lock_panel_button->set_toggle_mode(true);
lock_panel_button->set_theme_type_variation("FlatMenuButton");
lock_panel_button->set_accessibility_name(TTRC("Lock Panel"));
lock_panel_button->set_focus_mode(FOCUS_NONE);
lock_panel_button->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
lock_panel_button->connect(SceneStringName(toggled), callable_mp(this, &TouchActionsPanel::_lock_panel_toggled));
box->add_child(lock_panel_button);
lock_panel_button = memnew(Button);
lock_panel_button->set_toggle_mode(true);
lock_panel_button->set_theme_type_variation("FlatMenuButton");
lock_panel_button->set_accessibility_name(TTRC("Lock Panel"));
lock_panel_button->set_focus_mode(FOCUS_NONE);
lock_panel_button->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
lock_panel_button->connect(SceneStringName(toggled), callable_mp(this, &TouchActionsPanel::_lock_panel_toggled));
box->add_child(lock_panel_button);
} else {
panel_pos_button = memnew(Button);
panel_pos_button->set_theme_type_variation("FlatMenuButton");
panel_pos_button->set_accessibility_name(TTRC("Switch Embedded Panel Position"));
panel_pos_button->set_focus_mode(FOCUS_NONE);
panel_pos_button->set_icon_alignment(HORIZONTAL_ALIGNMENT_CENTER);
panel_pos_button->connect(SceneStringName(pressed), callable_mp(this, &TouchActionsPanel::_switch_embedded_panel_side));
box->add_child(panel_pos_button);
embedded_panel_index = EDITOR_DEF("_touch_actions_panel_embed_index", 0);
}
ColorRect *separator = memnew(ColorRect);
separator->set_color(Color(0.5, 0.5, 0.5));

View File

@@ -52,8 +52,9 @@ private:
TextureRect *drag_handle = nullptr;
Button *layout_toggle_button = nullptr;
Button *lock_panel_button = nullptr;
Button *panel_pos_button = nullptr;
bool lock_panel_position = false;
bool locked_panel = false;
bool dragging = false;
Vector2 drag_offset;
@@ -67,6 +68,9 @@ private:
bool shift_btn_pressed = false;
bool alt_btn_pressed = false;
bool is_floating = false; // Embedded panel mode is default.
int embedded_panel_index = 0;
void _notification(int p_what);
virtual void input(const Ref<InputEvent> &event) override;
@@ -75,8 +79,9 @@ private:
void _on_drag_handle_gui_input(const Ref<InputEvent> &p_event);
void _switch_layout();
void _lock_panel_toggled(bool p_pressed);
Button *_add_new_action_button(const String &p_shortcut, const String &p_name, Key p_keycode = Key::NONE);
void _switch_embedded_panel_side();
Button *_add_new_action_button(const String &p_shortcut, const String &p_name, Key p_keycode = Key::NONE);
void _add_new_modifier_button(Modifier p_modifier);
void _on_modifier_button_toggled(bool p_pressed, int p_modifier);