def test_selector(self) -> None: """ Test selector widget. """ menu = MenuUtils.generic_menu() selector = menu.add.selector('selector', [('1 - Easy', 'EASY'), ('2 - Medium', 'MEDIUM'), ('3 - Hard', 'HARD')], default=1) menu.enable() menu.draw(surface) selector.draw(surface) selector._selected = False selector.draw(surface) # Test events selector.update(PygameEventUtils.key(0, keydown=True, testmode=False)) selector.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)) selector.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True)) selector.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) selector.update(PygameEventUtils.joy_hat_motion(ctrl.JOY_LEFT)) selector.update(PygameEventUtils.joy_hat_motion(ctrl.JOY_RIGHT)) selector.update(PygameEventUtils.joy_motion(1, 0)) selector.update(PygameEventUtils.joy_motion(-1, 0)) click_pos = selector.get_rect(to_real_position=True, apply_padding=False).center selector.update( PygameEventUtils.mouse_click(click_pos[0], click_pos[1])) # Check left/right clicks self.assertEqual(selector.get_index(), 0) click_pos = selector.get_rect(to_real_position=True, apply_padding=False).midleft selector.update( PygameEventUtils.mouse_click(click_pos[0] + 150, click_pos[1])) self.assertEqual(selector.get_index(), 2) selector.update( PygameEventUtils.mouse_click(click_pos[0] + 150, click_pos[1])) self.assertEqual(selector.get_index(), 1) selector.update( PygameEventUtils.mouse_click(click_pos[0] + 150, click_pos[1])) self.assertEqual(selector.get_index(), 0) selector.update( PygameEventUtils.mouse_click(click_pos[0] + 250, click_pos[1])) self.assertEqual(selector.get_index(), 1) selector.update( PygameEventUtils.mouse_click(click_pos[0] + 250, click_pos[1])) self.assertEqual(selector.get_index(), 2) selector.update( PygameEventUtils.mouse_click(click_pos[0] + 250, click_pos[1])) self.assertEqual(selector.get_index(), 0) # Test left/right touch click_pos = selector.get_rect(to_real_position=True, apply_padding=False).midleft selector._touchscreen_enabled = True selector.update( PygameEventUtils.touch_click(click_pos[0] + 150, click_pos[1], menu=selector.get_menu())) self.assertEqual(selector.get_index(), 2) selector.update( PygameEventUtils.touch_click(click_pos[0] + 250, click_pos[1], menu=selector.get_menu())) self.assertEqual(selector.get_index(), 0) selector.update( PygameEventUtils.touch_click(click_pos[0] + 250, click_pos[1], menu=selector.get_menu())) self.assertEqual(selector.get_index(), 1) # Update elements new_elements = [('4 - Easy', 'EASY'), ('5 - Medium', 'MEDIUM'), ('6 - Hard', 'HARD')] selector.update_items(new_elements) selector.set_value('6 - Hard') self.assertEqual(selector.get_value()[1], 2) self.assertRaises(AssertionError, lambda: selector.set_value(bool)) self.assertRaises(AssertionError, lambda: selector.set_value(200)) selector.set_value(1) self.assertEqual(selector.get_value()[1], 1) self.assertEqual(selector.get_value()[0][0], '5 - Medium') selector.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)) self.assertEqual(selector.get_value()[0][0], '4 - Easy') selector.readonly = True selector.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)) self.assertEqual(selector.get_value()[0][0], '4 - Easy') selector._left() self.assertEqual(selector.get_value()[0][0], '4 - Easy') selector._right() self.assertEqual(selector.get_value()[0][0], '4 - Easy') # Test fancy selector sel_fancy = menu.add.selector( 'Fancy ', [('1 - Easy', 'EASY'), ('2 - Medium', 'MEDIUM'), ('3 - Hard', 'HARD')], default=1, style=pygame_menu.widgets.widget.selector.SELECTOR_STYLE_FANCY) self.assertEqual(sel_fancy.get_items(), [('1 - Easy', 'EASY'), ('2 - Medium', 'MEDIUM'), ('3 - Hard', 'HARD')]) self.assertRaises( AssertionError, lambda: menu.add.selector('title', [('a', 'a'), ('b', 'b')], default=2))
def test_toggleswitch(self) -> None: """ Test toggleswitch widget. """ menu = MenuUtils.generic_menu() value = [None] def onchange(val) -> None: """ Function executed by toggle. """ value[0] = val switch = menu.add.toggle_switch('toggle', False, onchange=onchange, infinite=False, single_click=False) self.assertFalse(switch.get_value()) self.assertIsNone(value[0]) switch.apply() self.assertFalse(value[0]) switch.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)) # not infinite self.assertFalse(value[0]) # as this is false, dont change switch.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True)) self.assertTrue(value[0]) switch.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)) self.assertFalse(value[0]) switch.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)) self.assertFalse(value[0]) self.assertFalse( switch.update( PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True, testmode=False))) switch = menu.add.toggle_switch('toggle', False, onchange=onchange, infinite=True, single_click=False) switch.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)) self.assertTrue(value[0]) switch.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)) self.assertFalse(value[0]) # As there's only 2 states, return should change too switch.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) self.assertTrue(value[0]) switch.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) self.assertFalse(value[0]) # Check left/right clicks click_pos = switch.get_rect(to_real_position=True, apply_padding=False).midleft switch.update( PygameEventUtils.mouse_click(click_pos[0] + 150, click_pos[1])) self.assertFalse(value[0]) switch.update( PygameEventUtils.mouse_click(click_pos[0] + 250, click_pos[1])) self.assertTrue(value[0]) switch.update( PygameEventUtils.mouse_click(click_pos[0] + 150, click_pos[1])) self.assertFalse(value[0]) # Test left/right touch switch._touchscreen_enabled = True switch.update( PygameEventUtils.touch_click(click_pos[0] + 250, click_pos[1], menu=switch.get_menu())) self.assertTrue(value[0]) switch.update( PygameEventUtils.touch_click(click_pos[0] + 250, click_pos[1], menu=switch.get_menu())) self.assertTrue(value[0]) switch.update( PygameEventUtils.touch_click(click_pos[0] + 150, click_pos[1], menu=switch.get_menu())) self.assertFalse(value[0]) # Test readonly switch.readonly = True switch.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) self.assertFalse(value[0]) switch.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) self.assertFalse(value[0]) switch.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) self.assertFalse(value[0]) switch._left() self.assertFalse(value[0]) switch._right() self.assertFalse(value[0]) switch.readonly = False switch.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True)) self.assertTrue(value[0]) switch.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True)) self.assertFalse(value[0]) switch.draw(surface) # Test transforms switch.set_position(1, 1) self.assertEqual(switch.get_position(), (1, 1)) switch.translate(1, 1) self.assertEqual(switch.get_translate(), (1, 1)) self.assertRaises(WidgetTransformationNotImplemented, lambda: switch.rotate(10)) self.assertEqual(switch._angle, 0) self.assertRaises(WidgetTransformationNotImplemented, lambda: switch.scale(100, 100)) self.assertFalse(switch._scale[0]) self.assertEqual(switch._scale[1], 1) self.assertEqual(switch._scale[2], 1) self.assertRaises(WidgetTransformationNotImplemented, lambda: switch.resize(100, 100)) self.assertFalse(switch._scale[0]) self.assertEqual(switch._scale[1], 1) self.assertEqual(switch._scale[2], 1) self.assertRaises(WidgetTransformationNotImplemented, lambda: switch.flip(True, True)) self.assertFalse(switch._flip[0]) self.assertFalse(switch._flip[1]) self.assertRaises(WidgetTransformationNotImplemented, lambda: switch.set_max_width(100)) self.assertIsNone(switch._max_width[0]) self.assertRaises(WidgetTransformationNotImplemented, lambda: switch.set_max_height(100)) self.assertIsNone(switch._max_height[0]) # Assert switch values self.assertRaises( ValueError, lambda: menu.add.toggle_switch( 'toggle', 'false', onchange=onchange, infinite=False)) # Test single click toggle switch_single = menu.add.toggle_switch('toggle', False, onchange=onchange) self.assertTrue(switch_single._infinite ) # Infinite sets to True if using single click self.assertFalse(switch_single.get_value()) switch_single._left() self.assertTrue(switch_single.get_value()) click_pos = switch_single.get_rect(to_real_position=True, apply_padding=False).midleft # Test single click toggle between two states switch_single.update( PygameEventUtils.mouse_click(click_pos[0] + 150, click_pos[1])) self.assertFalse( switch_single.get_value()) # single_click_dir=True, move to left switch_single.update( PygameEventUtils.mouse_click(click_pos[0] + 250, click_pos[1])) self.assertTrue(switch_single.get_value()) switch_single.update( PygameEventUtils.mouse_click(click_pos[0] + 250, click_pos[1])) self.assertFalse(switch_single.get_value()) switch_single._single_click_dir = False switch_single.update( PygameEventUtils.mouse_click(click_pos[0] + 250, click_pos[1])) self.assertTrue(switch_single.get_value()) # Create invalid single click params self.assertRaises( AssertionError, lambda: menu.add.toggle_switch( 'toggle', False, single_click='true')) self.assertRaises( AssertionError, lambda: menu.add.toggle_switch( 'toggle', False, single_click_dir='true')) # Test other constructor params pygame_menu.widgets.ToggleSwitch( 'Epic', state_text_font=menu._theme.widget_font) self.assertRaises( AssertionError, lambda: pygame_menu.widgets.ToggleSwitch('Epic', state_text_font_size=-1))
def test_dropselect(self) -> None: """ Test dropselect widget. """ menu = MenuUtils.generic_menu(mouse_motion_selection=True, theme=THEME_NON_FIXED_TITLE) items = [('This is a really long selection item', 1), ('epic', 2)] for i in range(10): items.append(('item{}'.format(i + 1), i + 1)) # noinspection SpellCheckingInspection drop = pygame_menu.widgets.DropSelect( 'dropsel', items, selection_option_font_size=int(0.75 * menu._theme.widget_font_size), placeholder_add_to_selection_box=False, selection_option_font=menu._theme.widget_font) menu.add.generic_widget(drop, configure_defaults=True) self.assertEqual( drop._selection_box_width, (207 if PYGAME_V2 else 208) if not SYS_PLATFORM_OSX else 209) self.assertEqual(drop.get_frame_depth(), 0) drop.render() self.assertTrue(drop._drop_frame.is_scrollable) drop_frame = drop._drop_frame self.assertIn(drop_frame, menu._update_frames) if PYGAME_V2: # noinspection SpellCheckingInspection self.assertEqual( menu._test_widgets_status(), ((('DropSelect-dropsel', (0, 0, 0, 123, 149, 354, 49, 123, 304, 123, 149), (1, 0, 1, 1, 0, 0, 0), ('Frame', (-1, -1, -1, 261, 193, 207, 136, 261, 348, 261, 193), (0, 0, 0, 0, 1, 0, 0), (-1, -1)), ('Button-This is a really long selection item', (-1, -1, -1, 0, -1, 356, 40, 261, 348, 0, 154), (1, 0, 0, 0, 0, 1, 1)), ('Button-epic', (-1, -1, -1, 0, 38, 356, 40, 261, 386, 0, 193), (1, 0, 0, 0, 0, 1, 1)), ('Button-item1', (-1, -1, -1, 0, 77, 356, 40, 261, 425, 0, 232), (1, 0, 0, 0, 0, 1, 1)), ('Button-item2', (-1, -1, -1, 0, 116, 356, 40, 261, 348, 0, 271), (1, 0, 0, 0, 0, 1, 1)), ('Button-item3', (-1, -1, -1, 0, 155, 356, 40, 261, 348, 0, 310), (1, 0, 0, 0, 0, 1, 1)), ('Button-item4', (-1, -1, -1, 0, 194, 356, 40, 261, 348, 0, 349), (1, 0, 0, 0, 0, 1, 1)), ('Button-item5', (-1, -1, -1, 0, 233, 356, 40, 261, 348, 0, 388), (1, 0, 0, 0, 0, 1, 1)), ('Button-item6', (-1, -1, -1, 0, 272, 356, 40, 261, 348, 0, 427), (1, 0, 0, 0, 0, 1, 1)), ('Button-item7', (-1, -1, -1, 0, 311, 356, 40, 261, 348, 0, 466), (1, 0, 0, 0, 0, 1, 1)), ('Button-item8', (-1, -1, -1, 0, 350, 356, 40, 261, 348, 0, 505), (1, 0, 0, 0, 0, 1, 1)), ('Button-item9', (-1, -1, -1, 0, 389, 356, 40, 261, 348, 0, 544), (1, 0, 0, 0, 0, 1, 1)), ('Button-item10', (-1, -1, -1, 0, 428, 356, 40, 261, 348, 0, 583), (1, 0, 0, 0, 0, 1, 1))), ))) self.assertEqual( drop._drop_frame.get_attribute('height'), (135 if PYGAME_V2 else 138) if not SYS_PLATFORM_OSX else 141) self.assertEqual( drop._drop_frame.get_attribute('width'), (187 if PYGAME_V2 else 188) if not SYS_PLATFORM_OSX else 189) # Test events self.assertFalse(drop.active) self.assertFalse(drop._drop_frame.is_visible()) drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) self.assertTrue(drop.active) self.assertTrue(drop._drop_frame.is_visible()) self.assertEqual(drop.get_index(), -1) drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True)) self.assertEqual(drop.get_index(), 0) self.assertTrue(drop.active) drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) self.assertFalse( drop.update( PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True, testmode=False))) self.assertFalse(drop.active) self.assertFalse(drop._drop_frame.is_visible()) drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_DOWN, keydown=True)) self.assertEqual(drop.get_index(), 0) self.assertFalse(drop.active) drop.update(PygameEventUtils.key(pygame.K_TAB, keydown=True)) # Enable self.assertTrue(drop.active) drop.update(PygameEventUtils.key(pygame.K_TAB, keydown=True)) self.assertFalse(drop.active) drop.update(PygameEventUtils.key(pygame.K_TAB, keydown=True)) # Enable self.assertTrue(drop.active) drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_DOWN, keydown=True)) # Not infinite self.assertEqual(drop.get_index(), 0) scroll_values = [ -1, 0, 0, 0.114, 0.228, 0.33, 0.447, 0.561, 0.664, 0.778, 0.895, 0.997 ] for i in range(1, 12): drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True)) self.assertEqual(drop.get_index(), i) if PYGAME_V2: self.assertEqual( drop.get_scroll_value_percentage(ORIENTATION_VERTICAL), scroll_values[i]) drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True)) # Not infinite self.assertEqual(drop.get_index(), 11) # Not infinite if PYGAME_V2: self.assertEqual( drop.get_scroll_value_percentage(ORIENTATION_VERTICAL), 0.997) # Mouseup over rect returns True updated status self.assertTrue(drop.active) self.assertTrue( drop.update( PygameEventUtils.middle_rect_click( drop.get_focus_rect(), evtype=pygame.MOUSEBUTTONDOWN))) self.assertTrue(drop.active) # Touch also does the same trick if PYGAME_V2: drop._touchscreen_enabled = True self.assertTrue( drop.update( PygameEventUtils.middle_rect_click(drop.get_focus_rect(), menu=menu, evtype=FINGERDOWN))) self.assertTrue(drop.active) # Scroll to bottom and close, then open again, this should scroll to current selected drop.scrollh(0) drop.scrollv(0) self.assertEqual( drop._drop_frame.get_scroll_value_percentage(ORIENTATION_VERTICAL), 0) drop._toggle_drop() drop._toggle_drop() if PYGAME_V2: self.assertEqual( drop._drop_frame.get_scroll_value_percentage( ORIENTATION_VERTICAL), 0.997) # Click drop box should toggle it self.assertTrue(drop.active) drop.update(PygameEventUtils.middle_rect_click(drop)) self.assertFalse(drop.active) drop.update(PygameEventUtils.middle_rect_click(drop)) self.assertTrue(drop.active) # Click middle option drop.update(PygameEventUtils.middle_rect_click(drop.get_focus_rect())) self.assertEqual(drop.get_index(), 10) self.assertFalse(drop.active) # Touch middle if not SYS_PLATFORM_OSX: self.assertTrue(drop._touchscreen_enabled) drop.update( PygameEventUtils.middle_rect_click(drop.get_focus_rect(), evtype=pygame.FINGERUP, menu=drop.get_menu())) self.assertTrue(drop.active) # Test focus if not drop.active: drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) if PYGAME_V2: self.assertEqual( menu._draw_focus_widget(surface, drop), { 1: ((0, 0), (600, 0), (600, 307), (0, 307)), 2: ((0, 308), (260, 308), (260, 483), (0, 483)), 3: ((468, 308), (600, 308), (600, 483), (468, 483)), 4: ((0, 484), (600, 484), (600, 600), (0, 600)) }) else: if not SYS_PLATFORM_OSX: self.assertEqual( menu._draw_focus_widget(surface, drop), { 1: ((0, 0), (600, 0), (600, 306), (0, 306)), 2: ((0, 307), (259, 307), (259, 486), (0, 486)), 3: ((468, 307), (600, 307), (600, 486), (468, 486)), 4: ((0, 487), (600, 487), (600, 600), (0, 600)) }) else: self.assertEqual( menu._draw_focus_widget(surface, drop), { 1: ((0, 0), (600, 0), (600, 305), (0, 305)), 2: ((0, 306), (259, 306), (259, 489), (0, 489)), 3: ((469, 306), (600, 306), (600, 489), (469, 489)), 4: ((0, 490), (600, 490), (600, 600), (0, 600)) }) # Test change items drop_frame = drop._drop_frame drop._drop_frame = None self.assertEqual(drop.get_scroll_value_percentage('any'), -1) self.assertRaises( pygame_menu.widgets.widget.dropselect. _SelectionDropNotMadeException, lambda: drop._check_drop_made()) drop._drop_frame = drop_frame drop.update_items([]) drop._make_selection_drop() self.assertEqual(drop._drop_frame.get_attribute('height'), 0) self.assertEqual(drop._drop_frame.get_attribute('width'), 0) self.assertFalse(drop.active) drop._toggle_drop() self.assertFalse(drop.active) fr = drop.get_focus_rect() r = drop.get_rect(apply_padding=False, to_real_position=True) self.assertEqual(fr.x, r.x) self.assertEqual(fr.y, r.y) self.assertEqual(fr.width + drop._selection_box_border_width, r.width) self.assertEqual(fr.height, r.height) self.assertEqual(drop.get_index(), -1) self.assertRaises(ValueError, lambda: drop.get_value()) drop._up() self.assertEqual(drop.get_index(), -1) drop._down() self.assertEqual(drop.get_index(), -1) # Check previous frame not in scrollable frames self.assertFalse(drop._drop_frame.is_scrollable) self.assertNotIn(drop_frame, menu._update_frames) # Restore previous values drop.update_items(items) self.assertEqual(drop.get_index(), -1) # Apply transforms drop.translate(1, 1) self.assertEqual(drop.get_translate(), (1, 1)) drop.translate(0, 0) self.assertRaises(WidgetTransformationNotImplemented, lambda: drop.rotate(10)) self.assertEqual(drop._angle, 0) self.assertRaises(WidgetTransformationNotImplemented, lambda: drop.resize(10, 10)) self.assertFalse(drop._scale[0]) self.assertEqual(drop._scale[1], 1) self.assertEqual(drop._scale[2], 1) self.assertRaises(WidgetTransformationNotImplemented, lambda: drop.scale(100, 100)) self.assertFalse(drop._scale[0]) self.assertEqual(drop._scale[1], 1) self.assertEqual(drop._scale[2], 1) self.assertRaises(WidgetTransformationNotImplemented, lambda: drop.flip(True, True)) self.assertFalse(drop._flip[0]) self.assertFalse(drop._flip[1]) self.assertRaises(WidgetTransformationNotImplemented, lambda: drop.set_max_width(100)) self.assertIsNone(drop._max_width[0]) self.assertRaises(WidgetTransformationNotImplemented, lambda: drop.set_max_height(100)) self.assertIsNone(drop._max_height[0]) self.assertFalse(drop.active) # Add margin vm = menu.add.vertical_margin(500) self.assertEqual(vm.get_height(), 500) # Add drop from widget manager, this has the placeholder button drop2 = menu.add.dropselect('drop2', items, dropselect_id='2', selection_infinite=True, selection_option_font_size=int( 0.75 * menu._theme.widget_font_size)) self.assertEqual(drop2._tab_size, menu._theme.widget_tab_size) for btn in drop2._option_buttons: self.assertEqual(btn._tab_size, menu._theme.widget_tab_size) self.assertEqual(drop2._drop_frame._tab_size, 4) self.assertEqual(drop2.get_id(), '2') self.assertEqual( menu.get_scrollarea().get_scroll_value_percentage( ORIENTATION_VERTICAL), 0) self.assertTrue(drop._open_bottom) self.assertFalse(drop2._open_bottom) # Move to bottom menu.get_scrollarea().scroll_to(ORIENTATION_VERTICAL, 1) menu.render() self.assertTrue(drop._open_bottom) self.assertFalse(drop2._open_bottom) menu.select_widget(drop2) drop2._toggle_drop() self.assertEqual(drop2.get_position(), ((132, 554) if PYGAME_V2 else (131, 555)) if not SYS_PLATFORM_OSX else (131, 556)) self.assertEqual( drop2._drop_frame.get_attribute('height'), (117 if PYGAME_V2 else 120) if not SYS_PLATFORM_OSX else 123) self.assertEqual( drop2._drop_frame.get_attribute('width'), (187 if PYGAME_V2 else 188) if not SYS_PLATFORM_OSX else 189) # Test infinite self.assertTrue(drop2.active) self.assertEqual(drop2.get_index(), -1) drop2._down() self.assertEqual(drop2.get_index(), 11) drop2.draw(surface) drop._index = -1 drop2._up() self.assertEqual(drop2.get_index(), 0) drop2._up() self.assertEqual(drop2.get_index(), 1) drop2._down() self.assertEqual(drop2.get_index(), 0) drop2._down() self.assertEqual(drop2.get_index(), 11) drop2._up() self.assertEqual(drop2.get_index(), 0) drop2.set_value('item6') self.assertEqual(drop2.get_index(), 7) drop2.readonly = True drop2._up() self.assertEqual(drop2.get_index(), 7) drop2._down() self.assertEqual(drop2.get_index(), 7) drop2.readonly = False menu.render() self.assertEqual( drop2.get_scroll_value_percentage(ORIENTATION_VERTICAL), (0.606 if PYGAME_V2 else 0.603) if not SYS_PLATFORM_OSX else 0.609) drop2.reset_value() self.assertTrue(drop2.active) self.assertEqual(drop2.get_index(), -1) drop2.set_scrollarea(drop2.get_scrollarea()) if PYGAME_V2: self.assertEqual( menu._draw_focus_widget(surface, drop2), { 1: ((0, 0), (600, 0), (600, 338), (0, 338)), 2: ((0, 339), (239, 339), (239, 496), (0, 496)), 3: ((447, 339), (600, 339), (600, 496), (447, 496)), 4: ((0, 497), (600, 497), (600, 600), (0, 600)) }) menu.draw(surface) self.assertIsNone(drop2.get_frame()) self.assertEqual(drop2.last_surface, menu._widgets_surface ) # Outside frame, must be the widgets surface # Add drop inside frame f = menu.add.frame_v(400, 500, max_height=200, background_color=(0, 0, 255)) f.pack(drop2) self.assertEqual(drop2.get_scrollarea(), f.get_scrollarea(inner=True)) self.assertEqual(drop2._drop_frame.get_scrollarea(), f.get_scrollarea(inner=True)) self.assertEqual(drop2.get_scrollarea().get_parent(), menu.get_scrollarea()) self.assertEqual(drop2._drop_frame.get_scrollarea().get_parent(), menu.get_scrollarea()) drop2.update_items([('optionA', 1), ('optionB', 2)]) if PYGAME_V2: self.assertEqual( drop2._get_status(), (('DropSelect-drop2', (0, 2, 3, 0, 0, 332, 49, 88, 308, 0, -242), (1, 0, 1, 1, 0, 1, 1), ('Frame', (-1, -1, -1, 116, 44, 207, 100, 204, 352, 116, -198), (0, 0, 0, 0, 0, 1, 1), (-1, -1)), ('Button-optionA', (-1, -1, -1, 116, 77, 207, 34, 204, 385, 116, -165), (1, 0, 0, 0, 0, 1, 2)), ('Button-optionB', (-1, -1, -1, 116, 110, 207, 34, 204, 418, 116, -132), (1, 0, 0, 0, 0, 1, 2))))) self.assertEqual( drop2._drop_frame.get_attribute('height'), (100 if PYGAME_V2 else 103) if not SYS_PLATFORM_OSX else 106) self.assertEqual( drop2._drop_frame.get_attribute('width'), (207 if PYGAME_V2 else 208) if not SYS_PLATFORM_OSX else 209) self.assertEqual( drop2.get_scrollarea().get_parent_scroll_value_percentage( ORIENTATION_VERTICAL), (0, 1) if not SYS_PLATFORM_OSX else (0, 0.997)) self.assertTrue(drop2._open_bottom) # Test onchange test = [-1, False] drop2.set_default_value(0) def test_change(item, v) -> None: """ Test change. """ assert item[0][1] == v test[0] = item[0][0] def test_apply(item, v) -> None: """ Test apply. """ assert item[0][1] == v test[1] = not test[1] drop2.set_onchange(test_change) drop2.set_onreturn(test_apply) drop2._toggle_drop() self.assertEqual(drop2.get_index(), -1) self.assertEqual(test[0], -1) drop2._up() self.assertEqual(test[0], 'optionA') drop2._up() self.assertEqual(test[0], 'optionB') drop2._up() self.assertEqual(test[0], 'optionA') self.assertFalse(test[1]) drop2.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) # Now it's closed self.assertTrue(test[1]) self.assertFalse(drop2.active) drop2.update(PygameEventUtils.key( ctrl.KEY_APPLY, keydown=True)) # This only opens but not apply self.assertTrue(test[1]) self.assertTrue(drop2.active) menu.draw(surface) self.assertEqual(drop2.get_frame(), f) self.assertEqual( drop2.last_surface, f.get_surface()) # Frame surface as drop is not in middle drop2.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True)) # Now applies self.assertFalse(test[1]) self.assertFalse(drop2.active) # Unpack from frame f.unpack(drop2) self.assertTrue(drop2.is_floating()) drop2.set_float(False) self.assertEqual( drop2._drop_frame.get_attribute('height'), (100 if PYGAME_V2 else 103) if not SYS_PLATFORM_OSX else 106) self.assertEqual( drop2._drop_frame.get_attribute('width'), (207 if PYGAME_V2 else 208) if not SYS_PLATFORM_OSX else 209) # Test close if mouse clicks outside menu.select_widget(drop) drop._toggle_drop() self.assertTrue(drop.active) drop.update(PygameEventUtils.mouse_click(0, 0)) self.assertFalse(drop.active) # Set drop in middle if PYGAME_V2: self.assertEqual(drop._drop_frame.get_position(), (251, 45)) self.assertEqual(drop.get_focus_rect(), pygame.Rect(121, 160, 337, 41)) drop._open_middle = True menu.render() # For this test, hide all widgets except drop # for w in menu.get_widgets(): # w.hide() # drop.show() if PYGAME_V2: self.assertEqual(drop._drop_frame.get_position(), (196, 105)) self.assertEqual(drop.get_focus_rect(), pygame.Rect(121, 160, 337, 41)) scr = drop._drop_frame.get_scrollarea() sfr = drop._drop_frame.get_frame() # Add drop to frame f.pack(drop) menu.render() self.assertEqual(drop._drop_frame.get_scrollarea(), scr) self.assertEqual(drop._drop_frame.get_frame(), sfr) if PYGAME_V2: self.assertEqual(drop._drop_frame.get_position(), (196, 453)) self.assertEqual(drop.get_focus_rect(), pygame.Rect(96, 312, 337, 41)) self.assertFalse(drop.active) drop._toggle_drop() menu.render() menu.draw(surface) self.assertEqual( drop.last_surface, menu._widgets_surface) # Menu surface as drop is in middle if PYGAME_V2: self.assertEqual( menu._draw_focus_widget(surface, drop), { 1: ((0, 0), (600, 0), (600, 259), (0, 259)), 2: ((0, 260), (195, 260), (195, 394), (0, 394)), 3: ((403, 260), (600, 260), (600, 394), (403, 394)), 4: ((0, 395), (600, 395), (600, 600), (0, 600)) }) drop._toggle_drop() drop2._open_middle = True menu.render() menu.select_widget(drop2) drop2._toggle_drop() menu.draw(surface) self.assertEqual(drop2.last_surface, menu._widgets_surface) if PYGAME_V2: self.assertEqual(drop2._drop_frame.get_position(), (196, 519)) self.assertEqual(drop2.get_focus_rect(), pygame.Rect(196, 277, 207, 99)) # Disable focus menu._mouse_motion_selection = False # As drop1 is scrollable, remove from menu, this should remove the widget too drop_frame = drop._drop_frame self.assertIn(drop_frame, menu._update_frames) menu.remove_widget(drop) self.assertNotIn(drop_frame, menu._update_frames) def draw_rect() -> None: """ Draw absolute rect on surface for testing purposes. """ # surface.fill((255, 0, 0), drop2.get_focus_rect()) # surface.fill((0, 0, 255), drop2.get_scrollarea().get_absolute_view_rect()) # surface.fill((255, 255, 0), drop2.get_scrollarea().get_absolute_view_rect().clip(drop.get_focus_rect())) return menu.get_decorator().add_callable(draw_rect, prev=False, pass_args=False) # Test active with different menu settings menu_theme = pygame_menu.themes.THEME_ORANGE.copy() menu_theme.title_fixed = False menu_theme.title_offset = (5, -2) menu_theme.widget_alignment = pygame_menu.locals.ALIGN_LEFT menu_theme.widget_font = pygame_menu.font.FONT_OPEN_SANS_LIGHT menu_theme.widget_font_size = 20 menu2 = MenuUtils.generic_menu(theme=menu_theme, width=400) menu2.add.vertical_margin(1000) drop3 = menu2.add.dropselect_multiple( title='Pick 3 colors', items=[('Black', (0, 0, 0)), ('Blue', (0, 0, 255)), ('Cyan', (0, 255, 255)), ('Fuchsia', (255, 0, 255)), ('Green', (0, 255, 0)), ('Red', (255, 0, 0)), ('White', (255, 255, 255)), ('Yellow', (255, 255, 0))], dropselect_multiple_id='pickcolors', open_middle=True, max_selected=3) rh = 28 if not SYS_PLATFORM_OSX else 29 self.assertEqual(drop3.get_focus_rect(), pygame.Rect(108, 468, 320, rh)) # Translate the menu, this should also modify focus menu2.translate(100, 50) self.assertEqual(drop3.get_focus_rect(), pygame.Rect(108 + 100, 468 + 50, 320, rh)) menu2.translate(100, 150) self.assertEqual(drop3.get_focus_rect(), pygame.Rect(108 + 100, 468 + 150, 320, rh)) menu2.translate(0, 0) self.assertEqual(drop3.get_focus_rect(), pygame.Rect(108, 468, 320, rh)) # Test update list def remove_selection_item(select: 'pygame_menu.widgets.DropSelect'): """ Update list event. """ if select.get_index() == -1: return s_val = select.get_value() _items = select.get_items() _items.pop(_items.index(s_val[0])) select.update_items(_items) print('removed {} left'.format(len(_items))) menu = MenuUtils.generic_menu() select1 = menu.add.dropselect('Subject Id', items=[('a', ), ('b', ), ('c', ), ('d', ), ('e', ), ('f', )], dropselect_id='s0') b_sel = menu.add.button('One', remove_selection_item, select1) b_sel.apply() select1.set_value(0) self.assertEqual(select1.get_value(), (('a', ), 0)) b_sel.apply() self.assertEqual(select1.get_index(), -1) self.assertEqual(select1.get_items(), [('b', ), ('c', ), ('d', ), ('e', ), ('f', )]) b_sel.apply() # Update by value select1.set_value('b') self.assertEqual(select1.get_index(), 0) select1.set_value('e') self.assertEqual(select1.get_index(), 3) self.assertRaises(ValueError, lambda: select1.set_value('unknown')) b_sel.apply() # to -1 select1.active = True select1.show() # Test configured select1.configured = False self.assertRaises(RuntimeError, lambda: select1._make_selection_drop()) select1.configured = True select1.readonly = True self.assertFalse(select1.update([])) # Test touchscreen support if not PYGAME_V2: return menu = MenuUtils.generic_menu(touchscreen=True) sel = menu.add.dropselect('Subject Id', items=[('a', ), ('b', ), ('c', ), ('d', ), ('e', ), ('f', )], dropselect_id='s0') menu.add.button('One', remove_selection_item, sel) # Select by touch touch_sel = sel.get_rect(to_real_position=True).center self.assertEqual(sel.get_index(), -1) self.assertFalse(sel.active) sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1], menu=menu)) self.assertTrue(sel.active) # Touch null option sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1] + 40, menu=menu)) self.assertTrue(sel.active) # Select option a sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1] + 80, menu=menu)) self.assertEqual(sel.get_index(), 0) self.assertFalse(sel.active) # Touch outside sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1] + 400, menu=menu)) self.assertFalse(sel.active) # Touch button menu.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1] + 40, menu=menu, evtype=FINGERDOWN)) menu.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1] + 40, menu=menu)) # Touch again outside sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1] + 400, menu=menu)) self.assertFalse(sel.active) # Select sel.select(update_menu=True) sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1], menu=menu)) self.assertTrue(sel.active) # Touch but by menu events, unselect current and force selection sel.active = False menu._widget_selected_update = False menu.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1], menu=menu)) self.assertTrue(sel.active) menu.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1], menu=menu)) self.assertFalse(sel.active) # Mouse click menu.update(PygameEventUtils.mouse_click(touch_sel[0], touch_sel[1])) self.assertTrue(sel.active) menu.update(PygameEventUtils.mouse_click(touch_sel[0], touch_sel[1])) self.assertFalse(sel.active) menu._widget_selected_update = True # Update the number of items sel.update_items([('a', ), ('b', )]) self.assertFalse(sel.active) sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1], menu=menu)) self.assertTrue(sel.active) self.assertEqual(sel.get_index(), -1) sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1] + 80, menu=menu)) self.assertEqual(sel.get_index(), 0) self.assertFalse(sel.active) sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1], menu=menu)) self.assertTrue(sel.active) sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1] + 80, menu=menu, evtype=pygame.FINGERDOWN)) sel.update( PygameEventUtils.touch_click(touch_sel[0], touch_sel[1], menu=menu)) self.assertFalse(sel.active) # Ignore buttons if not active self.assertFalse( sel.update( PygameEventUtils.key(pygame_menu.controls.KEY_MOVE_UP, keydown=True)))