summaryrefslogtreecommitdiff
path: root/scene/main/viewport.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/main/viewport.cpp')
-rw-r--r--scene/main/viewport.cpp228
1 files changed, 164 insertions, 64 deletions
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 3c7475a150..17411bb490 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -30,11 +30,11 @@
#include "viewport.h"
+#include "core/config/project_settings.h"
#include "core/core_string_names.h"
#include "core/debugger/engine_debugger.h"
#include "core/input/input.h"
#include "core/os/os.h"
-#include "core/project_settings.h"
#include "scene/2d/collision_object_2d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/collision_object_3d.h"
@@ -161,6 +161,11 @@ ViewportTexture::~ViewportTexture() {
/////////////////////////////////////
+// Aliases used to provide custom styles to tooltips in the default
+// theme and editor theme.
+// TooltipPanel is also used for custom tooltips, while TooltipLabel
+// is only relevant for default tooltips.
+
class TooltipPanel : public PopupPanel {
GDCLASS(TooltipPanel, PopupPanel);
@@ -175,6 +180,8 @@ public:
TooltipLabel() {}
};
+/////////////////////////////////////
+
Viewport::GUI::GUI() {
embed_subwindows_hint = false;
embedding_subwindows = false;
@@ -188,7 +195,7 @@ Viewport::GUI::GUI() {
mouse_over = nullptr;
drag_mouse_over = nullptr;
- tooltip = nullptr;
+ tooltip_control = nullptr;
tooltip_popup = nullptr;
tooltip_label = nullptr;
}
@@ -814,7 +821,14 @@ void Viewport::_notification(int p_what) {
}
} break;
- case NOTIFICATION_WM_MOUSE_EXIT:
+ case NOTIFICATION_WM_MOUSE_EXIT: {
+ _drop_physics_mouseover();
+
+ // Unlike on loss of focus (NOTIFICATION_WM_WINDOW_FOCUS_OUT), do not
+ // drop the gui mouseover here, as a scrollbar may be dragged while the
+ // mouse is outside the window (without the window having lost focus).
+ // See bug #39634
+ } break;
case NOTIFICATION_WM_WINDOW_FOCUS_OUT: {
_drop_physics_mouseover();
@@ -1465,7 +1479,7 @@ void Viewport::_gui_sort_roots() {
}
void Viewport::_gui_cancel_tooltip() {
- gui.tooltip = nullptr;
+ gui.tooltip_control = nullptr;
gui.tooltip_timer = -1;
if (gui.tooltip_popup) {
gui.tooltip_popup->queue_delete();
@@ -1474,21 +1488,23 @@ void Viewport::_gui_cancel_tooltip() {
}
}
-String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_which) {
+String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Control **r_tooltip_owner) {
Vector2 pos = p_pos;
String tooltip;
while (p_control) {
tooltip = p_control->get_tooltip(pos);
- if (r_which) {
- *r_which = p_control;
+ if (r_tooltip_owner) {
+ *r_tooltip_owner = p_control;
}
- if (tooltip != String()) {
+ // If we found a tooltip, we stop here.
+ if (!tooltip.empty()) {
break;
}
- pos = p_control->get_transform().xform(pos);
+
+ // Otherwise, we check parent controls unless some conditions prevent it.
if (p_control->data.mouse_filter == Control::MOUSE_FILTER_STOP) {
break;
@@ -1497,6 +1513,9 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont
break;
}
+ // Transform cursor pos for parent control.
+ pos = p_control->get_transform().xform(pos);
+
p_control = p_control->get_parent_control();
}
@@ -1504,34 +1523,40 @@ String Viewport::_gui_get_tooltip(Control *p_control, const Vector2 &p_pos, Cont
}
void Viewport::_gui_show_tooltip() {
- if (!gui.tooltip) {
+ if (!gui.tooltip_control) {
return;
}
- Control *which = nullptr;
- String tooltip = _gui_get_tooltip(gui.tooltip, gui.tooltip->get_global_transform().xform_inv(gui.last_mouse_pos), &which);
- tooltip = tooltip.strip_edges();
- if (tooltip.length() == 0) {
- return; // bye
+ // Get the Control under cursor and the relevant tooltip text, if any.
+ Control *tooltip_owner = nullptr;
+ String tooltip_text = _gui_get_tooltip(
+ gui.tooltip_control,
+ gui.tooltip_control->get_global_transform().xform_inv(gui.last_mouse_pos),
+ &tooltip_owner);
+ tooltip_text.strip_edges();
+ if (tooltip_text.empty()) {
+ return; // Nothing to show.
}
+ // Remove previous popup if we change something.
if (gui.tooltip_popup) {
memdelete(gui.tooltip_popup);
gui.tooltip_popup = nullptr;
gui.tooltip_label = nullptr;
}
- if (!which) {
+ if (!tooltip_owner) {
return;
}
- Control *rp = which;
-
- Control *base_tooltip = which->make_custom_tooltip(tooltip);
+ // Controls can implement `make_custom_tooltip` to provide their own tooltip.
+ // This should be a Control node which will be added as child to a TooltipPanel.
+ Control *base_tooltip = tooltip_owner->make_custom_tooltip(tooltip_text);
+ // If no custom tooltip is given, use a default implementation.
if (!base_tooltip) {
gui.tooltip_label = memnew(TooltipLabel);
- gui.tooltip_label->set_text(tooltip);
+ gui.tooltip_label->set_text(tooltip_text);
base_tooltip = gui.tooltip_label;
}
@@ -1545,10 +1570,7 @@ void Viewport::_gui_show_tooltip() {
gui.tooltip_popup = panel;
- rp->add_child(gui.tooltip_popup);
-
- //if (gui.tooltip) // Avoids crash when rapidly switching controls.
- // gui.tooltip_popup->set_scale(gui.tooltip->get_global_transform().get_scale());
+ tooltip_owner->add_child(gui.tooltip_popup);
Point2 tooltip_offset = ProjectSettings::get_singleton()->get("display/mouse_cursor/tooltip_position_offset");
Rect2 r(gui.tooltip_pos + tooltip_offset, gui.tooltip_popup->get_contents_minimum_size());
@@ -1794,6 +1816,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
if (mb.is_valid()) {
gui.key_event_accepted = false;
+ Control *over = nullptr;
+
Point2 mpos = mb->get_position();
if (mb->is_pressed()) {
Size2 pos = mpos;
@@ -1897,8 +1921,6 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
_gui_cancel_tooltip();
- //gui.tooltip_popup->hide();
-
} else {
if (gui.drag_data.get_type() != Variant::NIL && mb->get_button_index() == BUTTON_LEFT) {
if (gui.drag_mouse_over) {
@@ -1948,6 +1970,31 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
gui.drag_data=Variant(); //always clear
}*/
+ // In case the mouse was released after for example dragging a scrollbar,
+ // check whether the current control is different from the stored one. If
+ // it is different, rather than wait for it to be updated the next time the
+ // mouse is moved, notify the control so that it can e.g. drop the highlight.
+ // This code is duplicated from the mm.is_valid()-case further below.
+ if (gui.mouse_focus) {
+ over = gui.mouse_focus;
+ } else {
+ over = _gui_find_control(mpos);
+ }
+
+ if (gui.mouse_focus_mask == 0 && over != gui.mouse_over) {
+ if (gui.mouse_over) {
+ _gui_call_notification(gui.mouse_over, Control::NOTIFICATION_MOUSE_EXIT);
+ }
+
+ _gui_cancel_tooltip();
+
+ if (over) {
+ _gui_call_notification(over, Control::NOTIFICATION_MOUSE_ENTER);
+ }
+ }
+
+ gui.mouse_over = over;
+
set_input_as_handled();
}
}
@@ -2008,10 +2055,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
}
+ // These sections of code are reused in the mb.is_valid() case further up
+ // for the purpose of notifying controls about potential changes in focus
+ // when the mousebutton is released.
if (gui.mouse_focus) {
over = gui.mouse_focus;
- //recompute focus_inv_xform again here
-
} else {
over = _gui_find_control(mpos);
}
@@ -2052,8 +2100,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool is_tooltip_shown = false;
if (gui.tooltip_popup) {
- if (can_tooltip && gui.tooltip) {
- String tooltip = _gui_get_tooltip(over, gui.tooltip->get_global_transform().xform_inv(mpos));
+ if (can_tooltip && gui.tooltip_control) {
+ String tooltip = _gui_get_tooltip(over, gui.tooltip_control->get_global_transform().xform_inv(mpos));
if (tooltip.length() == 0) {
_gui_cancel_tooltip();
@@ -2078,14 +2126,12 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
}
if (can_tooltip && !is_tooltip_shown) {
- gui.tooltip = over;
- gui.tooltip_pos = over->get_screen_transform().xform(pos); //(parent_xform * get_transform()).affine_inverse().xform(pos);
+ gui.tooltip_control = over;
+ gui.tooltip_pos = over->get_screen_transform().xform(pos);
gui.tooltip_timer = gui.tooltip_delay;
}
}
- //pos = gui.focus_inv_xform.xform(pos);
-
mm->set_position(pos);
Control::CursorShape cursor_shape = Control::CURSOR_ARROW;
@@ -2436,7 +2482,7 @@ void Viewport::_gui_hide_control(Control *p_control) {
if (gui.drag_mouse_over == p_control) {
gui.drag_mouse_over = nullptr;
}
- if (gui.tooltip == p_control) {
+ if (gui.tooltip_control == p_control) {
_gui_cancel_tooltip();
}
}
@@ -2459,8 +2505,8 @@ void Viewport::_gui_remove_control(Control *p_control) {
if (gui.drag_mouse_over == p_control) {
gui.drag_mouse_over = nullptr;
}
- if (gui.tooltip == p_control) {
- gui.tooltip = nullptr;
+ if (gui.tooltip_control == p_control) {
+ gui.tooltip_control = nullptr;
}
}
@@ -3138,6 +3184,17 @@ Viewport::ScreenSpaceAA Viewport::get_screen_space_aa() const {
return screen_space_aa;
}
+void Viewport::set_use_debanding(bool p_use_debanding) {
+ if (use_debanding == p_use_debanding)
+ return;
+ use_debanding = p_use_debanding;
+ RS::get_singleton()->viewport_set_use_debanding(viewport, p_use_debanding);
+}
+
+bool Viewport::is_using_debanding() const {
+ return use_debanding;
+}
+
void Viewport::set_debug_draw(DebugDraw p_debug_draw) {
debug_draw = p_debug_draw;
RS::get_singleton()->viewport_set_debug_draw(viewport, RS::ViewportDebugDraw(p_debug_draw));
@@ -3159,6 +3216,24 @@ bool Viewport::is_snap_controls_to_pixels_enabled() const {
return snap_controls_to_pixels;
}
+void Viewport::set_snap_2d_transforms_to_pixel(bool p_enable) {
+ snap_2d_transforms_to_pixel = p_enable;
+ RS::get_singleton()->viewport_set_snap_2d_transforms_to_pixel(viewport, snap_2d_transforms_to_pixel);
+}
+
+bool Viewport::is_snap_2d_transforms_to_pixel_enabled() const {
+ return snap_2d_transforms_to_pixel;
+}
+
+void Viewport::set_snap_2d_vertices_to_pixel(bool p_enable) {
+ snap_2d_vertices_to_pixel = p_enable;
+ RS::get_singleton()->viewport_set_snap_2d_vertices_to_pixel(viewport, snap_2d_vertices_to_pixel);
+}
+
+bool Viewport::is_snap_2d_vertices_to_pixel_enabled() const {
+ return snap_2d_vertices_to_pixel;
+}
+
bool Viewport::gui_is_dragging() const {
return gui.dragging;
}
@@ -3213,11 +3288,28 @@ void Viewport::_validate_property(PropertyInfo &property) const {
}
void Viewport::set_default_canvas_item_texture_filter(DefaultCanvasItemTextureFilter p_filter) {
+ ERR_FAIL_INDEX(p_filter, DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_MAX);
+
if (default_canvas_item_texture_filter == p_filter) {
return;
}
default_canvas_item_texture_filter = p_filter;
- _propagate_update_default_filter(this);
+ switch (default_canvas_item_texture_filter) {
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR);
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS);
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_filter(viewport, RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS);
+ break;
+ default: {
+ }
+ }
}
Viewport::DefaultCanvasItemTextureFilter Viewport::get_default_canvas_item_texture_filter() const {
@@ -3225,37 +3317,31 @@ Viewport::DefaultCanvasItemTextureFilter Viewport::get_default_canvas_item_textu
}
void Viewport::set_default_canvas_item_texture_repeat(DefaultCanvasItemTextureRepeat p_repeat) {
+ ERR_FAIL_INDEX(p_repeat, DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MAX);
+
if (default_canvas_item_texture_repeat == p_repeat) {
return;
}
- default_canvas_item_texture_repeat = p_repeat;
- _propagate_update_default_repeat(this);
-}
-
-Viewport::DefaultCanvasItemTextureRepeat Viewport::get_default_canvas_item_texture_repeat() const {
- return default_canvas_item_texture_repeat;
-}
-void Viewport::_propagate_update_default_filter(Node *p_node) {
- CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
- if (ci) {
- ci->_update_texture_filter_changed(false);
- }
+ default_canvas_item_texture_repeat = p_repeat;
- for (int i = 0; i < p_node->get_child_count(); i++) {
- _propagate_update_default_filter(p_node->get_child(i));
+ switch (default_canvas_item_texture_repeat) {
+ case DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_DISABLED:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_repeat(viewport, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED);
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_ENABLED:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_repeat(viewport, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+ break;
+ case DEFAULT_CANVAS_ITEM_TEXTURE_REPEAT_MIRROR:
+ RS::get_singleton()->viewport_set_default_canvas_item_texture_repeat(viewport, RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR);
+ break;
+ default: {
+ }
}
}
-void Viewport::_propagate_update_default_repeat(Node *p_node) {
- CanvasItem *ci = Object::cast_to<CanvasItem>(p_node);
- if (ci) {
- ci->_update_texture_repeat_changed(false);
- }
-
- for (int i = 0; i < p_node->get_child_count(); i++) {
- _propagate_update_default_repeat(p_node->get_child(i));
- }
+Viewport::DefaultCanvasItemTextureRepeat Viewport::get_default_canvas_item_texture_repeat() const {
+ return default_canvas_item_texture_repeat;
}
DisplayServer::WindowID Viewport::get_window_id() const {
@@ -3324,6 +3410,9 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_screen_space_aa", "screen_space_aa"), &Viewport::set_screen_space_aa);
ClassDB::bind_method(D_METHOD("get_screen_space_aa"), &Viewport::get_screen_space_aa);
+ ClassDB::bind_method(D_METHOD("set_use_debanding", "enable"), &Viewport::set_use_debanding);
+ ClassDB::bind_method(D_METHOD("is_using_debanding"), &Viewport::is_using_debanding);
+
ClassDB::bind_method(D_METHOD("set_debug_draw", "debug_draw"), &Viewport::set_debug_draw);
ClassDB::bind_method(D_METHOD("get_debug_draw"), &Viewport::get_debug_draw);
@@ -3370,6 +3459,12 @@ void Viewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_snap_controls_to_pixels", "enabled"), &Viewport::set_snap_controls_to_pixels);
ClassDB::bind_method(D_METHOD("is_snap_controls_to_pixels_enabled"), &Viewport::is_snap_controls_to_pixels_enabled);
+ ClassDB::bind_method(D_METHOD("set_snap_2d_transforms_to_pixel", "enabled"), &Viewport::set_snap_2d_transforms_to_pixel);
+ ClassDB::bind_method(D_METHOD("is_snap_2d_transforms_to_pixel_enabled"), &Viewport::is_snap_2d_transforms_to_pixel_enabled);
+
+ ClassDB::bind_method(D_METHOD("set_snap_2d_vertices_to_pixel", "enabled"), &Viewport::set_snap_2d_vertices_to_pixel);
+ ClassDB::bind_method(D_METHOD("is_snap_2d_vertices_to_pixel_enabled"), &Viewport::is_snap_2d_vertices_to_pixel_enabled);
+
ClassDB::bind_method(D_METHOD("set_shadow_atlas_quadrant_subdiv", "quadrant", "subdiv"), &Viewport::set_shadow_atlas_quadrant_subdiv);
ClassDB::bind_method(D_METHOD("get_shadow_atlas_quadrant_subdiv", "quadrant"), &Viewport::get_shadow_atlas_quadrant_subdiv);
@@ -3394,9 +3489,12 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "world_2d", PROPERTY_HINT_RESOURCE_TYPE, "World2D", 0), "set_world_2d", "get_world_2d");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "transparent_bg"), "set_transparent_background", "has_transparent_background");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "handle_input_locally"), "set_handle_input_locally", "is_handling_input_locally");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_transforms_to_pixel"), "set_snap_2d_transforms_to_pixel", "is_snap_2d_transforms_to_pixel_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "snap_2d_vertices_to_pixel"), "set_snap_2d_vertices_to_pixel", "is_snap_2d_vertices_to_pixel_enabled");
ADD_GROUP("Rendering", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "msaa", PROPERTY_HINT_ENUM, "Disabled,2x,4x,8x,16x,AndroidVR 2x,AndroidVR 4x"), "set_msaa", "get_msaa");
ADD_PROPERTY(PropertyInfo(Variant::INT, "screen_space_aa", PROPERTY_HINT_ENUM, "Disabled,FXAA"), "set_screen_space_aa", "get_screen_space_aa");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
ADD_GROUP("Canvas Items", "canvas_item_");
ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_item_default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,MipmapLinear,MipmapNearest"), "set_default_canvas_item_texture_filter", "get_default_canvas_item_texture_filter");
@@ -3527,14 +3625,13 @@ Viewport::Viewport() {
disable_input = false;
- //window tooltip
+ // Window tooltip.
gui.tooltip_timer = -1;
- //gui.tooltip_timer->force_parent_owned();
gui.tooltip_delay = GLOBAL_DEF("gui/timers/tooltip_delay_sec", 0.5);
ProjectSettings::get_singleton()->set_custom_property_info("gui/timers/tooltip_delay_sec", PropertyInfo(Variant::FLOAT, "gui/timers/tooltip_delay_sec", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); // No negative numbers
- gui.tooltip = nullptr;
+ gui.tooltip_control = nullptr;
gui.tooltip_label = nullptr;
gui.drag_preview = nullptr;
gui.drag_attempted = false;
@@ -3551,6 +3648,9 @@ Viewport::Viewport() {
debug_draw = DEBUG_DRAW_DISABLED;
snap_controls_to_pixels = true;
+ snap_2d_transforms_to_pixel = false;
+ snap_2d_vertices_to_pixel = false;
+
physics_last_mouse_state.alt = false;
physics_last_mouse_state.control = false;
physics_last_mouse_state.shift = false;