Browse Source

Fix selecting popup menu items on mouse release

Robert Yevdokimov 1 year ago
parent
commit
06c2cda848
2 changed files with 50 additions and 45 deletions
  1. 48 43
      scene/gui/popup_menu.cpp
  2. 2 2
      scene/gui/popup_menu.h

+ 48 - 43
scene/gui/popup_menu.cpp

@@ -438,6 +438,9 @@ void PopupMenu::_input_from_window(const Ref<InputEvent> &p_event) {
 }
 
 void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
+	Ref<InputEventMouseButton> b = p_event;
+	Ref<InputEventMouseMotion> m = p_event;
+
 	if (!items.is_empty()) {
 		Input *input = Input::get_singleton();
 		Ref<InputEventJoypadMotion> joypadmotion_event = p_event;
@@ -566,52 +569,57 @@ void PopupMenu::_input_from_window_internal(const Ref<InputEvent> &p_event) {
 		}
 	}
 
-	Ref<InputEventMouseButton> b = p_event;
+	if (m.is_valid() && drag_to_press) {
+		BitField<MouseButtonMask> initial_button_mask = m->get_button_mask();
+		if (!initial_button_mask.has_flag(mouse_button_to_mask(MouseButton::LEFT)) && !initial_button_mask.has_flag(mouse_button_to_mask(MouseButton::RIGHT))) {
+			mouse_is_pressed = false;
+		}
 
-	if (b.is_valid()) {
-		if (!item_clickable_area.has_point(b->get_position())) {
-			return;
+		if (!item_clickable_area.has_point(m->get_position()) && !mouse_is_pressed) {
+			drag_to_press = false;
 		}
+	}
 
-		MouseButton button_idx = b->get_button_index();
-		if (!b->is_pressed()) {
-			// Activate the item on release of either the left mouse button or
-			// any mouse button held down when the popup was opened.
-			// This allows for opening the popup and triggering an action in a single mouse click.
-			if (button_idx == MouseButton::LEFT || initial_button_mask.has_flag(mouse_button_to_mask(button_idx))) {
-				bool was_during_grabbed_click = during_grabbed_click;
-				during_grabbed_click = false;
-				initial_button_mask.clear();
-
-				// Disable clicks under a time threshold to avoid selection right when opening the popup.
-				uint64_t now = OS::get_singleton()->get_ticks_msec();
-				uint64_t diff = now - popup_time_msec;
-				if (diff < 150) {
-					return;
-				}
+	if ((b.is_valid() && b->is_pressed()) || (!mouse_is_pressed && drag_to_press)) {
+		if (b.is_valid()) {
+			MouseButton button_idx = b->get_button_index();
+			if (button_idx != MouseButton::LEFT && button_idx != MouseButton::RIGHT) {
+				return;
+			}
+		} else {
+			uint64_t now = OS::get_singleton()->get_ticks_msec();
+			uint64_t diff = now - popup_time_msec;
+			if (diff < 250) {
+				drag_to_press = false;
+				return;
+			}
+		}
 
-				int over = _get_mouse_over(b->get_position());
-				if (over < 0) {
-					if (!was_during_grabbed_click) {
-						hide();
-					}
-					return;
-				}
+		drag_to_press = false;
 
-				if (items[over].separator || items[over].disabled) {
-					return;
-				}
+		int over = -1;
 
-				if (!items[over].submenu.is_empty()) {
-					_activate_submenu(over);
-					return;
-				}
-				activate_item(over);
-			}
+		if (m.is_valid()) {
+			over = _get_mouse_over(m->get_position());
+		} else if (b.is_valid()) {
+			over = _get_mouse_over(b->get_position());
 		}
-	}
 
-	Ref<InputEventMouseMotion> m = p_event;
+		if (over < 0) {
+			hide();
+			return;
+		}
+
+		if (items[over].separator || items[over].disabled) {
+			return;
+		}
+
+		if (!items[over].submenu.is_empty()) {
+			_activate_submenu(over);
+			return;
+		}
+		activate_item(over);
+	}
 
 	if (m.is_valid()) {
 		if (m->get_velocity().is_zero_approx()) {
@@ -1046,11 +1054,6 @@ void PopupMenu::_notification(int p_what) {
 			}
 		} break;
 
-		case NOTIFICATION_POST_POPUP: {
-			initial_button_mask = Input::get_singleton()->get_mouse_button_mask();
-			during_grabbed_click = (bool)initial_button_mask;
-		} break;
-
 		case NOTIFICATION_INTERNAL_PROCESS: {
 			Input *input = Input::get_singleton();
 
@@ -2844,6 +2847,8 @@ void PopupMenu::popup(const Rect2i &p_bounds) {
 	moved = Vector2();
 	popup_time_msec = OS::get_singleton()->get_ticks_msec();
 	Popup::popup(p_bounds);
+	drag_to_press = true;
+	mouse_is_pressed = true;
 }
 
 PopupMenu::PopupMenu() {

+ 2 - 2
scene/gui/popup_menu.h

@@ -101,8 +101,8 @@ class PopupMenu : public Popup {
 	Timer *submenu_timer = nullptr;
 	List<Rect2> autohide_areas;
 	Vector<Item> items;
-	BitField<MouseButtonMask> initial_button_mask;
-	bool during_grabbed_click = false;
+	bool mouse_is_pressed = true;
+	bool drag_to_press = true;
 	int mouse_over = -1;
 	int submenu_over = -1;
 	String _get_accel_text(const Item &p_item) const;