Improved the mouse focus system (mouse keeps focus on a control while buttons are pressed). Fixes #19154 and likely many others.
WARNING: Test well in every OS, if mouse wheel events are not properly sent as pressed+unpressed pair, it will fail and break (and the OS needs to be fixed). Only tested on X11 so far.
This commit is contained in:
parent
05755618c5
commit
39028cc161
|
@ -189,7 +189,7 @@ Viewport::GUI::GUI() {
|
||||||
dragging = false;
|
dragging = false;
|
||||||
mouse_focus = NULL;
|
mouse_focus = NULL;
|
||||||
mouse_click_grabber = NULL;
|
mouse_click_grabber = NULL;
|
||||||
mouse_focus_button = -1;
|
mouse_focus_mask = 0;
|
||||||
key_focus = NULL;
|
key_focus = NULL;
|
||||||
mouse_over = NULL;
|
mouse_over = NULL;
|
||||||
|
|
||||||
|
@ -671,15 +671,7 @@ void Viewport::_notification(int p_what) {
|
||||||
case SceneTree::NOTIFICATION_WM_FOCUS_OUT: {
|
case SceneTree::NOTIFICATION_WM_FOCUS_OUT: {
|
||||||
if (gui.mouse_focus) {
|
if (gui.mouse_focus) {
|
||||||
//if mouse is being pressed, send a release event
|
//if mouse is being pressed, send a release event
|
||||||
Ref<InputEventMouseButton> mb;
|
_drop_mouse_focus();
|
||||||
mb.instance();
|
|
||||||
mb->set_position(gui.mouse_focus->get_local_mouse_position());
|
|
||||||
mb->set_global_position(gui.mouse_focus->get_local_mouse_position());
|
|
||||||
mb->set_button_index(gui.mouse_focus_button);
|
|
||||||
mb->set_pressed(false);
|
|
||||||
Control *c = gui.mouse_focus;
|
|
||||||
gui.mouse_focus = NULL;
|
|
||||||
c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
|
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
}
|
}
|
||||||
|
@ -1686,10 +1678,10 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
||||||
if (mb->is_pressed()) {
|
if (mb->is_pressed()) {
|
||||||
|
|
||||||
Size2 pos = mpos;
|
Size2 pos = mpos;
|
||||||
if (gui.mouse_focus && mb->get_button_index() != gui.mouse_focus_button) {
|
if (gui.mouse_focus_mask) {
|
||||||
|
|
||||||
//do not steal mouse focus and stuff
|
|
||||||
|
|
||||||
|
//do not steal mouse focus and stuff while a focus mask exists
|
||||||
|
gui.mouse_focus_mask |= 1 << (mb->get_button_index() - 1); //add the button to the mask
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
bool is_handled = false;
|
bool is_handled = false;
|
||||||
|
@ -1734,7 +1726,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
gui.mouse_focus = _gui_find_control(pos);
|
gui.mouse_focus = _gui_find_control(pos);
|
||||||
gui.mouse_focus_button = mb->get_button_index();
|
gui.mouse_focus_mask = 1 << (mb->get_button_index() - 1);
|
||||||
|
|
||||||
if (!gui.mouse_focus) {
|
if (!gui.mouse_focus) {
|
||||||
return;
|
return;
|
||||||
|
@ -1837,6 +1829,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
||||||
//change mouse accordingly
|
//change mouse accordingly
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gui.mouse_focus_mask &= ~(1 << (mb->get_button_index() - 1)); //remove from mask
|
||||||
|
|
||||||
if (!gui.mouse_focus) {
|
if (!gui.mouse_focus) {
|
||||||
//release event is only sent if a mouse focus (previously pressed button) exists
|
//release event is only sent if a mouse focus (previously pressed button) exists
|
||||||
return;
|
return;
|
||||||
|
@ -1852,9 +1846,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
||||||
Control *mouse_focus = gui.mouse_focus;
|
Control *mouse_focus = gui.mouse_focus;
|
||||||
|
|
||||||
//disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise
|
//disable mouse focus if needed before calling input, this makes popups on mouse press event work better, as the release will never be received otherwise
|
||||||
if (mb->get_button_index() == gui.mouse_focus_button) {
|
if (gui.mouse_focus_mask == 0) {
|
||||||
gui.mouse_focus = NULL;
|
gui.mouse_focus = NULL;
|
||||||
gui.mouse_focus_button = -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mouse_focus->can_process()) {
|
if (mouse_focus->can_process()) {
|
||||||
|
@ -1900,6 +1893,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
|
||||||
if (gui.drag_data.get_type() != Variant::NIL) {
|
if (gui.drag_data.get_type() != Variant::NIL) {
|
||||||
|
|
||||||
gui.mouse_focus = NULL;
|
gui.mouse_focus = NULL;
|
||||||
|
gui.mouse_focus_mask = 0;
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
if (gui.drag_preview != NULL) {
|
if (gui.drag_preview != NULL) {
|
||||||
|
@ -2412,7 +2406,7 @@ void Viewport::_gui_unfocus_control(Control *p_control) {
|
||||||
void Viewport::_gui_hid_control(Control *p_control) {
|
void Viewport::_gui_hid_control(Control *p_control) {
|
||||||
|
|
||||||
if (gui.mouse_focus == p_control) {
|
if (gui.mouse_focus == p_control) {
|
||||||
gui.mouse_focus = NULL;
|
_drop_mouse_focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ???
|
/* ???
|
||||||
|
@ -2439,8 +2433,10 @@ void Viewport::_gui_hid_control(Control *p_control) {
|
||||||
|
|
||||||
void Viewport::_gui_remove_control(Control *p_control) {
|
void Viewport::_gui_remove_control(Control *p_control) {
|
||||||
|
|
||||||
if (gui.mouse_focus == p_control)
|
if (gui.mouse_focus == p_control) {
|
||||||
gui.mouse_focus = NULL;
|
gui.mouse_focus = NULL;
|
||||||
|
gui.mouse_focus_mask = 0;
|
||||||
|
}
|
||||||
if (gui.key_focus == p_control)
|
if (gui.key_focus == p_control)
|
||||||
gui.key_focus = NULL;
|
gui.key_focus = NULL;
|
||||||
if (gui.mouse_over == p_control)
|
if (gui.mouse_over == p_control)
|
||||||
|
@ -2489,6 +2485,27 @@ void Viewport::_gui_accept_event() {
|
||||||
set_input_as_handled();
|
set_input_as_handled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Viewport::_drop_mouse_focus() {
|
||||||
|
|
||||||
|
Control *c = gui.mouse_focus;
|
||||||
|
int mask = gui.mouse_focus_mask;
|
||||||
|
gui.mouse_focus = NULL;
|
||||||
|
gui.mouse_focus_mask = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
|
||||||
|
if (mask & (1 << i)) {
|
||||||
|
Ref<InputEventMouseButton> mb;
|
||||||
|
mb.instance();
|
||||||
|
mb->set_position(c->get_local_mouse_position());
|
||||||
|
mb->set_global_position(gui.mouse_focus->get_local_mouse_position());
|
||||||
|
mb->set_button_index(i + 1);
|
||||||
|
mb->set_pressed(false);
|
||||||
|
c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
|
List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
|
||||||
|
|
||||||
gui.modal_stack.push_back(p_control);
|
gui.modal_stack.push_back(p_control);
|
||||||
|
@ -2498,15 +2515,8 @@ List<Control *>::Element *Viewport::_gui_show_modal(Control *p_control) {
|
||||||
p_control->_modal_set_prev_focus_owner(0);
|
p_control->_modal_set_prev_focus_owner(0);
|
||||||
|
|
||||||
if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) {
|
if (gui.mouse_focus && !p_control->is_a_parent_of(gui.mouse_focus) && !gui.mouse_click_grabber) {
|
||||||
Ref<InputEventMouseButton> mb;
|
|
||||||
mb.instance();
|
_drop_mouse_focus();
|
||||||
mb->set_position(gui.mouse_focus->get_local_mouse_position());
|
|
||||||
mb->set_global_position(gui.mouse_focus->get_local_mouse_position());
|
|
||||||
mb->set_button_index(gui.mouse_focus_button);
|
|
||||||
mb->set_pressed(false);
|
|
||||||
Control *c = gui.mouse_focus;
|
|
||||||
gui.mouse_focus = NULL;
|
|
||||||
c->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return gui.modal_stack.back();
|
return gui.modal_stack.back();
|
||||||
|
@ -2536,26 +2546,47 @@ void Viewport::_post_gui_grab_click_focus() {
|
||||||
|
|
||||||
if (gui.mouse_focus == focus_grabber)
|
if (gui.mouse_focus == focus_grabber)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
int mask = gui.mouse_focus_mask;
|
||||||
|
Point2 click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
|
||||||
|
if (mask & (1 << i)) {
|
||||||
|
|
||||||
Ref<InputEventMouseButton> mb;
|
Ref<InputEventMouseButton> mb;
|
||||||
mb.instance();
|
mb.instance();
|
||||||
|
|
||||||
//send unclic
|
//send unclic
|
||||||
|
|
||||||
Point2 click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
|
|
||||||
mb->set_position(click);
|
mb->set_position(click);
|
||||||
mb->set_button_index(gui.mouse_focus_button);
|
mb->set_button_index(i + 1);
|
||||||
mb->set_pressed(false);
|
mb->set_pressed(false);
|
||||||
gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
|
gui.mouse_focus->call_multilevel(SceneStringNames::get_singleton()->_gui_input, mb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gui.mouse_focus = focus_grabber;
|
gui.mouse_focus = focus_grabber;
|
||||||
gui.focus_inv_xform = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse();
|
gui.focus_inv_xform = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse();
|
||||||
click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
|
click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
|
||||||
|
|
||||||
|
for (int i = 0; i < 3; i++) {
|
||||||
|
|
||||||
|
if (mask & (1 << i)) {
|
||||||
|
|
||||||
|
Ref<InputEventMouseButton> mb;
|
||||||
|
mb.instance();
|
||||||
|
|
||||||
|
//send clic
|
||||||
|
|
||||||
mb->set_position(click);
|
mb->set_position(click);
|
||||||
mb->set_button_index(gui.mouse_focus_button);
|
mb->set_button_index(i + 1);
|
||||||
mb->set_pressed(true);
|
mb->set_pressed(true);
|
||||||
gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb);
|
gui.mouse_focus->call_deferred(SceneStringNames::get_singleton()->_gui_input, mb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
|
|
||||||
|
|
|
@ -272,7 +272,7 @@ private:
|
||||||
bool key_event_accepted;
|
bool key_event_accepted;
|
||||||
Control *mouse_focus;
|
Control *mouse_focus;
|
||||||
Control *mouse_click_grabber;
|
Control *mouse_click_grabber;
|
||||||
int mouse_focus_button;
|
int mouse_focus_mask;
|
||||||
Control *key_focus;
|
Control *key_focus;
|
||||||
Control *mouse_over;
|
Control *mouse_over;
|
||||||
Control *tooltip;
|
Control *tooltip;
|
||||||
|
@ -379,6 +379,8 @@ private:
|
||||||
void _canvas_layer_add(CanvasLayer *p_canvas_layer);
|
void _canvas_layer_add(CanvasLayer *p_canvas_layer);
|
||||||
void _canvas_layer_remove(CanvasLayer *p_canvas_layer);
|
void _canvas_layer_remove(CanvasLayer *p_canvas_layer);
|
||||||
|
|
||||||
|
void _drop_mouse_focus();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void _notification(int p_what);
|
void _notification(int p_what);
|
||||||
static void _bind_methods();
|
static void _bind_methods();
|
||||||
|
|
Loading…
Reference in New Issue