Make BaseButton not emit press when container is scrolled [2.1]

This fixes the problem described in #13996 in a proper way.
This also adds "deadzone" property to ScrollContainer.
It can be usedon mobile, where taps are not as precise as mouse clicks.
Player couldslightly move their finger when tapping, in which case we still wantthe button to be pressed rather than the container to be scrolled.
(cherry picked from commit dcf5be9)
This commit is contained in:
allkhor 2018-07-16 03:49:49 +06:00
parent 241ca9624e
commit 37c43154fe
5 changed files with 59 additions and 24 deletions

View File

@ -225,7 +225,7 @@ void BaseButton::_notification(int p_what) {
status.hovering = false;
update();
}
if (p_what == NOTIFICATION_DRAG_BEGIN) {
if (p_what == NOTIFICATION_DRAG_BEGIN || p_what == NOTIFICATION_SCROLL_BEGIN) {
if (status.press_attempt) {
status.press_attempt = false;

View File

@ -2361,6 +2361,8 @@ void Control::_bind_methods() {
BIND_CONSTANT(NOTIFICATION_FOCUS_EXIT);
BIND_CONSTANT(NOTIFICATION_THEME_CHANGED);
BIND_CONSTANT(NOTIFICATION_MODAL_CLOSE);
BIND_CONSTANT(NOTIFICATION_SCROLL_BEGIN);
BIND_CONSTANT(NOTIFICATION_SCROLL_END);
BIND_CONSTANT(CURSOR_ARROW);
BIND_CONSTANT(CURSOR_IBEAM);

View File

@ -218,6 +218,8 @@ public:
NOTIFICATION_FOCUS_EXIT = 44,
NOTIFICATION_THEME_CHANGED = 45,
NOTIFICATION_MODAL_CLOSE = 46,
NOTIFICATION_SCROLL_BEGIN = 47,
NOTIFICATION_SCROLL_END = 48,
};

View File

@ -74,6 +74,12 @@ void ScrollContainer::_cancel_drag() {
drag_accum = Vector2();
last_drag_accum = Vector2();
drag_from = Vector2();
if (beyond_deadzone) {
emit_signal("scroll_ended");
propagate_notification(NOTIFICATION_SCROLL_END);
beyond_deadzone = false;
}
}
void ScrollContainer::_input_event(const InputEvent &p_input_event) {
@ -123,13 +129,7 @@ void ScrollContainer::_input_event(const InputEvent &p_input_event) {
if (mb.pressed) {
if (drag_touching) {
set_fixed_process(false);
drag_touching_deaccel = false;
drag_touching = false;
drag_speed = Vector2();
drag_accum = Vector2();
last_drag_accum = Vector2();
drag_from = Vector2();
_cancel_drag();
}
if (true) {
@ -139,6 +139,7 @@ void ScrollContainer::_input_event(const InputEvent &p_input_event) {
drag_from = Vector2(h_scroll->get_val(), v_scroll->get_val());
drag_touching = OS::get_singleton()->has_touchscreen_ui_hint();
drag_touching_deaccel = false;
beyond_deadzone = false;
time_since_motion = 0;
if (drag_touching) {
set_fixed_process(true);
@ -150,9 +151,7 @@ void ScrollContainer::_input_event(const InputEvent &p_input_event) {
if (drag_touching) {
if (drag_speed == Vector2()) {
drag_touching_deaccel = false;
drag_touching = false;
set_fixed_process(false);
_cancel_drag();
} else {
drag_touching_deaccel = true;
@ -169,17 +168,26 @@ void ScrollContainer::_input_event(const InputEvent &p_input_event) {
Vector2 motion = Vector2(mm.relative_x, mm.relative_y);
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");
if (scroll_h)
h_scroll->set_val(diff.x);
else
drag_accum.x = 0;
if (scroll_v)
v_scroll->set_val(diff.y);
else
drag_accum.y = 0;
time_since_motion = 0;
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)
h_scroll->set_val(diff.x);
else
drag_accum.x = 0;
if (scroll_v)
v_scroll->set_val(diff.y);
else
drag_accum.y = 0;
time_since_motion = 0;
}
}
} break;
@ -317,9 +325,7 @@ void ScrollContainer::_notification(int p_what) {
drag_speed = Vector2(sgn_x * val_x, sgn_y * val_y);
if (turnoff_h && turnoff_v) {
set_fixed_process(false);
drag_touching = false;
drag_touching_deaccel = false;
_cancel_drag();
}
} else {
@ -407,6 +413,7 @@ int ScrollContainer::get_v_scroll() const {
return v_scroll->get_val();
}
void ScrollContainer::set_v_scroll(int p_pos) {
v_scroll->set_val(p_pos);
@ -417,12 +424,21 @@ int ScrollContainer::get_h_scroll() const {
return h_scroll->get_val();
}
void ScrollContainer::set_h_scroll(int p_pos) {
h_scroll->set_val(p_pos);
_cancel_drag();
}
int ScrollContainer::get_deadzone() const {
return deadzone;
}
void ScrollContainer::set_deadzone(int p_deadzone) {
deadzone = p_deadzone;
}
void ScrollContainer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("_scroll_moved"), &ScrollContainer::_scroll_moved);
@ -436,9 +452,15 @@ void ScrollContainer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("get_h_scroll"), &ScrollContainer::get_h_scroll);
ObjectTypeDB::bind_method(_MD("set_v_scroll", "val"), &ScrollContainer::set_v_scroll);
ObjectTypeDB::bind_method(_MD("get_v_scroll"), &ScrollContainer::get_v_scroll);
ObjectTypeDB::bind_method(_MD("set_deadzone", "deadzone"), &ScrollContainer::set_deadzone);
ObjectTypeDB::bind_method(_MD("get_deadzone"), &ScrollContainer::get_deadzone);
ADD_SIGNAL(MethodInfo("scroll_started"));
ADD_SIGNAL(MethodInfo("scroll_ended"));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll/horizontal"), _SCS("set_enable_h_scroll"), _SCS("is_h_scroll_enabled"));
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scroll/vertical"), _SCS("set_enable_v_scroll"), _SCS("is_v_scroll_enabled"));
ADD_PROPERTY(PropertyInfo(Variant::INT, "scroll/deadzone"), _SCS("set_deadzone"), _SCS("get_deadzone"));
};
ScrollContainer::ScrollContainer() {
@ -457,6 +479,9 @@ ScrollContainer::ScrollContainer() {
drag_speed = Vector2();
drag_touching = false;
drag_touching_deaccel = false;
beyond_deadzone = false;
scroll_h = true;
scroll_v = true;
deadzone = GLOBAL_DEF("gui/common/default_scroll_deadzone", 0);
};

View File

@ -55,10 +55,13 @@ class ScrollContainer : public Container {
bool drag_touching;
bool drag_touching_deaccel;
bool click_handled;
bool beyond_deadzone;
bool scroll_h;
bool scroll_v;
int deadzone;
void _cancel_drag();
protected:
@ -85,6 +88,9 @@ public:
void set_enable_v_scroll(bool p_enable);
bool is_v_scroll_enabled() const;
int get_deadzone() const;
void set_deadzone(int p_deadzone);
virtual bool clips_input() const;
ScrollContainer();
};