Repository: MyreMylar/pygame_gui
Pull request #321 (2022-08-15 10:01:46)

Add option to drop down menu so only open/close button expands
Just set it to False to disable expanding the menu when the currently selected option is clicked.


Patch:
diff --git a/pygame_gui/elements/ui_drop_down_menu.py b/pygame_gui/elements/ui_drop_down_menu.py
index 3171205..2e1b663 100644
--- a/pygame_gui/elements/ui_drop_down_menu.py
+++ b/pygame_gui/elements/ui_drop_down_menu.py
@@ -43,7 +43,8 @@ class UIExpandedDropDownState:
                  manager: IUIManagerInterface,
                  container: IContainerLikeInterface,
                  object_ids: Union[List[Union[str, None]], None],
-                 element_ids: Union[List[str], None]):
+                 element_ids: Union[List[str], None],
+                 expand_on_option_click):
 
         self.drop_down_menu_ui = drop_down_menu_ui
         self.options_list = options_list
@@ -55,6 +56,7 @@ class UIExpandedDropDownState:
         self.ui_container = container
         self.element_ids = element_ids
         self.object_ids = object_ids
+        self.expand_on_option_click = expand_on_option_click
 
         # sizing variables
         self.options_list_height = 0
@@ -248,8 +250,12 @@ class UIExpandedDropDownState:
                  rest of the UI.
 
         """
-        if event.type == UI_BUTTON_PRESSED and event.ui_element in self.active_buttons:
-            self.should_transition = True
+        if event.type == UI_BUTTON_PRESSED:
+            if ((self.expand_on_option_click and event.ui_element in self.active_buttons) or
+                    (not self.expand_on_option_click and
+                     self.close_button is not None and event.ui_element == self.close_button)):
+                self.should_transition = True
+                return True
 
         if (event.type == UI_SELECTION_LIST_NEW_SELECTION and
                 event.ui_element == self.options_selection_list):
@@ -377,7 +383,8 @@ class UIClosedDropDownState:
                  container: IContainerLikeInterface,
                  object_ids: Union[List[Union[str, None]], None],
                  element_ids: Union[List[str], None],
-                 visible: int = 1):
+                 visible: int = 1,
+                 expand_on_option_click=True):
 
         self.drop_down_menu_ui = drop_down_menu_ui
         self.selected_option_button = None
@@ -392,6 +399,8 @@ class UIClosedDropDownState:
 
         self.open_button_width = open_button_width
 
+        self.expand_on_option_click = expand_on_option_click
+
         self.should_transition = False
         self.target_state = 'expanded'
         self.visible = visible
@@ -521,8 +530,12 @@ class UIClosedDropDownState:
         :return: Return True if we want to consume this event so it is not passed on to the
                  rest of the UI.
         """
-        if event.type == UI_BUTTON_PRESSED and event.ui_element in self.active_buttons:
-            self.should_transition = True
+        if event.type == UI_BUTTON_PRESSED:
+            if ((self.expand_on_option_click and event.ui_element in self.active_buttons) or
+                    (not self.expand_on_option_click and
+                     self.open_button is not None and event.ui_element == self.open_button)):
+                self.should_transition = True
+                return True
 
         return False
 
@@ -623,6 +636,9 @@ class UIDropDownMenu(UIContainer):
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
     :param visible: Whether the element is visible by default. Warning - container visibility
                     may override this.
+    :param expand_on_option_click: If this is set to False the drop down will only expand when
+                                   the open/close button is pressed and not when the selected
+                                   option is pressed.
     """
 
     def __init__(self,
@@ -635,7 +651,9 @@ class UIDropDownMenu(UIContainer):
                  object_id: Union[ObjectID, str, None] = None,
                  expansion_height_limit: Union[int, None] = None,
                  anchors: Dict[str, Union[str, UIElement]] = None,
-                 visible: int = 1
+                 visible: int = 1,
+                 *,
+                 expand_on_option_click: bool = True
                  ):
 
         super().__init__(relative_rect, manager, container=container,
@@ -653,6 +671,7 @@ class UIDropDownMenu(UIContainer):
         self.open_button_width = 20
 
         self.expansion_height_limit = expansion_height_limit
+        self.expand_on_option_click = expand_on_option_click
 
         self.border_width = None
         self.shadow_width = None
@@ -680,7 +699,8 @@ class UIDropDownMenu(UIContainer):
                                                             self,
                                                             self.element_ids,
                                                             self.object_ids,
-                                                            self.visible),
+                                                            self.visible,
+                                                            self.expand_on_option_click),
                             'expanded': UIExpandedDropDownState(self,
                                                                 self.options_list,
                                                                 self.selected_option,
@@ -690,7 +710,8 @@ class UIDropDownMenu(UIContainer):
                                                                 self.ui_manager,
                                                                 self,
                                                                 self.element_ids,
-                                                                self.object_ids
+                                                                self.object_ids,
+                                                                self.expand_on_option_click
                                                                 )}
         self.current_state = self.menu_states['closed']
         self.current_state.start(should_rebuild=True)


Test patch:
diff --git a/tests/test_elements/test_ui_drop_down_menu.py b/tests/test_elements/test_ui_drop_down_menu.py
index f84fb7e..3ab38d9 100644
--- a/tests/test_elements/test_ui_drop_down_menu.py
+++ b/tests/test_elements/test_ui_drop_down_menu.py
@@ -192,6 +192,38 @@ class TestUIDropDownMenu:
 
         assert confirm_drop_down_changed_event_fired
 
+        menu = UIDropDownMenu(options_list=['eggs', 'flour', 'sugar'],
+                              starting_option='eggs',
+                              relative_rect=pygame.Rect(100, 100, 200, 30),
+                              manager=default_ui_manager,
+                              expand_on_option_click=False)
+
+        # process a mouse button down event
+        menu.process_event(pygame.event.Event(
+            pygame_gui.UI_BUTTON_PRESSED, {'ui_element': menu.menu_states['closed'].open_button}))
+
+        assert menu.current_state.should_transition
+
+        menu.update(0.01)
+
+        assert not menu.current_state.should_transition
+
+        menu.process_event(pygame.event.Event(
+            pygame_gui.UI_BUTTON_PRESSED,
+            {'ui_element': menu.menu_states['expanded'].close_button}))
+
+        assert menu.current_state.should_transition
+
+        menu.update(0.01)
+
+        assert not menu.current_state.should_transition
+
+        menu.process_event(pygame.event.Event(
+            pygame_gui.UI_BUTTON_PRESSED,
+            {'ui_element': menu.menu_states['closed'].selected_option_button}))
+
+        assert not menu.current_state.should_transition
+
     def test_rebuild_from_theme_data_non_default(self, _init_pygame,
                                                  _display_surface_return_none):
         manager = UIManager((800, 600), os.path.join("tests", "data",