summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/input/input.cpp25
-rw-r--r--doc/classes/Button.xml5
-rw-r--r--doc/classes/EditorSettings.xml4
-rw-r--r--editor/editor_node.cpp4
-rw-r--r--editor/editor_settings.cpp3
-rw-r--r--editor/editor_themes.cpp41
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp13
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.h3
-rw-r--r--editor/plugins/curve_editor_plugin.cpp22
-rw-r--r--editor/plugins/curve_editor_plugin.h1
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp14
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp151
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h4
-rw-r--r--modules/openxr/action_map/openxr_action_map.cpp4
-rw-r--r--modules/openxr/extensions/openxr_htc_controller_extension.cpp3
-rw-r--r--scene/gui/button.cpp69
-rw-r--r--scene/gui/button.h5
-rw-r--r--scene/gui/color_picker.cpp33
-rw-r--r--scene/resources/visual_shader.cpp30
-rw-r--r--scene/resources/visual_shader.h6
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="&quot;&quot;">
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;
};
/////