diff options
| -rw-r--r-- | core/input/input.cpp | 25 | ||||
| -rw-r--r-- | doc/classes/Button.xml | 5 | ||||
| -rw-r--r-- | doc/classes/EditorSettings.xml | 4 | ||||
| -rw-r--r-- | editor/editor_node.cpp | 4 | ||||
| -rw-r--r-- | editor/editor_settings.cpp | 3 | ||||
| -rw-r--r-- | editor/editor_themes.cpp | 41 | ||||
| -rw-r--r-- | editor/plugins/collision_shape_2d_editor_plugin.cpp | 13 | ||||
| -rw-r--r-- | editor/plugins/collision_shape_2d_editor_plugin.h | 3 | ||||
| -rw-r--r-- | editor/plugins/curve_editor_plugin.cpp | 22 | ||||
| -rw-r--r-- | editor/plugins/curve_editor_plugin.h | 1 | ||||
| -rw-r--r-- | editor/plugins/tiles/tile_map_editor.cpp | 14 | ||||
| -rw-r--r-- | editor/plugins/visual_shader_editor_plugin.cpp | 151 | ||||
| -rw-r--r-- | editor/plugins/visual_shader_editor_plugin.h | 4 | ||||
| -rw-r--r-- | modules/openxr/action_map/openxr_action_map.cpp | 4 | ||||
| -rw-r--r-- | modules/openxr/extensions/openxr_htc_controller_extension.cpp | 3 | ||||
| -rw-r--r-- | scene/gui/button.cpp | 69 | ||||
| -rw-r--r-- | scene/gui/button.h | 5 | ||||
| -rw-r--r-- | scene/gui/color_picker.cpp | 33 | ||||
| -rw-r--r-- | scene/resources/visual_shader.cpp | 30 | ||||
| -rw-r--r-- | scene/resources/visual_shader.h | 6 |
20 files changed, 316 insertions, 124 deletions
diff --git a/core/input/input.cpp b/core/input/input.cpp index e74523e059..5aef9a9039 100644 --- a/core/input/input.cpp +++ b/core/input/input.cpp @@ -35,6 +35,10 @@ #include "core/input/input_map.h" #include "core/os/os.h" +#ifdef DEV_ENABLED +#include "core/os/thread.h" +#endif + static const char *_joy_buttons[(size_t)JoyButton::SDL_MAX] = { "a", "b", @@ -486,6 +490,10 @@ Vector3 Input::get_gyroscope() const { } void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_emulated) { + // This function does the final delivery of the input event to user land. + // Regardless where the event came from originally, this has to happen on the main thread. + DEV_ASSERT(Thread::get_caller_id() == Thread::get_main_id()); + // Notes on mouse-touch emulation: // - Emulated mouse events are parsed, that is, re-routed to this method, so they make the same effects // as true mouse events. The only difference is the situation is flagged as emulated so they are not @@ -537,7 +545,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em touch_event->set_position(mb->get_position()); touch_event->set_double_tap(mb->is_double_click()); touch_event->set_device(InputEvent::DEVICE_ID_EMULATION); + _THREAD_SAFE_UNLOCK_ event_dispatch_function(touch_event); + _THREAD_SAFE_LOCK_ } } @@ -563,7 +573,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em drag_event->set_velocity(get_last_mouse_velocity()); drag_event->set_device(InputEvent::DEVICE_ID_EMULATION); + _THREAD_SAFE_UNLOCK_ event_dispatch_function(drag_event); + _THREAD_SAFE_LOCK_ } } @@ -664,7 +676,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em if (ge.is_valid()) { if (event_dispatch_function) { + _THREAD_SAFE_UNLOCK_ event_dispatch_function(ge); + _THREAD_SAFE_LOCK_ } } @@ -687,7 +701,9 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em } if (event_dispatch_function) { + _THREAD_SAFE_UNLOCK_ event_dispatch_function(p_event); + _THREAD_SAFE_LOCK_ } } @@ -937,8 +953,15 @@ void Input::flush_buffered_events() { _THREAD_SAFE_METHOD_ while (buffered_events.front()) { - _parse_input_event_impl(buffered_events.front()->get(), false); + // The final delivery of the input event involves releasing the lock. + // While the lock is released, another thread may lock it and add new events to the back. + // Therefore, we get each event and pop it while we still have the lock, + // to ensure the list is in a consistent state. + List<Ref<InputEvent>>::Element *E = buffered_events.front(); + Ref<InputEvent> e = E->get(); buffered_events.pop_front(); + + _parse_input_event_impl(e, false); } } diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml index ec2447dbbc..1bf5c31818 100644 --- a/doc/classes/Button.xml +++ b/doc/classes/Button.xml @@ -58,7 +58,7 @@ To edit margin and spacing of the icon, use [theme_item h_separation] theme property and [code]content_margin_*[/code] properties of the used [StyleBox]es. </member> <member name="icon_alignment" type="int" setter="set_icon_alignment" getter="get_icon_alignment" enum="HorizontalAlignment" default="0"> - Specifies if the icon should be aligned to the left, right, or center of a button. Uses the same [enum HorizontalAlignment] constants as the text alignment. If centered, text will draw on top of the icon. + Specifies if the icon should be aligned horizontally to the left, right, or center of a button. Uses the same [enum HorizontalAlignment] constants as the text alignment. If centered horizontally and vertically, text will draw on top of the icon. </member> <member name="language" type="String" setter="set_language" getter="get_language" default=""""> Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead. @@ -72,6 +72,9 @@ <member name="text_overrun_behavior" type="int" setter="set_text_overrun_behavior" getter="get_text_overrun_behavior" enum="TextServer.OverrunBehavior" default="0"> Sets the clipping behavior when the text exceeds the node's bounding rectangle. See [enum TextServer.OverrunBehavior] for a description of all modes. </member> + <member name="vertical_icon_alignment" type="int" setter="set_vertical_icon_alignment" getter="get_vertical_icon_alignment" enum="VerticalAlignment" default="1"> + Specifies if the icon should be aligned vertically to the top, bottom, or center of a button. Uses the same [enum VerticalAlignment] constants as the text alignment. If centered horizontally and vertically, text will draw on top of the icon. + </member> </members> <theme_items> <theme_item name="font_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)"> diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml index e5500bd1ff..8c27c1bc06 100644 --- a/doc/classes/EditorSettings.xml +++ b/doc/classes/EditorSettings.xml @@ -644,6 +644,10 @@ 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. </member> + <member name="interface/touchscreen/scale_gizmo_handles" type="float" setter="" getter=""> + 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="network/debug/remote_host" type="String" setter="" getter=""> 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]). </member> diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp index f32c49c037..864d45230a 100644 --- a/editor/editor_node.cpp +++ b/editor/editor_node.cpp @@ -762,7 +762,9 @@ void EditorNode::_notification(int p_what) { EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/theme") || EditorSettings::get_singleton()->check_changed_settings_in_group("text_editor/help/help") || EditorSettings::get_singleton()->check_changed_settings_in_group("filesystem/file_dialog/thumbnail_size") || - EditorSettings::get_singleton()->check_changed_settings_in_group("run/output/font_size"); + EditorSettings::get_singleton()->check_changed_settings_in_group("run/output/font_size") || + EditorSettings::get_singleton()->check_changed_settings_in_group("interface/touchscreen/increase_scrollbar_touch_area") || + EditorSettings::get_singleton()->check_changed_settings_in_group("interface/touchscreen/scale_gizmo_handles"); if (theme_changed) { theme = create_custom_theme(theme_base->get_theme()); diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp index 9a6302b695..9577cd0e63 100644 --- a/editor/editor_settings.cpp +++ b/editor/editor_settings.cpp @@ -477,6 +477,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { set_restart_if_changed("interface/touchscreen/enable_long_press_as_right_click", true); EDITOR_SETTING(Variant::BOOL, PROPERTY_HINT_NONE, "interface/touchscreen/enable_pan_and_scale_gestures", has_touchscreen_ui, "") set_restart_if_changed("interface/touchscreen/enable_pan_and_scale_gestures", true); + EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "interface/touchscreen/scale_gizmo_handles", has_touchscreen_ui ? 3 : 1, "1,5,1") // Scene tabs EDITOR_SETTING(Variant::INT, PROPERTY_HINT_ENUM, "interface/scene_tabs/display_close_button", 1, "Never,If Tab Active,Always"); // TabBar::CloseButtonDisplayPolicy @@ -696,7 +697,7 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) { _initial_set("editors/tiles_editor/grid_color", Color(1.0, 0.5, 0.2, 0.5)); // Polygon editor - _initial_set("editors/polygon_editor/point_grab_radius", 8); + _initial_set("editors/polygon_editor/point_grab_radius", has_touchscreen_ui ? 32 : 8); _initial_set("editors/polygon_editor/show_previous_outline", true); // Animation diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp index 1a8a216605..1b5144af67 100644 --- a/editor/editor_themes.cpp +++ b/editor/editor_themes.cpp @@ -255,6 +255,28 @@ static Ref<ImageTexture> editor_generate_icon(int p_index, float p_scale, float return ImageTexture::create_from_image(img); } +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 additional scaling. + static HashSet<StringName> gizmo_to_scale; + if (gizmo_to_scale.is_empty()) { + gizmo_to_scale.insert("EditorHandle"); + gizmo_to_scale.insert("EditorHandleAdd"); + gizmo_to_scale.insert("EditorHandleDisabled"); + 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<Theme> p_theme, bool p_dark_theme, float p_icon_saturation, int p_thumb_size, bool p_only_thumbs = false) { // Before we register the icons, we adjust their colors and saturation. // Most icons follow the standard rules for color conversion to follow the editor @@ -314,22 +336,23 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme, f for (int i = 0; i < editor_icons_count; i++) { Ref<ImageTexture> icon; - if (accent_color_icons.has(editor_icons_names[i])) { - icon = editor_generate_icon(i, EDSCALE, 1.0, accent_color_map); + const String &editor_icon_name = editor_icons_names[i]; + if (accent_color_icons.has(editor_icon_name)) { + icon = editor_generate_icon(i, get_gizmo_handle_scale(editor_icon_name), 1.0, accent_color_map); } else { float saturation = p_icon_saturation; - if (saturation_exceptions.has(editor_icons_names[i])) { + if (saturation_exceptions.has(editor_icon_name)) { saturation = 1.0; } - if (conversion_exceptions.has(editor_icons_names[i])) { - icon = editor_generate_icon(i, EDSCALE, saturation); + if (conversion_exceptions.has(editor_icon_name)) { + icon = editor_generate_icon(i, get_gizmo_handle_scale(editor_icon_name), saturation); } else { - icon = editor_generate_icon(i, EDSCALE, saturation, color_conversion_map); + icon = editor_generate_icon(i, get_gizmo_handle_scale(editor_icon_name), saturation, color_conversion_map); } } - p_theme->set_icon(editor_icons_names[i], SNAME("EditorIcons"), icon); + p_theme->set_icon(editor_icon_name, SNAME("EditorIcons"), icon); } } @@ -395,6 +418,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { Color base_color = EDITOR_GET("interface/theme/base_color"); float contrast = EDITOR_GET("interface/theme/contrast"); 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 draw_extra_borders = EDITOR_GET("interface/theme/draw_extra_borders"); float icon_saturation = EDITOR_GET("interface/theme/icon_saturation"); float relationship_line_opacity = EDITOR_GET("interface/theme/relationship_line_opacity"); @@ -594,6 +618,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { theme->set_constant("class_icon_size", "Editor", 16 * EDSCALE); theme->set_constant("dark_theme", "Editor", dark_theme); theme->set_constant("color_picker_button_height", "Editor", 28 * EDSCALE); + theme->set_constant("gizmo_handle_scale", "Editor", gizmo_handle_scale); // Register editor icons. // If the settings are comparable to the old theme, then just copy them over. @@ -609,8 +634,10 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) { const bool prev_dark_theme = (bool)p_theme->get_constant(SNAME("dark_theme"), SNAME("Editor")); const Color prev_accent_color = p_theme->get_color(SNAME("accent_color"), SNAME("Editor")); const float prev_icon_saturation = p_theme->get_color(SNAME("icon_saturation"), SNAME("Editor")).r; + const float prev_gizmo_handle_scale = (float)p_theme->get_constant(SNAME("gizmo_handle_scale"), SNAME("Editor")); keep_old_icons = (Math::is_equal_approx(prev_scale, EDSCALE) && + Math::is_equal_approx(prev_gizmo_handle_scale, gizmo_handle_scale) && prev_dark_theme == dark_theme && prev_accent_color == accent_color && prev_icon_saturation == icon_saturation); diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp index 0aef364c2d..15c40a5cb3 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.cpp +++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp @@ -33,6 +33,7 @@ #include "canvas_item_editor_plugin.h" #include "core/os/keyboard.h" #include "editor/editor_node.h" +#include "editor/editor_settings.h" #include "editor/editor_undo_redo_manager.h" #include "scene/resources/capsule_shape_2d.h" #include "scene/resources/circle_shape_2d.h" @@ -44,6 +45,10 @@ #include "scene/resources/world_boundary_shape_2d.h" #include "scene/scene_string_names.h" +CollisionShape2DEditor::CollisionShape2DEditor() { + grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius"); +} + void CollisionShape2DEditor::_node_removed(Node *p_node) { if (p_node == node) { node = nullptr; @@ -307,7 +312,7 @@ bool CollisionShape2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e if (mb->get_button_index() == MouseButton::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; @@ -529,6 +534,12 @@ void CollisionShape2DEditor::_notification(int p_what) { _shape_changed(); } } break; + + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + if (EditorSettings::get_singleton()->check_changed_settings_in_group("editors/polygon_editor/point_grab_radius")) { + grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius"); + } + } break; } } diff --git a/editor/plugins/collision_shape_2d_editor_plugin.h b/editor/plugins/collision_shape_2d_editor_plugin.h index 13a99ec6f3..d58f5d511f 100644 --- a/editor/plugins/collision_shape_2d_editor_plugin.h +++ b/editor/plugins/collision_shape_2d_editor_plugin.h @@ -69,6 +69,7 @@ class CollisionShape2DEditor : public Control { int shape_type = -1; int edit_handle = -1; bool pressed = false; + real_t grab_threshold = 8; Variant original; Transform2D original_transform; Vector2 original_point; @@ -90,6 +91,8 @@ public: bool forward_canvas_gui_input(const Ref<InputEvent> &p_event); void forward_canvas_draw_over_viewport(Control *p_overlay); void edit(Node *p_node); + + CollisionShape2DEditor(); }; class CollisionShape2DEditorPlugin : public EditorPlugin { diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp index ba2d7e67bf..72cd1da9dd 100644 --- a/editor/plugins/curve_editor_plugin.cpp +++ b/editor/plugins/curve_editor_plugin.cpp @@ -49,6 +49,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); @@ -105,6 +106,11 @@ void CurveEditor::_notification(int p_what) { case NOTIFICATION_DRAW: { _draw(); } break; + case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: { + if (EditorSettings::get_singleton()->check_changed_settings_in_group("interface/touchscreen/scale_gizmo_handles")) { + _gizmo_handle_scale = EDITOR_GET("interface/touchscreen/scale_gizmo_handles"); + } + } break; } } @@ -397,7 +403,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) { @@ -417,14 +423,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; } } @@ -562,7 +568,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 { @@ -707,13 +713,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)); - 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)); - 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); } } @@ -736,7 +742,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); } @@ -746,7 +752,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 ca1a824f0c..b0d666b847 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/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp index 55b5abf983..0a8ccdba1a 100644 --- a/editor/plugins/tiles/tile_map_editor.cpp +++ b/editor/plugins/tiles/tile_map_editor.cpp @@ -938,6 +938,20 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over } } } + + Ref<Font> font = p_overlay->get_theme_font(SNAME("font"), SNAME("Label")); + int font_size = p_overlay->get_theme_font_size(SNAME("font_size"), SNAME("Label")); + Point2 msgpos = Point2(20 * EDSCALE, p_overlay->get_size().y - 20 * EDSCALE); + + String text = tile_map->local_to_map(tile_map->get_local_mouse_position()); + if (drag_type == DRAG_TYPE_RECT) { + Vector2i size = tile_map->local_to_map(tile_map->get_local_mouse_position()) - tile_map->local_to_map(drag_start_mouse_pos); + text += vformat(" %s (%dx%d)", TTR("Drawing Rect:"), ABS(size.x) + 1, ABS(size.y) + 1); + } + + p_overlay->draw_string(font, msgpos + Point2(1, 1), text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8)); + p_overlay->draw_string(font, msgpos + Point2(-1, -1), text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(0, 0, 0, 0.8)); + p_overlay->draw_string(font, msgpos, text, HORIZONTAL_ALIGNMENT_LEFT, -1, font_size, Color(1, 1, 1, 1)); } } diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp index b74324ff29..754533ab31 100644 --- a/editor/plugins/visual_shader_editor_plugin.cpp +++ b/editor/plugins/visual_shader_editor_plugin.cpp @@ -1209,13 +1209,19 @@ void VisualShaderEditor::clear_custom_types() { } } -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, bool p_highend) { +void VisualShaderEditor::add_custom_type(const String &p_name, const String &p_type, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend) { ERR_FAIL_COND(!p_name.is_valid_identifier()); - ERR_FAIL_COND(!p_script.is_valid()); + ERR_FAIL_COND(p_type.is_empty() && !p_script.is_valid()); for (int i = 0; i < add_options.size(); i++) { - if (add_options[i].is_custom) { - if (add_options[i].script == p_script) { + const AddOption &op = add_options[i]; + + if (op.is_custom) { + if (!p_type.is_empty()) { + if (op.type == p_type) { + return; + } + } else if (op.script == p_script) { return; } } @@ -1223,12 +1229,14 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> AddOption ao; ao.name = p_name; + ao.type = p_type; ao.script = p_script; ao.return_type = p_return_icon_type; ao.description = p_description; ao.category = p_category; ao.highend = p_highend; ao.is_custom = true; + ao.is_native = !p_type.is_empty(); bool begin = false; String root = p_category.split("/")[0]; @@ -1253,50 +1261,23 @@ void VisualShaderEditor::add_custom_type(const String &p_name, const Ref<Script> Dictionary VisualShaderEditor::get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node) { Dictionary dict; dict["script"] = p_custom_node->get_script(); + dict["name"] = p_custom_node->_get_name(); + dict["description"] = p_custom_node->_get_description(); + dict["return_icon_type"] = p_custom_node->_get_return_icon_type(); + dict["highend"] = p_custom_node->_is_highend(); - String name; - if (p_custom_node->has_method("_get_name")) { - name = (String)p_custom_node->call("_get_name"); - } else { - name = "Unnamed"; - } - dict["name"] = name; - - String description = ""; - if (p_custom_node->has_method("_get_description")) { - description = (String)p_custom_node->call("_get_description"); - } - dict["description"] = description; - - int return_icon_type = -1; - if (p_custom_node->has_method("_get_return_icon_type")) { - return_icon_type = (int)p_custom_node->call("_get_return_icon_type"); - } - dict["return_icon_type"] = return_icon_type; - - String category = ""; - if (p_custom_node->has_method("_get_category")) { - category = (String)p_custom_node->call("_get_category"); - } + String category = p_custom_node->_get_category(); category = category.rstrip("/"); category = category.lstrip("/"); category = "Addons/" + category; - - String subcategory = ""; if (p_custom_node->has_method("_get_subcategory")) { - subcategory = (String)p_custom_node->call("_get_subcategory"); - } - if (!subcategory.is_empty()) { - category += "/" + subcategory; + String subcategory = (String)p_custom_node->call("_get_subcategory"); + if (!subcategory.is_empty()) { + category += "/" + subcategory; + } } dict["category"] = category; - bool highend = false; - if (p_custom_node->has_method("_is_highend")) { - highend = (bool)p_custom_node->call("_is_highend"); - } - dict["highend"] = highend; - return dict; } @@ -1333,7 +1314,7 @@ void VisualShaderEditor::_script_created(const Ref<Script> &p_script) { ref->set_script(p_script); Dictionary dict = get_custom_node_data(ref); - add_custom_type(dict["name"], dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]); + add_custom_type(dict["name"], String(), dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]); _update_options_menu(); } @@ -1456,7 +1437,7 @@ void VisualShaderEditor::_update_custom_script(const Ref<Script> &p_script) { } if (!found_type) { - add_custom_type(dict["name"], dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]); + add_custom_type(dict["name"], String(), dict["script"], dict["description"], dict["return_icon_type"], dict["category"], dict["highend"]); } // To prevent updating options multiple times when multiple scripts are saved. @@ -1595,29 +1576,60 @@ bool VisualShaderEditor::_is_available(int p_mode) { void VisualShaderEditor::_update_nodes() { clear_custom_types(); - List<StringName> class_list; - ScriptServer::get_global_class_list(&class_list); Dictionary added; - 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> scr = Ref<Script>(res); - - Ref<VisualShaderNodeCustom> ref; - ref.instantiate(); - ref->set_script(scr); - if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { - continue; + + // Add GDScript classes. + { + 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_CONTINUE(res.is_null()); + ERR_CONTINUE(!res->is_class("Script")); + Ref<Script> scr = Ref<Script>(res); + + Ref<VisualShaderNodeCustom> ref; + ref.instantiate(); + ref->set_script(scr); + if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { + continue; + } + Dictionary dict = get_custom_node_data(ref); + dict["type"] = String(); + + String key; + key = String(dict["category"]) + "/" + String(dict["name"]); + + added[key] = dict; } - Dictionary dict = get_custom_node_data(ref); + } + } - String key; - key = String(dict["category"]) + "/" + String(dict["name"]); + // Add GDExtension classes. + { + List<StringName> class_list; + ClassDB::get_class_list(&class_list); + + for (int i = 0; i < class_list.size(); i++) { + if (ClassDB::get_parent_class(class_list[i]) == "VisualShaderNodeCustom") { + Object *instance = ClassDB::instantiate(class_list[i]); + Ref<VisualShaderNodeCustom> ref = Object::cast_to<VisualShaderNodeCustom>(instance); + ERR_CONTINUE(ref.is_null()); + if (!ref->is_available(visual_shader->get_mode(), visual_shader->get_shader_type())) { + continue; + } + Dictionary dict = get_custom_node_data(ref); + dict["type"] = class_list[i]; + dict["script"] = Ref<Script>(); - added[key] = dict; + String key; + key = String(dict["category"]) + "/" + String(dict["name"]); + + added[key] = dict; + } } } @@ -1655,7 +1667,7 @@ void VisualShaderEditor::_update_nodes() { const Dictionary &value = (Dictionary)added[key]; - add_custom_type(value["name"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]); + add_custom_type(value["name"], value["type"], value["script"], value["description"], value["return_icon_type"], value["category"], value["highend"]); } _update_options_menu(); @@ -3062,12 +3074,21 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri vsnode = Ref<VisualShaderNode>(vsn); } else { - ERR_FAIL_COND(add_options[p_idx].script.is_null()); - StringName base_type = add_options[p_idx].script->get_instance_base_type(); + StringName base_type; + bool is_native = add_options[p_idx].is_native; + + if (is_native) { + base_type = add_options[p_idx].type; + } else { + ERR_FAIL_COND(add_options[p_idx].script.is_null()); + base_type = add_options[p_idx].script->get_instance_base_type(); + } VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type)); ERR_FAIL_COND(!vsn); vsnode = Ref<VisualShaderNode>(vsn); - vsnode->set_script(add_options[p_idx].script); + if (!is_native) { + vsnode->set_script(add_options[p_idx].script); + } } bool is_texture2d = (Object::cast_to<VisualShaderNodeTexture>(vsnode.ptr()) != nullptr); diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h index 21139fbddd..bdb23afa0f 100644 --- a/editor/plugins/visual_shader_editor_plugin.h +++ b/editor/plugins/visual_shader_editor_plugin.h @@ -310,6 +310,7 @@ class VisualShaderEditor : public VBoxContainer { int func = 0; bool highend = false; bool is_custom = false; + bool is_native = false; int temp_idx = 0; AddOption(const String &p_name = String(), const String &p_category = String(), const String &p_type = String(), const String &p_description = String(), const Vector<Variant> &p_ops = Vector<Variant>(), int p_return_type = -1, int p_mode = -1, int p_func = -1, bool p_highend = false) { @@ -527,9 +528,10 @@ public: VisualShaderGraphPlugin *get_graph_plugin() { return graph_plugin.ptr(); } 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, bool p_highend); + void add_custom_type(const String &p_name, const String &p_type, const Ref<Script> &p_script, const String &p_description, int p_return_icon_type, const String &p_category, bool p_highend); Dictionary get_custom_node_data(Ref<VisualShaderNodeCustom> &p_custom_node); + void update_custom_type(const Ref<Resource> &p_resource); virtual Size2 get_minimum_size() const override; void edit(VisualShader *p_visual_shader); diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp index d2f6be2233..63abbf0d71 100644 --- a/modules/openxr/action_map/openxr_action_map.cpp +++ b/modules/openxr/action_map/openxr_action_map.cpp @@ -415,7 +415,7 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); - profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select + profile->add_new_binding(select_button, "/user/hand/right/input/system/click"); // we'll map system to select profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); @@ -439,7 +439,7 @@ void OpenXRActionMap::create_default_action_sets() { profile->add_new_binding(grip_pose, "/user/hand/left/input/grip/pose,/user/hand/right/input/grip/pose"); profile->add_new_binding(palm_pose, "/user/hand/left/input/palm_ext/pose,/user/hand/right/input/palm_ext/pose"); profile->add_new_binding(menu_button, "/user/hand/left/input/menu/click"); - profile->add_new_binding(select_button, "/user/hand/left/input/system/click"); // we'll map system to select + profile->add_new_binding(select_button, "/user/hand/right/input/system/click"); // we'll map system to select profile->add_new_binding(ax_button, "/user/hand/left/input/x/click,/user/hand/right/input/a/click"); // x on left hand, a on right hand profile->add_new_binding(by_button, "/user/hand/left/input/y/click,/user/hand/right/input/b/click"); // y on left hand, b on right hand profile->add_new_binding(trigger, "/user/hand/left/input/trigger/value,/user/hand/right/input/trigger/value"); diff --git a/modules/openxr/extensions/openxr_htc_controller_extension.cpp b/modules/openxr/extensions/openxr_htc_controller_extension.cpp index 4d141b0695..116762ee8d 100644 --- a/modules/openxr/extensions/openxr_htc_controller_extension.cpp +++ b/modules/openxr/extensions/openxr_htc_controller_extension.cpp @@ -108,7 +108,7 @@ void OpenXRHTCControllerExtension::on_register_metadata() { metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/left", "/user/hand/left/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger", "/user/hand/right", "/user/hand/right/input/trigger/value", "", OpenXRAction::OPENXR_ACTION_FLOAT); metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger click", "/user/hand/right", "/user/hand/right/input/trigger/click", "", OpenXRAction::OPENXR_ACTION_BOOL); - metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch ", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Trigger touch", "/user/hand/right", "/user/hand/right/input/trigger/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze click", "/user/hand/left", "/user/hand/left/input/squeeze/click", "", OpenXRAction::OPENXR_ACTION_BOOL); metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Squeeze touch", "/user/hand/left", "/user/hand/left/input/squeeze/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); @@ -122,6 +122,7 @@ void OpenXRHTCControllerExtension::on_register_metadata() { metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick click", "/user/hand/right", "/user/hand/right/input/thumbstick/click", "", OpenXRAction::OPENXR_ACTION_BOOL); metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbstick touch", "/user/hand/right", "/user/hand/right/input/thumbstick/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); + metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbrest touch", "/user/hand/left", "/user/hand/left/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Thumbrest touch", "/user/hand/right", "/user/hand/right/input/thumbrest/touch", "", OpenXRAction::OPENXR_ACTION_BOOL); metadata->register_io_path("/interaction_profiles/htc/vive_focus3_controller", "Haptic output", "/user/hand/left", "/user/hand/left/output/haptic", "", OpenXRAction::OPENXR_ACTION_HAPTIC); diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index 70d87e221c..46ac8187c4 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -233,13 +233,13 @@ void Button::_notification(int p_what) { } Rect2 icon_region; - HorizontalAlignment icon_align_rtl_checked = icon_alignment; + HorizontalAlignment icon_align_rtl_checked = horizontal_icon_alignment; HorizontalAlignment align_rtl_checked = alignment; // Swap icon and text alignment sides if right-to-left layout is set. if (rtl) { - if (icon_alignment == HORIZONTAL_ALIGNMENT_RIGHT) { + if (horizontal_icon_alignment == HORIZONTAL_ALIGNMENT_RIGHT) { icon_align_rtl_checked = HORIZONTAL_ALIGNMENT_LEFT; - } else if (icon_alignment == HORIZONTAL_ALIGNMENT_LEFT) { + } else if (horizontal_icon_alignment == HORIZONTAL_ALIGNMENT_LEFT) { icon_align_rtl_checked = HORIZONTAL_ALIGNMENT_RIGHT; } if (alignment == HORIZONTAL_ALIGNMENT_RIGHT) { @@ -251,6 +251,14 @@ void Button::_notification(int p_what) { if (!_icon.is_null()) { int valign = size.height - style->get_minimum_size().y; + int voffset = 0; + Size2 icon_size = _icon->get_size(); + + // Fix vertical size. + if (vertical_icon_alignment != VERTICAL_ALIGNMENT_CENTER) { + valign -= text_buf->get_size().height; + } + float icon_ofs_region = 0.0; Point2 style_offset; if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) { @@ -268,7 +276,6 @@ void Button::_notification(int p_what) { } style_offset.y = style->get_margin(SIDE_TOP); - Size2 icon_size = _icon->get_size(); if (expand_icon) { Size2 _size = get_size() - style->get_offset() * 2; int icon_text_separation = text.is_empty() ? 0 : theme_cache.h_separation; @@ -276,6 +283,9 @@ void Button::_notification(int p_what) { if (!clip_text && icon_align_rtl_checked != HORIZONTAL_ALIGNMENT_CENTER) { _size.width -= text_buf->get_size().width; } + if (vertical_icon_alignment != VERTICAL_ALIGNMENT_CENTER) { + _size.height -= text_buf->get_size().height; + } float icon_width = _icon->get_width() * _size.height / _icon->get_height(); float icon_height = _size.height; @@ -288,12 +298,19 @@ void Button::_notification(int p_what) { } icon_size = _fit_icon_size(icon_size); + if (vertical_icon_alignment == VERTICAL_ALIGNMENT_TOP) { + voffset = -(valign - icon_size.y) / 2; + } + if (vertical_icon_alignment == VERTICAL_ALIGNMENT_BOTTOM) { + voffset = (valign - icon_size.y) / 2 + text_buf->get_size().y; + } + if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) { - icon_region = Rect2(style_offset + Point2(icon_ofs_region, Math::floor((valign - icon_size.y) * 0.5)), icon_size); + icon_region = Rect2(style_offset + Point2(icon_ofs_region, voffset + Math::floor((valign - icon_size.y) * 0.5)), icon_size); } else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) { - icon_region = Rect2(style_offset + Point2(icon_ofs_region + Math::floor((size.x - icon_size.x) * 0.5), Math::floor((valign - icon_size.y) * 0.5)), icon_size); + icon_region = Rect2(style_offset + Point2(icon_ofs_region + Math::floor((size.x - icon_size.x) * 0.5), voffset + Math::floor((valign - icon_size.y) * 0.5)), icon_size); } else { - icon_region = Rect2(style_offset + Point2(icon_ofs_region + size.x - icon_size.x, Math::floor((valign - icon_size.y) * 0.5)), icon_size); + icon_region = Rect2(style_offset + Point2(icon_ofs_region + size.x - icon_size.x, voffset + Math::floor((valign - icon_size.y) * 0.5)), icon_size); } if (icon_region.size.width > 0) { @@ -320,6 +337,13 @@ void Button::_notification(int p_what) { Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - text_buf->get_size() - Point2(_internal_margin[SIDE_RIGHT] - _internal_margin[SIDE_LEFT], 0)) / 2.0; + if (vertical_icon_alignment == VERTICAL_ALIGNMENT_TOP) { + text_ofs.y += icon_region.size.height / 2; + } + if (vertical_icon_alignment == VERTICAL_ALIGNMENT_BOTTOM) { + text_ofs.y -= icon_region.size.height / 2; + } + text_buf->set_alignment(align_rtl_checked); text_buf->set_width(text_width); switch (align_rtl_checked) { @@ -395,9 +419,13 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu if (!expand_icon && p_icon.is_valid()) { Size2 icon_size = _fit_icon_size(p_icon->get_size()); - minsize.height = MAX(minsize.height, icon_size.height); + if (vertical_icon_alignment == VERTICAL_ALIGNMENT_CENTER) { + minsize.height = MAX(minsize.height, icon_size.height); + } else { + minsize.height += icon_size.height; + } - if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) { + if (horizontal_icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) { minsize.width += icon_size.width; if (!xl_text.is_empty() || !p_text.is_empty()) { minsize.width += MAX(0, theme_cache.h_separation); @@ -410,7 +438,11 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu if (!xl_text.is_empty() || !p_text.is_empty()) { Ref<Font> font = theme_cache.font; float font_height = font->get_height(theme_cache.font_size); - minsize.height = MAX(font_height, minsize.height); + if (vertical_icon_alignment == VERTICAL_ALIGNMENT_CENTER) { + minsize.height = MAX(font_height, minsize.height); + } else { + minsize.height += font_height; + } } return theme_cache.normal->get_minimum_size() + minsize; @@ -556,13 +588,23 @@ HorizontalAlignment Button::get_text_alignment() const { } void Button::set_icon_alignment(HorizontalAlignment p_alignment) { - icon_alignment = p_alignment; + horizontal_icon_alignment = p_alignment; + update_minimum_size(); + queue_redraw(); +} + +void Button::set_vertical_icon_alignment(VerticalAlignment p_alignment) { + vertical_icon_alignment = p_alignment; update_minimum_size(); queue_redraw(); } HorizontalAlignment Button::get_icon_alignment() const { - return icon_alignment; + return horizontal_icon_alignment; +} + +VerticalAlignment Button::get_vertical_icon_alignment() const { + return vertical_icon_alignment; } void Button::_bind_methods() { @@ -584,6 +626,8 @@ void Button::_bind_methods() { ClassDB::bind_method(D_METHOD("get_text_alignment"), &Button::get_text_alignment); ClassDB::bind_method(D_METHOD("set_icon_alignment", "icon_alignment"), &Button::set_icon_alignment); ClassDB::bind_method(D_METHOD("get_icon_alignment"), &Button::get_icon_alignment); + ClassDB::bind_method(D_METHOD("set_vertical_icon_alignment", "vertical_icon_alignment"), &Button::set_vertical_icon_alignment); + ClassDB::bind_method(D_METHOD("get_vertical_icon_alignment"), &Button::get_vertical_icon_alignment); ClassDB::bind_method(D_METHOD("set_expand_icon", "enabled"), &Button::set_expand_icon); ClassDB::bind_method(D_METHOD("is_expand_icon"), &Button::is_expand_icon); @@ -598,6 +642,7 @@ void Button::_bind_methods() { ADD_GROUP("Icon Behavior", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_icon_alignment", "get_icon_alignment"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_icon_alignment", PROPERTY_HINT_ENUM, "Top,Center,Bottom"), "set_vertical_icon_alignment", "get_vertical_icon_alignment"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_icon"), "set_expand_icon", "is_expand_icon"); ADD_GROUP("BiDi", ""); diff --git a/scene/gui/button.h b/scene/gui/button.h index 3634b5344c..733f40c84e 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -51,7 +51,8 @@ private: bool expand_icon = false; bool clip_text = false; HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_CENTER; - HorizontalAlignment icon_alignment = HORIZONTAL_ALIGNMENT_LEFT; + HorizontalAlignment horizontal_icon_alignment = HORIZONTAL_ALIGNMENT_LEFT; + VerticalAlignment vertical_icon_alignment = VERTICAL_ALIGNMENT_CENTER; float _internal_margin[4] = {}; struct ThemeCache { @@ -135,7 +136,9 @@ public: HorizontalAlignment get_text_alignment() const; void set_icon_alignment(HorizontalAlignment p_alignment); + void set_vertical_icon_alignment(VerticalAlignment p_alignment); HorizontalAlignment get_icon_alignment() const; + VerticalAlignment get_vertical_icon_alignment() const; Button(const String &p_text = String()); ~Button(); diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp index b7dc1c4fbe..5e861ba45d 100644 --- a/scene/gui/color_picker.cpp +++ b/scene/gui/color_picker.cpp @@ -1913,34 +1913,23 @@ void ColorPickerButton::_modal_closed() { void ColorPickerButton::pressed() { _update_picker(); - Size2 size = get_size() * get_viewport()->get_canvas_transform().get_scale(); + Size2 minsize = popup->get_contents_minimum_size(); + float viewport_height = get_viewport_rect().size.y; popup->reset_size(); picker->_update_presets(); picker->_update_recent_presets(); - Rect2i usable_rect = popup->get_usable_parent_rect(); - //let's try different positions to see which one we can use - - Rect2i cp_rect(Point2i(), popup->get_size()); - for (int i = 0; i < 4; i++) { - if (i > 1) { - cp_rect.position.y = get_screen_position().y - cp_rect.size.y; - } else { - cp_rect.position.y = get_screen_position().y + size.height; - } - - if (i & 1) { - cp_rect.position.x = get_screen_position().x; - } else { - cp_rect.position.x = get_screen_position().x - MAX(0, (cp_rect.size.x - size.x)); - } - - if (usable_rect.encloses(cp_rect)) { - break; - } + // Determine in which direction to show the popup. By default popup horizontally centered below the button. + // But if the popup doesn't fit below and the button is in the bottom half of the viewport, show above. + bool show_above = false; + if (get_global_position().y + get_size().y + minsize.y > viewport_height && get_global_position().y * 2 + get_size().y > viewport_height) { + show_above = true; } - popup->set_position(cp_rect.position); + + float h_offset = (get_size().x - minsize.x) / 2; + float v_offset = show_above ? -minsize.y : get_size().y; + popup->set_position(get_screen_position() + Vector2(h_offset, v_offset)); popup->popup(); picker->set_focus_on_line_edit(); } diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp index 42e4a0fa3d..a361b7584a 100644 --- a/scene/resources/visual_shader.cpp +++ b/scene/resources/visual_shader.cpp @@ -611,6 +611,36 @@ void VisualShaderNodeCustom::_set_initialized(bool p_enabled) { is_initialized = p_enabled; } +String VisualShaderNodeCustom::_get_name() const { + String ret; + GDVIRTUAL_CALL(_get_name, ret); + return ret; +} + +String VisualShaderNodeCustom::_get_description() const { + String ret; + GDVIRTUAL_CALL(_get_description, ret); + return ret; +} + +String VisualShaderNodeCustom::_get_category() const { + String ret; + GDVIRTUAL_CALL(_get_category, ret); + return ret; +} + +VisualShaderNodeCustom::PortType VisualShaderNodeCustom::_get_return_icon_type() const { + PortType ret = PORT_TYPE_SCALAR; + GDVIRTUAL_CALL(_get_return_icon_type, ret); + return ret; +} + +bool VisualShaderNodeCustom::_is_highend() const { + bool ret = false; + GDVIRTUAL_CALL(_is_highend, ret); + return ret; +} + void VisualShaderNodeCustom::_bind_methods() { GDVIRTUAL_BIND(_get_name); GDVIRTUAL_BIND(_get_description); diff --git a/scene/resources/visual_shader.h b/scene/resources/visual_shader.h index 2838a49209..38d51dba9c 100644 --- a/scene/resources/visual_shader.h +++ b/scene/resources/visual_shader.h @@ -411,6 +411,12 @@ public: bool _is_initialized(); void _set_initialized(bool p_enabled); + + String _get_name() const; + String _get_description() const; + String _get_category() const; + PortType _get_return_icon_type() const; + bool _is_highend() const; }; ///// |
