Beispiel #1
0
    def test_double_discrete(self) -> None:
        """
        Test double range slider with discrete values.
        """
        menu = MenuUtils.generic_menu()
        rv = [0, 1, 2, 3, 4, 5]

        # Double slider discrete
        slider = pygame_menu.widgets.RangeSlider(
            'Range',
            range_text_value_tick_number=3,
            range_values=rv,
            default_value=(1, 4))
        menu.add.generic_widget(slider, True)
        slider.draw(surface)

        # Test set values
        slider.set_value([1, 2])
        self.assertEqual(slider.get_value(), (1, 2))

        # Test invalid values
        self.assertRaises(AssertionError, lambda: slider.set_value((1.1, 2.2)))
        self.assertRaises(AssertionError, lambda: slider.set_value((1, 1)))
        self.assertRaises(AssertionError, lambda: slider.set_value((2, 1)))
        self.assertRaises(AssertionError, lambda: slider.set_value(1))

        # Test left/right
        self.assertTrue(
            slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)))
        self.assertEqual(slider.get_value(), (0, 2))
        self.assertFalse(
            slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)))
        self.assertEqual(slider.get_value(), (0, 2))
        self.assertTrue(
            slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True)))
        self.assertEqual(slider.get_value(), (1, 2))
        self.assertFalse(
            slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True)))
        self.assertEqual(slider.get_value(), (1, 2))

        slider._update_value(0.99)
        self.assertEqual(slider.get_value(), (1, 2))

        self.assertEqual(
            slider._get_slider_inflate_rect(0, to_absolute_position=True),
            pygame.Rect(301, 209, 15, 28))
    def test_overflow_removal(self) -> None:
        """
        Test text with max width and right overflow removal.
        """
        if SYS_PLATFORM_OSX:
            return

        menu = MenuUtils.generic_menu()
        menu._copy_theme()
        menu._theme.widget_font_size = 20
        textinput = menu.add.text_input('Some long text: ',
                                        maxwidth=19,
                                        textinput_id='long_text',
                                        input_underline='_')
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: textinput.resize())
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: textinput.set_max_width())
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: textinput.set_max_height())
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: textinput.scale())
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: textinput.rotate())
        textinput.flip(True, True)
        self.assertEqual(textinput._flip, (False, True))
        # noinspection SpellCheckingInspection
        textinput.set_value('aaaaaaaaaaaaaaaaaaaaaaaaaa')
        self.assertEqual(textinput._cursor_position, 26)
        self.assertEqual(textinput._renderbox, [1, 26, 25])
        textinput.update(PygameEventUtils.key(pygame.K_BACKSPACE,
                                              keydown=True))
        self.assertEqual(textinput._cursor_position, 25)
        self.assertEqual(textinput._renderbox, [0, 25, 25])
        textinput.update(
            PygameEventUtils.key(pygame.K_a, keydown=True, char='a'))
        self.assertEqual(textinput._cursor_position, 26)
        self.assertEqual(textinput._renderbox, [1, 26, 25])
        textinput.update(PygameEventUtils.key(pygame.K_BACKSPACE,
                                              keydown=True))
        self.assertEqual(textinput._cursor_position, 25)
        self.assertEqual(textinput._renderbox, [0, 25, 25])
Beispiel #3
0
    def test_config(self) -> None:
        """
        Configure controls.
        """
        self.assertEqual(ctrl.KEY_APPLY, K_RETURN)

        # Change apply to new key
        ctrl.KEY_APPLY = K_END
        self.assertEqual(ctrl.KEY_APPLY, K_END)

        # Create new button
        menu = MenuUtils.generic_menu()
        test = [False]

        def click_button() -> None:
            """
            Button apply handler.
            """
            test[0] = not test[0]
            print('new test value', test)

        button = menu.add.button('button', click_button)
        self.assertFalse(test[0])
        button.apply()
        self.assertTrue(test[0])
        button.apply()
        self.assertFalse(test[0])

        # Now test new apply button
        button.update(PygameEventUtils.key(K_END, keydown=True))
        self.assertTrue(test[0])

        # Rollback change
        ctrl.KEY_APPLY = K_RETURN

        button.update(PygameEventUtils.key(K_END, keydown=True))
        self.assertTrue(test[0])
        button.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        self.assertFalse(test[0])
Beispiel #4
0
 def test_invalid_range(self) -> None:
     """
     Test invalid ranges. #356
     """
     menu = MenuUtils.generic_menu()
     r = menu.add.range_slider('Infection Rate',
                               default=2,
                               increment=0.5,
                               range_values=(2, 10))
     self.assertEqual(r.get_value(), 2)
     self.assertTrue(
         r.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True)))
     self.assertEqual(r.get_value(), 2.5)
     self.assertTrue(
         r.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)))
     self.assertEqual(r.get_value(), 2)
     self.assertFalse(
         r.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True)))
     self.assertEqual(r.get_value(), 2)
     for _ in range(20):
         r.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True))
     self.assertEqual(r.get_value(), 10)
Beispiel #5
0
    def test_non_ascii(self) -> None:
        """
        Test non-ascii.
        """
        menu = MenuUtils.generic_menu()
        m = MenuUtils.generic_menu(title=u'Ménu')
        m.clear()
        menu.add.button('0', pygame_menu.events.NONE)
        menu.add.button('Test', pygame_menu.events.NONE)
        menu.add.button(u'Menú', pygame_menu.events.NONE)
        menu.add.color_input(u'Cólor', 'rgb')
        text = menu.add.text_input(u'Téxt')
        menu.add.label(u'Téxt')
        menu.add.selector(u'Sélect'.encode('latin1'), [('a', 'a')])
        menu.enable()
        menu.draw(surface)

        # Text text input
        text.set_value('ą, ę, ś, ć, ż, ź, ó, ł, ń')
        self.assertEqual(text.get_value(), 'ą, ę, ś, ć, ż, ź, ó, ł, ń')
        text.set_value('')
        text.update(PygameEventUtils.key(pygame.K_l, char='ł', keydown=True))
        self.assertEqual(text.get_value(), 'ł')
    def test_textinput(self) -> None:
        """
        Test TextInput widget.
        """
        menu = MenuUtils.generic_menu()

        # Assert bad settings
        self.assertRaises(
            ValueError, lambda: menu.add.text_input('title',
                                                    input_type=pygame_menu.
                                                    locals.INPUT_FLOAT,
                                                    default='bad'))
        self.assertRaises(
            ValueError,  # Default and password cannot coexist
            lambda: menu.add.text_input('title', password=True, default='bad'))

        # Create text input widget
        textinput = menu.add.text_input('title', input_underline='_')
        textinput.set_value('new_value')  # No error
        textinput._selected = False
        textinput.draw(surface)
        textinput.select(update_menu=True)
        textinput.draw(surface)
        self.assertEqual(textinput.get_value(), 'new_value')
        textinput.clear()
        self.assertEqual(textinput.get_value(), '')

        # Create selection box
        string = 'the text'
        textinput._cursor_render = True
        textinput.set_value(string)
        textinput._select_all()
        self.assertEqual(textinput._get_selected_text(), 'the text')
        textinput.draw(surface)
        textinput._unselect_text()
        textinput.draw(surface)

        # Assert events
        textinput.update(PygameEventUtils.key(0, keydown=True, testmode=False))
        PygameEventUtils.test_widget_key_press(textinput)
        textinput.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        textinput.update(PygameEventUtils.key(pygame.K_LSHIFT, keydown=True))
        textinput.clear()

        # Type
        textinput.update(
            PygameEventUtils.key(pygame.K_t, keydown=True, char='t'))
        textinput.update(
            PygameEventUtils.key(pygame.K_e, keydown=True, char='e'))
        textinput.update(
            PygameEventUtils.key(pygame.K_s, keydown=True, char='s'))
        textinput.update(
            PygameEventUtils.key(pygame.K_t, keydown=True, char='t'))

        # Keyup
        textinput.update(PygameEventUtils.key(pygame.K_a, keyup=True,
                                              char='a'))
        self.assertEqual(textinput.get_value(), 'test')  # The text we typed

        # Ctrl events
        textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_c))  # copy
        textinput.update(PygameEventUtils.keydown_mod_ctrl(
            pygame.K_v))  # paste
        textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_z))  # undo
        self.assertEqual(textinput.get_value(), 'tes')
        textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_y))  # redo
        self.assertEqual(textinput.get_value(), 'test')
        textinput._select_all()
        textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_x))  # cut
        self.assertEqual(textinput.get_value(), '')
        textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_z))  # undo
        self.assertEqual(textinput.get_value(), 'test')
        textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_y))  # redo
        self.assertEqual(textinput.get_value(), '')
        textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_z))  # undo
        self.assertEqual(textinput.get_value(), 'test')

        # Test ignore ctrl events
        textinput._copy_paste_enabled = False
        self.assertFalse(
            textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_c)))
        self.assertFalse(
            textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_v)))
        max_history = textinput._max_history
        textinput._max_history = 0
        self.assertFalse(
            textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_z)))
        self.assertFalse(
            textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_y)))
        self.assertFalse(
            textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_x)))
        textinput._selection_enabled = False
        self.assertFalse(
            textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_a)))
        self.assertFalse(
            textinput.update(PygameEventUtils.keydown_mod_ctrl(
                pygame.K_r)))  # invalid

        # Reset
        textinput._copy_paste_enabled = True
        textinput._max_history = max_history
        textinput._selection_enabled = True

        # Test selection, if user selects all and types anything the selected
        # text must be destroyed
        textinput.update(PygameEventUtils.keydown_mod_ctrl(
            pygame.K_a))  # select all
        textinput._unselect_text()
        self.assertEqual(textinput._get_selected_text(), '')
        textinput._select_all()
        self.assertEqual(textinput._get_selected_text(), 'test')
        textinput._unselect_text()
        self.assertEqual(textinput._get_selected_text(), '')
        textinput.update(PygameEventUtils.keydown_mod_ctrl(pygame.K_a))
        self.assertEqual(textinput._get_selected_text(), 'test')
        textinput.update(
            PygameEventUtils.key(pygame.K_t, keydown=True, char='t'))
        textinput._select_all()
        self.assertTrue(
            textinput.update(
                PygameEventUtils.key(pygame.K_ESCAPE, keydown=True)))
        textinput._select_all()
        self.assertTrue(
            textinput.update(
                PygameEventUtils.key(pygame.K_BACKSPACE, keydown=True)))
        self.assertEqual(textinput.get_value(), '')
        textinput.set_value('t')

        # Releasing shift disable selection
        textinput._selection_active = True
        textinput.update(PygameEventUtils.key(pygame.K_LSHIFT, keyup=True))
        self.assertFalse(textinput._selection_active)

        # Arrows while selection
        textinput._select_all()
        self.assertIsNotNone(textinput._selection_surface)
        textinput.update(PygameEventUtils.key(pygame.K_LEFT, keydown=True))
        self.assertIsNone(textinput._selection_surface)
        textinput._select_all()
        self.assertIsNotNone(textinput._selection_surface)
        textinput.update(PygameEventUtils.key(pygame.K_RIGHT, keydown=True))
        self.assertIsNone(textinput._selection_surface)

        textinput._select_all()
        textinput._selection_active = True
        self.assertEqual(textinput._selection_box, [0, 1])
        textinput.update(PygameEventUtils.key(pygame.K_LEFT, keydown=True))
        self.assertEqual(textinput._selection_box, [0, 0])
        textinput._select_all()
        textinput._selection_active = True
        textinput.update(PygameEventUtils.key(pygame.K_RIGHT, keydown=True))
        self.assertEqual(textinput._selection_box, [0, 1])

        # Remove while selection
        textinput._select_all()
        textinput.update(PygameEventUtils.key(pygame.K_DELETE, keydown=True))
        self.assertEqual(textinput.get_value(), '')
        textinput.set_value('t')

        # Now the value must be t
        self.assertEqual(textinput._get_selected_text(), '')
        self.assertEqual(textinput.get_value(), 't')

        # Test readonly
        textinput.update(
            PygameEventUtils.key(pygame.K_t, keydown=True, char='k'))
        self.assertEqual(textinput.get_value(), 'tk')
        textinput.readonly = True
        textinput.update(
            PygameEventUtils.key(pygame.K_t, keydown=True, char='k'))
        self.assertEqual(textinput.get_value(), 'tk')
        textinput.readonly = False

        # Test keyup
        self.assertIn(pygame.K_t, textinput._keyrepeat_counters.keys())
        self.assertFalse(
            textinput.update(
                PygameEventUtils.key(pygame.K_t, keyup=True, char='1')))
        self.assertNotIn(pygame.K_t, textinput._keyrepeat_counters.keys())

        # Test tab
        self.assertEqual(textinput._tab_size, 4)
        textinput.update(PygameEventUtils.key(pygame.K_TAB, keydown=True))
        self.assertEqual(textinput.get_value(), 'tk    ')

        # Test invalid unicode
        self.assertFalse(
            textinput.update(PygameEventUtils.key(pygame.K_1, keydown=True)))

        # Up/Down disable active status
        textinput.active = True
        textinput.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True))
        self.assertFalse(textinput.active)
        textinput.active = True
        textinput.update(PygameEventUtils.key(ctrl.KEY_MOVE_DOWN,
                                              keydown=True))
        self.assertFalse(textinput.active)
        textinput.active = True
        self.assertTrue(
            textinput.update(
                PygameEventUtils.key(pygame.K_ESCAPE, keydown=True)))
        self.assertFalse(textinput.active)

        # Test mouse
        textinput._selected = True
        textinput._selection_time = 0
        textinput.update(PygameEventUtils.middle_rect_click(textinput))
        self.assertTrue(textinput._cursor_visible)
        textinput._select_all()
        textinput._selection_active = True
        self.assertEqual(textinput._cursor_position, 6)
        self.assertEqual(textinput._selection_box, [0, 6])
        textinput.update(
            PygameEventUtils.middle_rect_click(textinput,
                                               evtype=pygame.MOUSEBUTTONDOWN))
        self.assertEqual(textinput._selection_box, [0, 0])

        # Check click pos
        textinput._check_mouse_collide_input(
            PygameEventUtils.middle_rect_click(textinput)[0].pos)
        self.assertEqual(textinput._cursor_position, 6)

        # Test touch
        textinput._cursor_position = 0
        textinput._check_touch_collide_input(
            PygameEventUtils.middle_rect_click(textinput)[0].pos)
        self.assertEqual(textinput._cursor_position, 6)

        # Update mouse
        for i in range(50):
            textinput.update(
                PygameEventUtils.key(pygame.K_t, keydown=True, char='t'))
        textinput._update_cursor_mouse(50)
        textinput._cursor_render = True
        textinput._render_cursor()

        # Test multiple are selected
        menu.add.text_input('title', password=True,
                            input_underline='_').select()
        self.assertRaises(
            pygame_menu.menu._MenuMultipleSelectedWidgetsException,
            lambda: menu.draw(surface))
        textinput.clear()
        textinput.select(update_menu=True)
        menu.draw(surface)

        # Clear the menu
        self.assertEqual(menu._stats.removed_widgets, 0)
        self.assertEqual(textinput.get_menu(), menu)
        menu.clear()
        self.assertIsNone(textinput.get_menu())
        self.assertEqual(menu._stats.removed_widgets, 3)
        menu.add.generic_widget(textinput)
        self.assertEqual(textinput.get_menu(), menu)
        menu.clear()
        self.assertEqual(menu._stats.removed_widgets, 4)
Beispiel #7
0
    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_scrollbar(self) -> None:
        """
        Test ScrollBar widget.
        """
        screen_size = surface.get_size()
        world = pygame.Surface((WINDOW_SIZE[0] * 2, WINDOW_SIZE[1] * 3))
        world.fill((200, 200, 200))
        for x in range(100, world.get_width(), 200):
            for y in range(100, world.get_height(), 200):
                pygame.draw.circle(world, (225, 34, 43), (x, y), 100, 10)

        # Vertical right scrollbar
        thick = 80
        length = screen_size[1]
        world_range = (50, world.get_height())
        x, y = screen_size[0] - thick, 0

        sb = ScrollBar(
            length, world_range, 'sb2', ORIENTATION_VERTICAL,
            slider_pad=2,
            slider_color=(210, 120, 200),
            page_ctrl_thick=thick,
            page_ctrl_color=(235, 235, 230)
        )
        self.assertEqual(sb.get_thickness(), 80)
        self.assertIsNone(sb.get_scrollarea())

        sb.set_shadow(color=(245, 245, 245), position=POSITION_SOUTHEAST)
        self.assertFalse(sb._font_shadow)

        sb.set_position(x, y)

        self.assertEqual(sb._orientation, 1)
        self.assertEqual(sb.get_orientation(), ORIENTATION_VERTICAL)
        self.assertEqual(sb.get_minimum(), world_range[0])
        self.assertEqual(sb.get_maximum(), world_range[1])

        sb.set_value(80)
        self.assertAlmostEqual(sb.get_value(), 80, delta=2)  # Scaling delta

        sb.update(PygameEventUtils.mouse_click(x + thick / 2, y + 2, evtype=pygame.MOUSEBUTTONDOWN))
        self.assertEqual(sb.get_value(), 50)
        self.assertEqual(sb.get_value_percentage(), 0)

        sb.set_page_step(length)
        self.assertAlmostEqual(sb.get_page_step(), length, delta=2)  # Scaling delta

        sb.draw(surface)

        # Test events
        sb.update(PygameEventUtils.key(pygame.K_PAGEDOWN, keydown=True))
        self.assertEqual(sb.get_value(), 964)
        sb.update(PygameEventUtils.key(pygame.K_PAGEUP, keydown=True))
        self.assertEqual(sb.get_value(), 50)
        self.assertEqual(sb._last_mouse_pos, (-1, -1))
        sb.update(PygameEventUtils.enter_window())
        self.assertEqual(sb._last_mouse_pos, (-1, -1))
        sb.update(PygameEventUtils.leave_window())
        self.assertEqual(sb._last_mouse_pos, pygame.mouse.get_pos())
        self.assertFalse(sb.scrolling)
        sb.update(PygameEventUtils.middle_rect_click(sb.get_slider_rect(), evtype=pygame.MOUSEBUTTONDOWN))
        self.assertTrue(sb.scrolling)
        sb.update(PygameEventUtils.mouse_click(1, 1))
        self.assertFalse(sb.scrolling)
        self.assertEqual(sb.get_value(), 50)
        sb.update(PygameEventUtils.middle_rect_click(sb.get_rect(to_absolute_position=True),
                                                     evtype=pygame.MOUSEBUTTONDOWN))
        self.assertEqual(sb.get_value(), 964)
        sb.update(PygameEventUtils.middle_rect_click(sb.get_slider_rect(), evtype=pygame.MOUSEBUTTONDOWN))
        self.assertTrue(sb.scrolling)
        sb.update(PygameEventUtils.middle_rect_click(sb.get_slider_rect(), button=4,
                                                     evtype=pygame.MOUSEBUTTONDOWN))
        self.assertEqual(sb.get_value(), 875)
        sb.update(PygameEventUtils.middle_rect_click(sb.get_slider_rect(), button=5,
                                                     evtype=pygame.MOUSEBUTTONDOWN))
        self.assertEqual(sb.get_value(), 964)
        self.assertEqual(sb.get_value_percentage(), 0.522)

        # Test mouse motion while scrolling
        sb.update(PygameEventUtils.middle_rect_click(sb.get_slider_rect(), button=5, delta=(0, 50), rel=(0, 10),
                                                     evtype=pygame.MOUSEMOTION))
        self.assertEqual(sb.get_value_percentage(), 0.547)
        sb.update(PygameEventUtils.middle_rect_click(sb.get_slider_rect(), button=5, delta=(0, 50), rel=(0, -10),
                                                     evtype=pygame.MOUSEMOTION))
        self.assertEqual(sb.get_value_percentage(), 0.522)
        sb.update(PygameEventUtils.middle_rect_click(sb.get_slider_rect(), button=5, delta=(0, 50), rel=(0, 999),
                                                     evtype=pygame.MOUSEMOTION))
        self.assertEqual(sb.get_value_percentage(), 1)
        sb.readonly = True
        self.assertFalse(sb.update([]))

        # Ignore events if mouse outside the region
        sb.update(PygameEventUtils.middle_rect_click(sb.get_slider_rect(), button=5, delta=(0, 999), rel=(0, -10),
                                                     evtype=pygame.MOUSEMOTION))
        self.assertIn(sb.get_value_percentage(), (0.976, 1))

        # Test remove onreturn
        sb = ScrollBar(length, world_range, 'sb', ORIENTATION_VERTICAL, onreturn=-1)
        self.assertIsNone(sb._onreturn)
        self.assertTrue(sb._kwargs.get('onreturn', 0))

        # Scrollbar ignores scaling
        self.assertRaises(WidgetTransformationNotImplemented, lambda: sb.scale(2, 2))
        self.assertFalse(sb._scale[0])
        self.assertRaises(WidgetTransformationNotImplemented, lambda: sb.resize(2, 2))
        self.assertFalse(sb._scale[0])
        self.assertRaises(WidgetTransformationNotImplemented, lambda: sb.set_max_width(10))
        self.assertIsNone(sb._max_width[0])
        self.assertRaises(WidgetTransformationNotImplemented, lambda: sb.set_max_height(10))
        self.assertIsNone(sb._max_height[0])
        sb._apply_font()
        sb.set_padding(10)
        self.assertEqual(sb._padding[0], 0)
        self.assertRaises(WidgetTransformationNotImplemented, lambda: sb.rotate(10))
        self.assertEqual(sb._angle, 0)
        self.assertRaises(WidgetTransformationNotImplemented, lambda: sb.flip(True, True))
        self.assertFalse(sb._flip[0])
        self.assertFalse(sb._flip[1])

        # Set minimum
        sb.set_minimum(0.5 * sb._values_range[1])

        # Test hide
        sb._mouseover = True
        sb.hide()
Beispiel #9
0
    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))
Beispiel #10
0
    def test_dropselect_multiple(self) -> None:
        """
        Test dropselect multiple widget.
        """
        theme = pygame_menu.themes.THEME_DEFAULT.copy()
        theme.widget_font_size = 25
        menu = MenuUtils.generic_menu(mouse_motion_selection=True, theme=theme)
        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.DropSelectMultiple('dropsel',
                                                      items,
                                                      open_middle=True,
                                                      selection_box_height=5)
        self.assertNotEqual(id(items), id(drop._items))
        menu.add.generic_widget(drop, configure_defaults=True)
        self.assertEqual(drop._selection_box_width,
                         225 if not SYS_PLATFORM_OSX else 226)

        # Check drop is empty
        self.assertEqual(drop.get_value(), ([], []))
        self.assertEqual(drop.get_index(), [])
        self.assertEqual(drop._get_current_selected_text(), 'Select an option')

        # Check events
        self.assertFalse(drop.active)
        drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        self.assertTrue(drop.active)
        self.assertEqual(drop._index, -1)
        drop.update(PygameEventUtils.key(ctrl.KEY_APPLY,
                                         keydown=True))  # Index is -1
        self.assertFalse(drop.active)
        drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        self.assertTrue(drop.active)
        drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True))
        self.assertEqual(drop._index, 0)
        drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True))
        self.assertEqual(drop._index, 1)

        # Apply on current
        drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        self.assertEqual(drop.get_value(), ([('epic', 2)], [1]))
        self.assertEqual(drop.get_index(), [1])
        self.assertEqual(drop._get_current_selected_text(), '1 selected')
        drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True))
        drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True))
        drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        self.assertEqual(drop.get_value(), ([('epic', 2),
                                             ('item2', 2)], [1, 3]))
        self.assertEqual(drop._get_current_selected_text(), '2 selected')

        # Change selection type
        drop._selection_placeholder_format = DROPSELECT_MULTIPLE_SFORMAT_LIST_COMMA
        self.assertEqual(drop._get_current_selected_text(),
                         'epic,item2 selected')
        drop._selection_placeholder_format = DROPSELECT_MULTIPLE_SFORMAT_LIST_HYPHEN
        self.assertEqual(drop._get_current_selected_text(),
                         'epic-item2 selected')
        drop._selection_placeholder_format = '+'
        self.assertEqual(drop._get_current_selected_text(),
                         'epic+item2 selected')

        def format_string_list(items_list) -> str:
            """
            Receives the items list string and returns a function.

            :param items_list: Items list
            :return: Join string
            """
            if len(items_list) == 1:
                return items_list[0]
            elif len(items_list) == 2:
                return items_list[0] + ' and ' + items_list[1]
            return 'overflow'

        drop._selection_placeholder_format = format_string_list
        self.assertEqual(drop._get_current_selected_text(),
                         'epic and item2 selected')

        # Invalid format
        drop._selection_placeholder_format = 1
        self.assertRaises(ValueError,
                          lambda: drop._get_current_selected_text())
        drop._selection_placeholder_format = lambda: print('nice')
        self.assertRaises(ValueError,
                          lambda: drop._get_current_selected_text())
        drop._selection_placeholder_format = lambda x: 1
        self.assertRaises(AssertionError,
                          lambda: drop._get_current_selected_text())

        # Back to default
        drop._selection_placeholder_format = DROPSELECT_MULTIPLE_SFORMAT_TOTAL

        # Click item 2, this should unselect
        self.assertTrue(drop.active)
        drop.update(PygameEventUtils.middle_rect_click(
            drop._option_buttons[3]))
        self.assertEqual(drop.get_value(), ([('epic', 2)], [1]))
        self.assertEqual(drop._get_current_selected_text(), '1 selected')
        drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True))
        self.assertEqual(drop._index, 4)
        drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        self.assertEqual(drop.get_value(), ([('epic', 2),
                                             ('item3', 3)], [1, 4]))
        self.assertEqual(drop._get_current_selected_text(), '2 selected')

        # Close
        drop.update(PygameEventUtils.key(pygame.K_ESCAPE, keydown=True))
        self.assertFalse(drop.active)
        self.assertEqual(drop.get_value(), ([('epic', 2),
                                             ('item3', 3)], [1, 4]))
        self.assertEqual(drop._get_current_selected_text(), '2 selected')

        # Change drop selected text method

        # Set max limit
        drop._max_selected = 3
        self.assertEqual(drop.get_total_selected(), 2)
        drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True))
        drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        self.assertEqual(drop.get_total_selected(), 3)
        self.assertTrue(drop.active)
        drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_UP, keydown=True))
        drop.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        self.assertEqual(drop.get_total_selected(), 3)  # Limit reached
        self.assertEqual(drop.get_value(), ([('epic', 2), ('item3', 3),
                                             ('item4', 4)], [1, 4, 5]))
        drop.update(PygameEventUtils.key(ctrl.KEY_MOVE_DOWN, keydown=True))
        drop.update(PygameEventUtils.key(ctrl.KEY_APPLY,
                                         keydown=True))  # Unselect previous
        self.assertEqual(drop.get_total_selected(), 2)  # Limit reached
        self.assertEqual(drop.get_value(), ([('epic', 2),
                                             ('item3', 3)], [1, 4]))

        # Update elements
        drop.update_items([('This is a really long selection item', 1),
                           ('epic', 2)])
        self.assertEqual(drop.get_value(), ([], []))
        self.assertEqual(drop._get_current_selected_text(), 'Select an option')
        drop.set_value(1, process_index=True)
        self.assertEqual(drop.get_value(), ([('epic', 2)], [1]))
        drop.set_value('This is a really long selection item',
                       process_index=True)
        self.assertEqual(drop.get_value(),
                         ([('This is a really long selection item', 1),
                           ('epic', 2)], [0, 1]))
        self.assertEqual(drop._get_current_selected_text(), '2 selected')
        drop.set_default_value(1)
        self.assertEqual(drop.get_value(), ([('epic', 2)], [1]))
        self.assertEqual(drop._get_current_selected_text(), '1 selected')

        # Use manager
        drop2 = menu.add.dropselect_multiple(
            'nice', [('This is a really long selection item', 1), ('epic', 2)],
            placeholder_selected='nice {0}',
            placeholder='epic',
            max_selected=1)
        self.assertEqual(drop2._selection_box_width,
                         134 if not SYS_PLATFORM_OSX else 135)
        self.assertEqual(drop2._get_current_selected_text(), 'epic')
        drop2.set_value('epic', process_index=True)
        self.assertEqual(drop2.get_index(), [1])
        self.assertEqual(drop2._get_current_selected_text(), 'nice 1')
        drop2.set_value(0, process_index=True)
        self.assertEqual(drop2.get_index(), [1])
        self.assertEqual(drop2._get_current_selected_text(), 'nice 1')
        self.assertEqual(drop2._default_value, [])
        self.assertEqual(drop2._index, 0)
        self.assertRaises(ValueError, lambda: drop2.set_value('not epic'))

        # Reset
        drop2.reset_value()
        self.assertEqual(drop2._get_current_selected_text(), 'epic')
        self.assertEqual(drop2._default_value, [])
        self.assertEqual(drop2._index, -1)
        self.assertEqual(drop2.get_index(), [])
        self.assertNotEqual(id(drop2._default_value),
                            id(drop2._selected_indices))

        menu.select_widget(drop2)
        self.assertTrue(
            drop2.update(PygameEventUtils.key(pygame.K_TAB, keydown=True)))

        # Test hide
        self.assertTrue(drop2._drop_frame.is_visible())
        self.assertTrue(drop2.active)
        drop2.hide()  # Hiding selects the other widget
        self.assertEqual(menu.get_selected_widget(), drop)
        self.assertFalse(drop2._drop_frame.is_visible())
        self.assertFalse(drop2.active)
        drop2.show()
        self.assertFalse(drop2._drop_frame.is_visible())
        self.assertFalse(drop2.active)
        self.assertEqual(menu.get_selected_widget(), drop)
        menu.select_widget(drop2)
        drop2._toggle_drop()
        self.assertTrue(drop2.active)
        self.assertTrue(drop2._drop_frame.is_visible())

        # Test change
        test = [-1]

        def onchange(value) -> None:
            """
            Test onchange.
            """
            test[0] = value[1]

        drop2.set_onchange(onchange)

        # Pick any option
        menu.render()
        self.assertEqual(test, [-1])
        drop2._option_buttons[0].apply()
        self.assertEqual(test[0], [0])
        drop2._option_buttons[0].apply()
        self.assertEqual(test[0], [])
        drop2._option_buttons[0].apply()
        drop2._option_buttons[1].apply()
        self.assertEqual(test[0], [0])  # As max selected is only 1
        drop2._max_selected = 2
        drop2._option_buttons[1].apply()
        self.assertEqual(test[0], [0, 1])

        # Test none drop frame
        drop2._drop_frame = None
        self.assertEqual(drop2.get_scroll_value_percentage('any'), -1)

        # Test format option from manager
        menu._theme.widget_background_inflate_to_selection = True
        menu._theme.widget_background_inflate = 0
        # menu._theme.widget_border_inflate = 0
        menu._theme.widget_margin = 0
        drop2 = menu.add.dropselect_multiple(
            'nice', [('This is a really long selection item', 1), ('epic', 2)],
            placeholder_selected='nice {0}',
            placeholder='epic',
            max_selected=1,
            selection_placeholder_format=lambda x: 'not EPIC')
        self.assertEqual(drop2._get_current_selected_text(), 'epic')
        drop2.set_value('epic', process_index=True)
        self.assertEqual(drop2._get_current_selected_text(), 'nice not EPIC')
        self.assertEqual(drop2.get_margin(), (0, 0))
        self.assertEqual(drop2._background_inflate, (0, 0))
        self.assertEqual(drop2._border_inflate, (0, 0))
        menu._theme.widget_background_inflate_to_selection = False

        # Process index
        drop2._index = -1
        drop2._process_index()
Beispiel #11
0
    def test_double(self) -> None:
        """
        Test double range slider.
        """
        menu = MenuUtils.generic_menu()

        # Double slider
        slider = pygame_menu.widgets.RangeSlider(
            'Range',
            range_text_value_tick_number=3,
            default_value=(0.2, 1.0),
            slider_text_value_font=pygame_menu.font.FONT_BEBAS,
            range_text_value_font=pygame_menu.font.FONT_8BIT,
            slider_text_value_triangle=False)
        slider._slider_text_value_vmargin = -2
        menu.add.generic_widget(slider, True)
        slider.draw(surface)
        slider.draw_after_if_selected(surface)

        self.assertEqual(slider.get_value(), (0.2, 1.0))
        self.assertRaises(AssertionError, lambda: slider.set_value(0.2))
        self.assertRaises(AssertionError, lambda: slider.set_value((0.2, 0.2)))
        self.assertRaises(AssertionError, lambda: slider.set_value((1.0, 0.2)))
        self.assertRaises(AssertionError, lambda: slider.set_value(
            (0.2, 0.5, 1.0)))

        # Test slider selection
        self.assertTrue(slider._slider_selected[0])
        self.assertTrue(
            slider.update(PygameEventUtils.key(ctrl.KEY_TAB, keydown=True)))
        self.assertFalse(slider._slider_selected[0])
        slider.draw(surface)
        slider.draw_after_if_selected(surface)

        # Test click sliders
        slider_rect = slider._get_slider_inflate_rect(0, to_real_position=True)
        self.assertTrue(
            slider.update(
                PygameEventUtils.middle_rect_click(
                    slider_rect, evtype=pygame.MOUSEBUTTONDOWN)))
        self.assertTrue(slider._slider_selected[0])
        self.assertFalse(
            slider.update(  # Slider already selected
                PygameEventUtils.middle_rect_click(
                    slider_rect, evtype=pygame.MOUSEBUTTONDOWN)))

        # Click if sliders are colliding
        slider.set_value((0.5, 0.50000001))
        slider_rect = slider._get_slider_inflate_rect(1, to_real_position=True)
        self.assertFalse(
            slider.update(
                PygameEventUtils.middle_rect_click(
                    slider_rect, evtype=pygame.MOUSEBUTTONDOWN)))
        self.assertTrue(slider._slider_selected[0])
        slider.set_value((0.5, 0.7))
        slider_rect = slider._get_slider_inflate_rect(1, to_real_position=True)
        self.assertTrue(
            slider.update(
                PygameEventUtils.middle_rect_click(
                    slider_rect, evtype=pygame.MOUSEBUTTONDOWN)))
        self.assertTrue(slider._slider_selected[1])

        # Test left slider
        pos = slider._test_get_pos_value(0.5)
        pos2 = slider._test_get_pos_value(0.6)
        slider_rect = slider._get_slider_inflate_rect(0, to_real_position=True)
        self.assertEqual(slider_rect, pygame.Rect(344, 311, 15, 28))
        slider.update(
            PygameEventUtils.middle_rect_click(slider_rect,
                                               evtype=pygame.MOUSEBUTTONDOWN))
        self.assertTrue(slider._slider_selected[0])
        self.assertTrue(slider._scrolling)
        self.assertTrue(slider._selected_mouse)
        dx = pos[0] - pos2[0]
        slider.update(
            PygameEventUtils.mouse_motion(slider_rect,
                                          rel=(-dx, pos[1]),
                                          update_mouse=True))
        self.assertEqual(slider.get_value(), (0.6, 0.7))

        # As slider moved, ignore this
        slider.update(
            PygameEventUtils.mouse_motion(slider_rect,
                                          rel=(-dx, pos[1]),
                                          update_mouse=True))
        self.assertEqual(slider.get_value(), (0.6, 0.7))
        self.assertTrue(slider._scrolling)
        self.assertTrue(slider._slider_selected[0])

        # Move to 0
        self.assertTrue(slider._selected_mouse)
        pos = slider._test_get_pos_value(0)
        pos2 = slider._test_get_pos_value(0.6)
        dx = pos[0] - pos2[0]
        slider.update(
            PygameEventUtils.mouse_motion(slider_rect,
                                          rel=(dx, pos[1]),
                                          update_mouse=True))
        self.assertEqual(slider.get_value(), (0, 0.7))

        # Move more than 0.7
        pos = slider._test_get_pos_value(0)
        pos2 = slider._test_get_pos_value(0.75)
        slider_rect = slider._get_slider_inflate_rect(0, to_real_position=True)
        dx = pos[0] - pos2[0]
        slider.update(
            PygameEventUtils.mouse_motion(slider_rect,
                                          rel=(-dx, pos[1]),
                                          update_mouse=True))
        self.assertEqual(slider.get_value(), (0, 0.7))

        # Move to 0.7 - eps
        pos = slider._test_get_pos_value(0)
        pos2 = slider._test_get_pos_value(0.7 - 1e-6)
        slider_rect = slider._get_slider_inflate_rect(0, to_real_position=True)
        dx = pos[0] - pos2[0]
        slider.update(
            PygameEventUtils.mouse_motion(slider_rect,
                                          rel=(-dx, pos[1]),
                                          update_mouse=True))
        self.assertAlmostEqual(slider.get_value()[0], 0.7 - 1e-7, places=1)

        # Ignore if move 0.7 + eps
        self.assertFalse(
            slider.update(
                PygameEventUtils.mouse_motion(slider_rect,
                                              rel=(1, pos[1]),
                                              update_mouse=True)))

        # Change to right
        slider_rect = slider._get_slider_inflate_rect(1, to_real_position=True)
        self.assertTrue(
            slider.update(PygameEventUtils.key(ctrl.KEY_TAB, keydown=True)))
        pos = slider._test_get_pos_value(0.7)
        pos2 = slider._test_get_pos_value(0.8)
        dx = pos[0] - pos2[0]
        self.assertFalse(
            slider.update(
                PygameEventUtils.mouse_motion(slider_rect,
                                              rel=(-1, pos[1]),
                                              update_mouse=True)))
        self.assertTrue(
            slider.update(
                PygameEventUtils.mouse_motion(slider_rect,
                                              rel=(-dx, pos[1]),
                                              update_mouse=True)))
        self.assertAlmostEqual(slider.get_value()[1], 0.8)

        # Test left/right
        slider.set_value((0.7, 0.8))
        slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True))
        slider.set_value((0.7, 0.8))  # Ignored
        slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True))
        slider.set_value((0.7, 0.9))
        slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True))
        slider.set_value((0.7, 1.0))
        slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True))
        slider.set_value((0.7, 1.0))
        slider.set_value((0.7, 0.8))
        slider.update(PygameEventUtils.key(ctrl.KEY_TAB, keydown=True))
        slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True))
        slider.set_value((0.7, 0.8))
        slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True))
        slider.set_value((0.6, 0.8))

        # Reset value
        slider.reset_value()
        self.assertEqual(slider.get_value(), (0.2, 1.0))
Beispiel #12
0
    def test_single_rangeslider(self) -> None:
        """
        Test single range slider.
        """
        menu = MenuUtils.generic_menu()

        # Single slider
        slider = pygame_menu.widgets.RangeSlider('Range S')

        test = [0, 0]

        def onchange(x: float) -> None:
            """
            Change slider.
            """
            # noinspection PyTypeChecker
            test[0] = x

        def onreturn(x: float) -> None:
            """
            Return slider.
            """
            # noinspection PyTypeChecker
            test[1] = x

        slider.set_onchange(onchange)
        slider.set_onreturn(onreturn)

        menu.add.generic_widget(slider, True)
        self.assertEqual(slider.get_value(), 0)
        slider.set_value(0.5)
        self.assertEqual(slider.get_value(), 0.5)
        self.assertEqual(slider._value, [0.5, 0])

        self.assertEqual(test[0], 0)
        slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True))
        self.assertEqual(test[0], 0.4)
        self.assertEqual(slider.get_value(), 0.4)
        slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True))
        self.assertAlmostEqual(slider.get_value(), 0.3)
        for _ in range(10):
            slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True))
        self.assertEqual(slider.get_value(), 0)
        self.assertTrue(
            slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True)))
        self.assertEqual(slider.get_value(), 0.1)
        self.assertEqual(test[1], 0)
        slider.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        self.assertEqual(test[1], 0.1)

        # Ignore invalid key
        self.assertFalse(
            slider.update(
                PygameEventUtils.key(ctrl.KEY_LEFT,
                                     keydown=True,
                                     testmode=False)))

        # Ignore for readonly
        slider.draw(surface)
        slider.draw_after_if_selected(surface)
        slider.readonly = True
        self.assertFalse(
            slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True)))
        self.assertEqual(slider.get_value(), 0.1)
        slider._update_value(0)
        self.assertEqual(slider.get_value(), 0.1)
        slider.readonly = False

        # Test invalid values
        self.assertRaises(AssertionError, lambda: slider.set_value(-1))
        self.assertRaises(AssertionError, lambda: slider.set_value([0.4, 0.5]))

        # Test invalid transforms
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: slider.rotate())
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: slider.flip())
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: slider.scale())
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: slider.resize())
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: slider.set_max_width())
        self.assertRaises(WidgetTransformationNotImplemented,
                          lambda: slider.set_max_height())

        # Test mouse click
        self.assertFalse(slider._selected_mouse)
        pos = slider._test_get_pos_value(0.5)
        slider.update(
            PygameEventUtils.middle_rect_click(pos,
                                               evtype=pygame.MOUSEBUTTONDOWN))
        self.assertEqual(slider.get_value(), 0.1)
        self.assertTrue(slider._selected_mouse)
        self.assertFalse(slider._scrolling)
        slider.update(PygameEventUtils.middle_rect_click(pos))
        self.assertFalse(slider._scrolling)
        self.assertEqual(slider.get_value(), 0.5)
        self.assertFalse(slider._selected_mouse)

        # Mouse click out of range
        slider._selected_mouse = True
        pos = slider._test_get_pos_value(1, dx=100)
        slider.update(PygameEventUtils.middle_rect_click(pos))
        self.assertEqual(slider.get_value(), 0.5)
        self.assertFalse(slider._selected_mouse)

        slider._selected_mouse = True
        pos = slider._test_get_pos_value(0, dx=-100)
        slider.update(PygameEventUtils.middle_rect_click(pos))
        self.assertEqual(slider.get_value(), 0.5)
        self.assertFalse(slider._selected_mouse)

        # Test extremes
        slider._selected_mouse = True
        pos = slider._test_get_pos_value(0)
        slider.update(PygameEventUtils.middle_rect_click(pos))
        self.assertEqual(slider.get_value(), 0)
        slider._selected_mouse = True
        pos = slider._test_get_pos_value(1)
        slider.update(PygameEventUtils.middle_rect_click(pos))
        self.assertEqual(slider.get_value(), 1)

        # Scroll to 0.5
        pos2 = slider._test_get_pos_value(0.5)
        self.assertFalse(slider._scrolling)
        slider_rect = slider._get_slider_inflate_rect(0, to_real_position=True)
        slider.update(
            PygameEventUtils.middle_rect_click(slider_rect,
                                               evtype=pygame.MOUSEBUTTONDOWN))
        self.assertTrue(slider._scrolling)
        self.assertTrue(slider._selected_mouse)
        dx = pos[0] - pos2[0]
        slider.update(
            PygameEventUtils.mouse_motion(slider_rect,
                                          rel=(-dx, pos[1]),
                                          update_mouse=True))
        self.assertEqual(slider.get_value(), 0.5)
        self.assertTrue(slider._scrolling)
        slider.update(PygameEventUtils.middle_rect_click(pos))
        self.assertFalse(slider._scrolling)

        # Check invalid constructor for single slider
        self.assertRaises(
            AssertionError, lambda: pygame_menu.widgets.RangeSlider(
                'Range S', default_value=2))
        self.assertRaises(
            AssertionError, lambda: pygame_menu.widgets.RangeSlider(
                'Range S', default_value=1, range_values=[1, 0]))
        self.assertRaises(
            AssertionError, lambda: pygame_menu.widgets.RangeSlider(
                'Range S', default_value=1, range_values=[1, 1]))
        self.assertRaises(
            AssertionError,
            lambda: pygame_menu.widgets.RangeSlider('Range S',
                                                    default_value='a'))

        # Ignore tabs
        self.assertFalse(
            slider.update(PygameEventUtils.key(ctrl.KEY_TAB, keydown=True)))

        # Check LEFT key in repeat
        self.assertIn(ctrl.KEY_RIGHT, slider._keyrepeat_counters.keys())
        self.assertEqual(slider.get_value(), 0.5)

        # Make left repeat
        slider._keyrepeat_counters[ctrl.KEY_RIGHT] += 1e4
        self.assertEqual(len(slider._events), 0)
        self.assertFalse(slider.update([]))
        self.assertEqual(len(slider._events), 1)
        self.assertFalse(slider.update(
            []))  # As key is not pressed, event continues
        self.assertEqual(len(slider._events), 0)

        # Keyup, removes counters
        slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keyup=True))
        self.assertNotIn(ctrl.KEY_RIGHT, slider._keyrepeat_counters.keys())
        self.assertFalse(hasattr(slider, '_range_box'))

        # Single slider with range box
        slider_rb = pygame_menu.widgets.RangeSlider(
            'Range', range_box_single_slider=True)
        menu.add.generic_widget(slider_rb, True)
        slider_rb.draw(surface)
        self.assertTrue(hasattr(slider_rb, '_range_box'))
        self.assertEqual(slider_rb._range_box.get_width(), 0)
        slider_rb.set_value(1)
        self.assertEqual(slider_rb._range_box.get_width(), 150)
Beispiel #13
0
    def test_single_discrete(self) -> None:
        """
        Test single range slider with discrete values.
        """
        menu = MenuUtils.generic_menu()

        # Single slider with discrete values
        rv = [0, 1, 2, 3, 4, 5]
        slider = pygame_menu.widgets.RangeSlider('Range', range_values=rv)
        menu.add.generic_widget(slider, True)

        self.assertRaises(
            AssertionError, lambda: pygame_menu.widgets.RangeSlider(
                'Range', default_value=0.5, range_values=rv))
        self.assertRaises(
            AssertionError, lambda: pygame_menu.widgets.RangeSlider(
                'Range', default_value=-1, range_values=rv))

        self.assertRaises(AssertionError, lambda: slider.set_value(-1))
        self.assertRaises(AssertionError, lambda: slider.set_value([0, 1]))
        self.assertRaises(AssertionError, lambda: slider.set_value((0, 1)))

        # Test key events
        self.assertFalse(
            slider.update(PygameEventUtils.key(ctrl.KEY_TAB, keydown=True)))
        slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True))
        self.assertEqual(slider.get_value(), 1)
        slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True))
        self.assertEqual(slider.get_value(), 2)
        slider._increment = 0
        slider.update(PygameEventUtils.key(ctrl.KEY_RIGHT, keydown=True))
        self.assertEqual(slider.get_value(), 3)
        slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True))
        self.assertEqual(slider.get_value(), 2)
        slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True))
        self.assertEqual(slider.get_value(), 1)
        slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True))
        self.assertEqual(slider.get_value(), 0)
        slider.update(PygameEventUtils.key(ctrl.KEY_LEFT, keydown=True))
        self.assertEqual(slider.get_value(), 0)

        # Test click mouse
        slider._selected_mouse = True
        pos = slider._test_get_pos_value(2)
        slider.update(PygameEventUtils.middle_rect_click(pos))
        self.assertEqual(slider.get_value(), 2)
        self.assertFalse(slider._selected_mouse)

        # Test invalid click
        slider._selected_mouse = True
        pos = slider._test_get_pos_value(2, dx=1000)
        slider.update(PygameEventUtils.middle_rect_click(pos))
        self.assertEqual(slider.get_value(), 2)
        self.assertFalse(slider._selected_mouse)

        # Scroll to 4
        pos = slider._test_get_pos_value(2)
        pos2 = slider._test_get_pos_value(4)
        self.assertFalse(slider._scrolling)
        slider_rect = slider._get_slider_inflate_rect(0, to_real_position=True)
        slider.update(
            PygameEventUtils.middle_rect_click(slider_rect,
                                               evtype=pygame.MOUSEBUTTONDOWN))
        self.assertTrue(slider._scrolling)
        self.assertTrue(slider._selected_mouse)
        dx = pos[0] - pos2[0]
        slider.update(
            PygameEventUtils.mouse_motion(slider_rect,
                                          rel=(-dx, pos[1]),
                                          update_mouse=True))
        self.assertEqual(slider.get_value(), 4)
        self.assertTrue(slider._scrolling)
        slider.update(PygameEventUtils.middle_rect_click(pos))
        self.assertFalse(slider._scrolling)

        # Back to 2
        slider.set_value(2)

        # Invalid scrolling if clicked outside the slider
        slider.update(
            PygameEventUtils.middle_rect_click(slider._test_get_pos_value(0),
                                               evtype=pygame.MOUSEBUTTONDOWN))
        self.assertFalse(slider._scrolling)
Beispiel #14
0
    def test_config(self) -> None:
        """
        Configure controls.
        """
        self.assertEqual(ctrl.KEY_APPLY, pygame.K_RETURN)

        # Change apply to new key
        ctrl.KEY_APPLY = pygame.K_END
        self.assertEqual(ctrl.KEY_APPLY, pygame.K_END)

        # Create new button
        menu = MenuUtils.generic_menu()
        test = [False]

        def click_button() -> None:
            """
            Button apply handler.
            """
            test[0] = not test[0]
            print('new test value', test)

        button = menu.add.button('button', click_button)
        self.assertFalse(test[0])
        button.apply()
        self.assertTrue(test[0])
        button.apply()
        self.assertFalse(test[0])

        # Now test new apply button
        button.update(PygameEventUtils.key(pygame.K_END, keydown=True))
        self.assertTrue(test[0])
        button.update(PygameEventUtils.key(pygame.K_END, keydown=True))
        self.assertFalse(test[0])

        # Rollback change
        ctrl.KEY_APPLY = pygame.K_RETURN

        # Create new controller object
        new_ctrl = ctrl.Controller()
        test_apply = [0]

        def new_apply(event, _) -> bool:
            """
            Updates apply.
            """
            test_apply[0] += 1
            return event.key == pygame.K_a

        new_ctrl.apply = new_apply
        button.set_controller(new_ctrl)

        # Now test new apply button
        button.update(PygameEventUtils.key(pygame.K_a, keydown=True))
        self.assertTrue(test[0])
        button.update(PygameEventUtils.key(pygame.K_a, keydown=True))
        self.assertFalse(test[0])
        self.assertEqual(test_apply[0], 2)

        button.update(PygameEventUtils.key(pygame.K_END, keydown=True))
        self.assertFalse(test[0])
        button.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
        self.assertFalse(
            test[0])  # It should do nothing as object has new controller

        # The same can be done with menu
        menu.set_controller(new_ctrl)
Beispiel #15
0
    def test_menu_link(self) -> None:
        """
        Test menu link.
        """
        menu = MenuUtils.generic_menu()
        menu1 = MenuUtils.generic_menu(title='Menu1',
                                       theme=pygame_menu.themes.THEME_BLUE)
        menu1.add.button('Back', pygame_menu.events.BACK)
        menu2 = MenuUtils.generic_menu(title='Menu2',
                                       theme=pygame_menu.themes.THEME_ORANGE)
        menu2.add.button('Back', pygame_menu.events.BACK)
        menu3 = MenuUtils.generic_menu(title='Menu3',
                                       theme=pygame_menu.themes.THEME_GREEN)
        menu3.add.button('Back', pygame_menu.events.BACK)
        btn1 = menu.add.button('menu1', menu1)
        btn2 = menu.add.button('menu2', menu2)
        btn3 = menu.add.button('menu3', menu3)

        # Hide the buttons
        btn1.hide()
        btn2.hide()
        btn3.hide()

        # Now open menu with the button, this should open Menu1 by default
        self.assertEqual(menu.get_current(), menu)
        btn1.apply()
        self.assertEqual(menu.get_current(), menu1)
        menu.full_reset()
        self.assertEqual(menu.get_current(), menu)

        # Add menu link
        link_test = menu.add.menu_link(menu2)
        link_test.open()
        self.assertEqual(menu.get_current(), menu2)
        menu.full_reset()
        self.assertEqual(menu.get_current(), menu)

        self.assertFalse(link_test.is_visible())
        link_test.hide()
        self.assertFalse(link_test.is_visible())
        link_test.show()
        self.assertFalse(link_test.is_visible())

        self.assertRaises(ValueError, lambda: menu.add.menu_link(menu))

        # Invalid objects
        self.assertRaises(ValueError, lambda: menu.add.menu_link(True))

        # noinspection PyMissingTypeHints,PyMissingOrEmptyDocstring
        def open_link(*args) -> None:
            link: 'pygame_menu.widgets.MenuLink' = args[-1]
            self.assertIsInstance(link, pygame_menu.widgets.MenuLink)
            link.open()

        # Add a selection object, which opens the links
        sel = menu.add.selector('Change menu ',
                                [('Menu 1', menu.add.menu_link(menu1)),
                                 ('Menu 2', menu.add.menu_link(menu2)),
                                 ('Menu 3', menu.add.menu_link(menu3))],
                                onreturn=open_link,
                                style=pygame_menu.widgets.SELECTOR_STYLE_FANCY)

        sel.update(PygameEventUtils.key(ctrl.KEY_APPLY, keydown=True))
    def test_unicode(self) -> None:
        """
        Test unicode support.
        """
        menu = MenuUtils.generic_menu()
        textinput = menu.add.text_input('title', input_underline='_')
        textinput.set_value('tk')

        # Test alt+x
        textinput.update(PygameEventUtils.key(pygame.K_SPACE, keydown=True))
        textinput.update(
            PygameEventUtils.key(pygame.K_2, keydown=True, char='2'))
        textinput.update(
            PygameEventUtils.key(pygame.K_1, keydown=True, char='1'))
        textinput.update(
            PygameEventUtils.key(pygame.K_1, keydown=True, char='5'))
        self.assertEqual(textinput.get_value(), 'tk 215')
        textinput.update(PygameEventUtils.keydown_mod_alt(
            pygame.K_x))  # convert 215 to unicode
        self.assertEqual(textinput.get_value(), 'tkȕ')
        textinput.update(PygameEventUtils.key(pygame.K_SPACE, keydown=True))
        textinput.update(PygameEventUtils.key(pygame.K_SPACE, keydown=True))
        textinput.update(
            PygameEventUtils.key(pygame.K_b, keydown=True, char='B'))
        textinput.update(
            PygameEventUtils.key(pygame.K_1, keydown=True, char='1'))
        textinput.update(PygameEventUtils.keydown_mod_alt(
            pygame.K_x))  # convert 215 to unicode
        self.assertEqual(textinput.get_value(), 'tkȕ ±')

        # Remove all
        textinput.clear()
        textinput.update(
            PygameEventUtils.key(pygame.K_b, keydown=True, char='B'))
        textinput.update(
            PygameEventUtils.key(pygame.K_1, keydown=True, char='1'))
        textinput.update(PygameEventUtils.keydown_mod_alt(
            pygame.K_x))  # convert 215 to unicode
        self.assertEqual(textinput.get_value(), '±')
        textinput.update(PygameEventUtils.keydown_mod_alt(
            pygame.K_x))  # convert same to unicode, do nothing
        self.assertEqual(textinput.get_value(), '±')

        # Test consecutive
        textinput.update(
            PygameEventUtils.key(pygame.K_2, keydown=True, char='2'))
        textinput.update(
            PygameEventUtils.key(pygame.K_0, keydown=True, char='0'))
        textinput.update(
            PygameEventUtils.key(pygame.K_1, keydown=True, char='1'))
        textinput.update(
            PygameEventUtils.key(pygame.K_3, keydown=True, char='3'))
        textinput.update(PygameEventUtils.keydown_mod_alt(
            pygame.K_x))  # convert 215 to unicode
        self.assertEqual(textinput.get_value(), '±–')

        # Test 0x
        textinput.clear()
        PygameEventUtils.release_key_mod()
        textinput.update(
            PygameEventUtils.key(pygame.K_0, keydown=True, char='0'))
        self.assertEqual(textinput.get_value(), '0')
        textinput.update(
            PygameEventUtils.key(pygame.K_x, keydown=True, char='x'))
        self.assertEqual(textinput.get_value(), '0x')
        textinput.update(PygameEventUtils.keydown_mod_alt(pygame.K_x))
        self.assertEqual(textinput.get_value(), '0x')
        textinput.update(
            PygameEventUtils.key(pygame.K_b, keydown=True, char='B'))
        textinput.update(
            PygameEventUtils.key(pygame.K_1, keydown=True, char='1'))
        self.assertEqual(textinput.get_value(), '0xB1')
        textinput.update(PygameEventUtils.keydown_mod_alt(pygame.K_x))
        self.assertEqual(textinput.get_value(), '±')
        PygameEventUtils.release_key_mod()

        textinput.update(
            PygameEventUtils.key(pygame.K_0, keydown=True, char='0'))
        textinput.update(
            PygameEventUtils.key(pygame.K_x, keydown=True, char='x'))
        textinput.update(
            PygameEventUtils.key(pygame.K_b, keydown=True, char='B'))
        textinput.update(
            PygameEventUtils.key(pygame.K_1, keydown=True, char='1'))
        textinput.update(PygameEventUtils.keydown_mod_alt(pygame.K_x))
        self.assertEqual(textinput.get_value(), '±±')

        # Test keyup
        self.assertIn(pygame.K_1, textinput._keyrepeat_counters.keys())
        self.assertFalse(
            textinput.update(
                PygameEventUtils.key(pygame.K_1, keyup=True, char='1')))
        self.assertNotIn(pygame.K_1, textinput._keyrepeat_counters.keys())

        # Test tab
        self.assertEqual(textinput._tab_size, 4)
        textinput.update(PygameEventUtils.key(pygame.K_TAB, keydown=True))
        self.assertEqual(textinput.get_value(), '±±    ')

        # Test invalid unicode
        self.assertFalse(
            textinput.update(PygameEventUtils.key(pygame.K_1, keydown=True)))

        # Test others
        textinput._input_type = 'other'
        self.assertTrue(textinput._check_input_type('-'))
        self.assertFalse(textinput._check_input_type('x'))
        textinput._maxwidth_update = None
        self.assertIsNone(textinput._update_maxlimit_renderbox())
    def test_colorinput(self) -> None:
        """
        Test ColorInput widget.
        """
        def _assert_invalid_color(widg) -> None:
            """
            Assert that the widget color is invalid.
            :param widg: Widget object
            """
            r, g, b = widg.get_value()
            self.assertEqual(r, -1)
            self.assertEqual(g, -1)
            self.assertEqual(b, -1)

        def _assert_color(widg, cr, cg, cb) -> None:
            """
            Assert that the widget color is invalid.
            :param widg: Widget object
            :param cr: Red channel, number between 0 and 255
            :param cg: Green channel, number between 0 and 255
            :param cb: Blue channel, number between 0 and 255
            """
            r, g, b = widg.get_value()
            self.assertEqual(r, cr)
            self.assertEqual(g, cg)
            self.assertEqual(b, cb)

        menu = MenuUtils.generic_menu(theme=TEST_THEME.copy())

        # Base rgb
        widget = menu.add.color_input('title',
                                      color_type='rgb',
                                      input_separator=',')
        widget.set_value((123, 234, 55))
        self.assertRaises(AssertionError, lambda: widget.set_value('0,0,0'))
        self.assertRaises(AssertionError, lambda: widget.set_value((
            255,
            0,
        )))
        self.assertRaises(AssertionError, lambda: widget.set_value(
            (255, 255, -255)))
        _assert_color(widget, 123, 234, 55)

        # Test separator
        widget = menu.add.color_input('color',
                                      color_type='rgb',
                                      input_separator='+')
        widget.set_value((34, 12, 12))
        self.assertEqual(widget._input_string, '34+12+12')
        self.assertRaises(
            AssertionError, lambda: menu.add.color_input(
                'title', color_type='rgb', input_separator=''))
        self.assertRaises(
            AssertionError, lambda: menu.add.color_input(
                'title', color_type='rgb', input_separator='  '))
        self.assertRaises(
            AssertionError,
            lambda: menu.add.color_input('title', color_type='unknown'))
        for i in range(10):
            self.assertRaises(
                AssertionError, lambda: menu.add.color_input(
                    'title', color_type='rgb', input_separator=str(i)))

        # Empty rgb
        widget = menu.add.color_input('color',
                                      color_type='rgb',
                                      input_separator=',')

        PygameEventUtils.test_widget_key_press(widget)
        self.assertEqual(widget._cursor_position, 0)
        widget.update(PygameEventUtils.key(pygame.K_RIGHT, keydown=True))
        self.assertEqual(widget._cursor_position, 0)
        _assert_invalid_color(widget)

        # Write sequence: 2 -> 25 -> 25, -> 25,0,
        # The comma after the zero must be automatically set
        self.assertFalse(
            widget.update(PygameEventUtils.key(0, keydown=True,
                                               testmode=False)))
        widget.update(PygameEventUtils.key(pygame.K_2, keydown=True, char='2'))
        widget.update(PygameEventUtils.key(pygame.K_5, keydown=True, char='5'))
        widget.update(
            PygameEventUtils.key(pygame.K_COMMA, keydown=True, char=','))
        self.assertEqual(widget._input_string, '25,')
        widget.update(PygameEventUtils.key(pygame.K_0, keydown=True, char='0'))
        self.assertEqual(widget._input_string, '25,0,')
        _assert_invalid_color(widget)

        # Now, sequence: 25,0,c -> 25c,0, with cursor c
        widget.update(PygameEventUtils.key(pygame.K_LEFT, keydown=True))
        widget.update(PygameEventUtils.key(pygame.K_LEFT, keydown=True))
        widget.update(PygameEventUtils.key(pygame.K_LEFT, keydown=True))
        self.assertEqual(widget._cursor_position, 2)

        # Sequence. 25,0, -> 255,0, -> 255,0, trying to write another 5 in the same position
        # That should be cancelled because 2555 > 255
        widget.update(PygameEventUtils.key(pygame.K_5, keydown=True, char='5'))
        self.assertEqual(widget._input_string, '255,0,')
        widget.update(PygameEventUtils.key(pygame.K_5, keydown=True, char='5'))
        self.assertEqual(widget._input_string, '255,0,')

        # Invalid left zeros, try to write 255,0, -> 255,00, but that should be disabled
        widget.update(PygameEventUtils.key(pygame.K_RIGHT, keydown=True))
        widget.update(PygameEventUtils.key(pygame.K_0, keydown=True, char='0'))
        self.assertEqual(widget._input_string, '255,0,')

        # Second comma cannot be deleted because there's a number between ,0,
        widget.update(PygameEventUtils.key(pygame.K_BACKSPACE, keydown=True))
        self.assertEqual(widget._input_string, '255,0,')
        widget.update(PygameEventUtils.key(pygame.K_LEFT, keydown=True))
        widget.update(PygameEventUtils.key(pygame.K_DELETE, keydown=True))
        self.assertEqual(widget._input_string, '255,0,')

        # Current cursor is at 255c,0,
        # Now right comma and 0 can be deleted
        widget.update(PygameEventUtils.key(pygame.K_END, keydown=True))
        widget.update(PygameEventUtils.key(pygame.K_BACKSPACE, keydown=True))
        widget.update(PygameEventUtils.key(pygame.K_BACKSPACE, keydown=True))
        self.assertEqual(widget._input_string, '255,')

        # Fill with zeros, then number with 2 consecutive 0 types must be 255,0,0
        # Commas should be inserted automatically
        widget.readonly = True
        widget.update(PygameEventUtils.key(pygame.K_0, keydown=True, char='0'))
        self.assertEqual(widget._input_string, '255,')
        widget.readonly = False
        widget.update(PygameEventUtils.key(pygame.K_0, keydown=True, char='0'))
        widget.update(PygameEventUtils.key(pygame.K_0, keydown=True, char='0'))
        self.assertEqual(widget._input_string, '255,0,0')
        _assert_color(widget, 255, 0, 0)

        # At this state, user cannot add more zeros at right
        for i in range(5):
            widget.update(
                PygameEventUtils.key(pygame.K_0, keydown=True, char='0'))
        self.assertEqual(widget._input_string, '255,0,0')
        widget.get_rect()

        widget.clear()
        self.assertEqual(widget._input_string, '')

        # Assert invalid defaults rgb
        self.assertRaises(
            AssertionError, lambda: menu.add.color_input(
                'title', color_type='rgb', default=(
                    255,
                    255,
                )))
        self.assertRaises(
            AssertionError, lambda: menu.add.color_input(
                'title', color_type='rgb', default=(255, 255)))
        self.assertRaises(
            AssertionError, lambda: menu.add.color_input(
                'title', color_type='rgb', default=(255, 255, 255, 255)))

        # Assert hex widget
        widget = menu.add.color_input('title', color_type='hex')
        self.assertEqual(widget._input_string, '#')
        self.assertEqual(widget._cursor_position, 1)
        _assert_invalid_color(widget)
        self.assertRaises(AssertionError, lambda: widget.set_value('#FF'))
        self.assertRaises(AssertionError, lambda: widget.set_value('#FFFFF<'))
        self.assertRaises(AssertionError, lambda: widget.set_value('#FFFFF'))
        self.assertRaises(AssertionError, lambda: widget.set_value('#F'))
        # noinspection SpellCheckingInspection
        self.assertRaises(AssertionError, lambda: widget.set_value('FFFFF'))
        self.assertRaises(AssertionError, lambda: widget.set_value('F'))
        widget.set_value('FF00FF')
        _assert_color(widget, 255, 0, 255)
        widget.set_value('#12FfAa')
        _assert_color(widget, 18, 255, 170)
        widget.set_value('   59C1e5')
        _assert_color(widget, 89, 193, 229)

        widget.render()
        widget.draw(surface)

        widget.clear()
        self.assertEqual(widget._input_string, '#')  # This cannot be empty
        self.assertEqual(widget._cursor_position, 1)

        # In hex widget # cannot be deleted
        widget.update(PygameEventUtils.key(pygame.K_BACKSPACE, keydown=True))
        self.assertEqual(widget._cursor_position, 1)
        widget.update(PygameEventUtils.key(pygame.K_LEFT, keydown=True))
        widget.update(PygameEventUtils.key(pygame.K_DELETE, keydown=True))
        self.assertEqual(widget._input_string, '#')
        widget.update(PygameEventUtils.key(pygame.K_END, keydown=True))
        for i in range(10):
            widget.update(
                PygameEventUtils.key(pygame.K_f, keydown=True, char='f'))
        self.assertEqual(widget._input_string, '#ffffff')
        _assert_color(widget, 255, 255, 255)

        # Test hex formats
        widget = menu.add.color_input('title',
                                      color_type='hex',
                                      hex_format='none')
        widget.set_value('#ff00ff')
        self.assertFalse(
            widget.update(PygameEventUtils.key(0, keydown=True,
                                               testmode=False)))
        self.assertEqual(widget.get_value(as_string=True), '#ff00ff')
        widget.set_value('#FF00ff')
        self.assertEqual(widget.get_value(as_string=True), '#FF00ff')

        widget = menu.add.color_input('title',
                                      color_type='hex',
                                      hex_format='lower')
        widget.set_value('#FF00ff')
        self.assertEqual(widget.get_value(as_string=True), '#ff00ff')
        widget.set_value('AABBcc')
        self.assertEqual(widget.get_value(as_string=True), '#aabbcc')

        widget = menu.add.color_input('title',
                                      color_type='hex',
                                      hex_format='upper')
        widget.set_value('#FF00ff')
        self.assertEqual(widget.get_value(as_string=True), '#FF00FF')
        widget.set_value('AABBcc')
        self.assertEqual(widget.get_value(as_string=True), '#AABBCC')

        # Test dynamic sizing
        widget = menu.add.color_input('title',
                                      color_type='hex',
                                      hex_format='upper',
                                      dynamic_width=True)
        self.assertEqual(widget.get_width(), 200)
        widget.set_value('#ffffff')
        width = 342 if PYGAME_V2 else 345
        self.assertEqual(widget.get_width(), width)
        widget.set_value(None)
        self.assertEqual(widget.get_width(), 200)
        self.assertEqual(widget.get_value(as_string=True), '#')
        widget.set_value('#ffffff')
        self.assertEqual(widget.get_width(), width)
        widget.update(PygameEventUtils.key(
            pygame.K_BACKSPACE,
            keydown=True))  # remove the last character, now color is invalid
        self.assertEqual(widget.get_value(as_string=True),
                         '#FFFFF')  # is upper
        widget.render()
        self.assertEqual(widget.get_width(), 200)

        widget = menu.add.color_input('title',
                                      color_type='hex',
                                      hex_format='upper',
                                      dynamic_width=False)
        self.assertEqual(widget.get_width(), width)
        widget.set_value('#ffffff')
        self.assertEqual(widget.get_width(), width)
Beispiel #18
0
    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)))