Make BaseButton not emit press when container is scrolled
This fixes the problem described in #13996 in a proper way.
This also adds "deadzone" property to ScrollContainer. It can be used
on mobile, where taps are not as precise as mouse clicks. Player could
slightly move their finger when tapping, in which case we still want
the button to be pressed rather than the container to be scrolled.
(cherry picked from commit dcf5be92a3
)
This commit is contained in:
parent
ef44ed93a7
commit
710b57d493
|
@ -252,7 +252,7 @@ void BaseButton::_notification(int p_what) {
|
||||||
status.hovering = false;
|
status.hovering = false;
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
if (p_what == NOTIFICATION_DRAG_BEGIN) {
|
if (p_what == NOTIFICATION_DRAG_BEGIN || p_what == NOTIFICATION_SCROLL_BEGIN) {
|
||||||
|
|
||||||
if (status.press_attempt) {
|
if (status.press_attempt) {
|
||||||
status.press_attempt = false;
|
status.press_attempt = false;
|
||||||
|
|
|
@ -2884,6 +2884,8 @@ void Control::_bind_methods() {
|
||||||
BIND_CONSTANT(NOTIFICATION_FOCUS_EXIT);
|
BIND_CONSTANT(NOTIFICATION_FOCUS_EXIT);
|
||||||
BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
|
BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
|
||||||
BIND_CONSTANT(NOTIFICATION_MODAL_CLOSE);
|
BIND_CONSTANT(NOTIFICATION_MODAL_CLOSE);
|
||||||
|
BIND_CONSTANT(NOTIFICATION_SCROLL_BEGIN);
|
||||||
|
BIND_CONSTANT(NOTIFICATION_SCROLL_END);
|
||||||
|
|
||||||
BIND_ENUM_CONSTANT(CURSOR_ARROW);
|
BIND_ENUM_CONSTANT(CURSOR_ARROW);
|
||||||
BIND_ENUM_CONSTANT(CURSOR_IBEAM);
|
BIND_ENUM_CONSTANT(CURSOR_IBEAM);
|
||||||
|
|
|
@ -271,6 +271,8 @@ public:
|
||||||
NOTIFICATION_FOCUS_EXIT = 44,
|
NOTIFICATION_FOCUS_EXIT = 44,
|
||||||
NOTIFICATION_THEME_CHANGED = 45,
|
NOTIFICATION_THEME_CHANGED = 45,
|
||||||
NOTIFICATION_MODAL_CLOSE = 46,
|
NOTIFICATION_MODAL_CLOSE = 46,
|
||||||
|
NOTIFICATION_SCROLL_BEGIN = 47,
|
||||||
|
NOTIFICATION_SCROLL_END = 48,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,12 @@ void ScrollContainer::_cancel_drag() {
|
||||||
drag_accum = Vector2();
|
drag_accum = Vector2();
|
||||||
last_drag_accum = Vector2();
|
last_drag_accum = Vector2();
|
||||||
drag_from = Vector2();
|
drag_from = Vector2();
|
||||||
|
|
||||||
|
if (beyond_deadzone) {
|
||||||
|
emit_signal("scroll_ended");
|
||||||
|
propagate_notification(NOTIFICATION_SCROLL_END);
|
||||||
|
beyond_deadzone = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
||||||
|
@ -122,13 +128,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
||||||
if (mb->is_pressed()) {
|
if (mb->is_pressed()) {
|
||||||
|
|
||||||
if (drag_touching) {
|
if (drag_touching) {
|
||||||
set_physics_process(false);
|
_cancel_drag();
|
||||||
drag_touching_deaccel = false;
|
|
||||||
drag_touching = false;
|
|
||||||
drag_speed = Vector2();
|
|
||||||
drag_accum = Vector2();
|
|
||||||
last_drag_accum = Vector2();
|
|
||||||
drag_from = Vector2();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (true) {
|
if (true) {
|
||||||
|
@ -138,6 +138,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
||||||
drag_from = Vector2(h_scroll->get_value(), v_scroll->get_value());
|
drag_from = Vector2(h_scroll->get_value(), v_scroll->get_value());
|
||||||
drag_touching = OS::get_singleton()->has_touchscreen_ui_hint();
|
drag_touching = OS::get_singleton()->has_touchscreen_ui_hint();
|
||||||
drag_touching_deaccel = false;
|
drag_touching_deaccel = false;
|
||||||
|
beyond_deadzone = false;
|
||||||
time_since_motion = 0;
|
time_since_motion = 0;
|
||||||
if (drag_touching) {
|
if (drag_touching) {
|
||||||
set_physics_process(true);
|
set_physics_process(true);
|
||||||
|
@ -149,9 +150,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
||||||
if (drag_touching) {
|
if (drag_touching) {
|
||||||
|
|
||||||
if (drag_speed == Vector2()) {
|
if (drag_speed == Vector2()) {
|
||||||
drag_touching_deaccel = false;
|
_cancel_drag();
|
||||||
drag_touching = false;
|
|
||||||
set_physics_process(false);
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
drag_touching_deaccel = true;
|
drag_touching_deaccel = true;
|
||||||
|
@ -168,8 +167,17 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
||||||
|
|
||||||
Vector2 motion = Vector2(mm->get_relative().x, mm->get_relative().y);
|
Vector2 motion = Vector2(mm->get_relative().x, mm->get_relative().y);
|
||||||
drag_accum -= motion;
|
drag_accum -= motion;
|
||||||
Vector2 diff = drag_from + drag_accum;
|
|
||||||
|
|
||||||
|
if (beyond_deadzone || scroll_h && Math::abs(drag_accum.x) > deadzone || scroll_v && Math::abs(drag_accum.y) > deadzone) {
|
||||||
|
if (!beyond_deadzone) {
|
||||||
|
propagate_notification(NOTIFICATION_SCROLL_BEGIN);
|
||||||
|
emit_signal("scroll_started");
|
||||||
|
|
||||||
|
beyond_deadzone = true;
|
||||||
|
// resetting drag_accum here ensures smooth scrolling after reaching deadzone
|
||||||
|
drag_accum = -motion;
|
||||||
|
}
|
||||||
|
Vector2 diff = drag_from + drag_accum;
|
||||||
if (scroll_h)
|
if (scroll_h)
|
||||||
h_scroll->set_value(diff.x);
|
h_scroll->set_value(diff.x);
|
||||||
else
|
else
|
||||||
|
@ -181,6 +189,7 @@ void ScrollContainer::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
||||||
time_since_motion = 0;
|
time_since_motion = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ref<InputEventPanGesture> pan_gesture = p_gui_input;
|
Ref<InputEventPanGesture> pan_gesture = p_gui_input;
|
||||||
if (pan_gesture.is_valid()) {
|
if (pan_gesture.is_valid()) {
|
||||||
|
@ -323,9 +332,7 @@ void ScrollContainer::_notification(int p_what) {
|
||||||
drag_speed = Vector2(sgn_x * val_x, sgn_y * val_y);
|
drag_speed = Vector2(sgn_x * val_x, sgn_y * val_y);
|
||||||
|
|
||||||
if (turnoff_h && turnoff_v) {
|
if (turnoff_h && turnoff_v) {
|
||||||
set_physics_process(false);
|
_cancel_drag();
|
||||||
drag_touching = false;
|
|
||||||
drag_touching_deaccel = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
@ -430,6 +437,14 @@ void ScrollContainer::set_h_scroll(int p_pos) {
|
||||||
_cancel_drag();
|
_cancel_drag();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ScrollContainer::get_deadzone() const {
|
||||||
|
return deadzone;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ScrollContainer::set_deadzone(int p_deadzone) {
|
||||||
|
deadzone = p_deadzone;
|
||||||
|
}
|
||||||
|
|
||||||
String ScrollContainer::get_configuration_warning() const {
|
String ScrollContainer::get_configuration_warning() const {
|
||||||
|
|
||||||
int found = 0;
|
int found = 0;
|
||||||
|
@ -466,12 +481,20 @@ void ScrollContainer::_bind_methods() {
|
||||||
ClassDB::bind_method(D_METHOD("get_h_scroll"), &ScrollContainer::get_h_scroll);
|
ClassDB::bind_method(D_METHOD("get_h_scroll"), &ScrollContainer::get_h_scroll);
|
||||||
ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &ScrollContainer::set_v_scroll);
|
ClassDB::bind_method(D_METHOD("set_v_scroll", "value"), &ScrollContainer::set_v_scroll);
|
||||||
ClassDB::bind_method(D_METHOD("get_v_scroll"), &ScrollContainer::get_v_scroll);
|
ClassDB::bind_method(D_METHOD("get_v_scroll"), &ScrollContainer::get_v_scroll);
|
||||||
|
ClassDB::bind_method(D_METHOD("set_deadzone", "deadzone"), &ScrollContainer::set_deadzone);
|
||||||
|
ClassDB::bind_method(D_METHOD("get_deadzone"), &ScrollContainer::get_deadzone);
|
||||||
|
|
||||||
|
ADD_SIGNAL(MethodInfo("scroll_started"));
|
||||||
|
ADD_SIGNAL(MethodInfo("scroll_ended"));
|
||||||
|
|
||||||
ADD_GROUP("Scroll", "scroll_");
|
ADD_GROUP("Scroll", "scroll_");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal_enabled"), "set_enable_h_scroll", "is_h_scroll_enabled");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_horizontal_enabled"), "set_enable_h_scroll", "is_h_scroll_enabled");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_horizontal"), "set_h_scroll", "get_h_scroll");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_horizontal"), "set_h_scroll", "get_h_scroll");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical_enabled"), "set_enable_v_scroll", "is_v_scroll_enabled");
|
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll_vertical_enabled"), "set_enable_v_scroll", "is_v_scroll_enabled");
|
||||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_vertical"), "set_v_scroll", "get_v_scroll");
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_vertical"), "set_v_scroll", "get_v_scroll");
|
||||||
|
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll_deadzone"), "set_deadzone", "get_deadzone");
|
||||||
|
|
||||||
|
GLOBAL_DEF("gui/common/default_scroll_deadzone", 0);
|
||||||
};
|
};
|
||||||
|
|
||||||
ScrollContainer::ScrollContainer() {
|
ScrollContainer::ScrollContainer() {
|
||||||
|
@ -490,8 +513,11 @@ ScrollContainer::ScrollContainer() {
|
||||||
drag_speed = Vector2();
|
drag_speed = Vector2();
|
||||||
drag_touching = false;
|
drag_touching = false;
|
||||||
drag_touching_deaccel = false;
|
drag_touching_deaccel = false;
|
||||||
|
beyond_deadzone = false;
|
||||||
scroll_h = true;
|
scroll_h = true;
|
||||||
scroll_v = true;
|
scroll_v = true;
|
||||||
|
|
||||||
|
deadzone = GLOBAL_GET("gui/common/default_scroll_deadzone");
|
||||||
|
|
||||||
set_clip_contents(true);
|
set_clip_contents(true);
|
||||||
};
|
};
|
||||||
|
|
|
@ -56,10 +56,13 @@ class ScrollContainer : public Container {
|
||||||
bool drag_touching;
|
bool drag_touching;
|
||||||
bool drag_touching_deaccel;
|
bool drag_touching_deaccel;
|
||||||
bool click_handled;
|
bool click_handled;
|
||||||
|
bool beyond_deadzone;
|
||||||
|
|
||||||
bool scroll_h;
|
bool scroll_h;
|
||||||
bool scroll_v;
|
bool scroll_v;
|
||||||
|
|
||||||
|
int deadzone;
|
||||||
|
|
||||||
void _cancel_drag();
|
void _cancel_drag();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -86,6 +89,9 @@ public:
|
||||||
void set_enable_v_scroll(bool p_enable);
|
void set_enable_v_scroll(bool p_enable);
|
||||||
bool is_v_scroll_enabled() const;
|
bool is_v_scroll_enabled() const;
|
||||||
|
|
||||||
|
int get_deadzone() const;
|
||||||
|
void set_deadzone(int p_deadzone);
|
||||||
|
|
||||||
virtual bool clips_input() const;
|
virtual bool clips_input() const;
|
||||||
|
|
||||||
virtual String get_configuration_warning() const;
|
virtual String get_configuration_warning() const;
|
||||||
|
|
Loading…
Reference in New Issue