Example #1
0
    def update(self, events):
        updated = False
        for event in events:  # type: pygame.event.Event

            if event.type == pygame.KEYDOWN:  # Check key is valid
                if not check_key_pressed_valid(event):
                    continue

            # Events
            keydown = event.type == pygame.KEYDOWN
            joy_hatmotion = self.joystick_enabled and event.type == pygame.JOYHATMOTION
            joy_axismotion = self.joystick_enabled and event.type == pygame.JOYAXISMOTION
            joy_button_down = self.joystick_enabled and event.type == pygame.JOYBUTTONDOWN

            if keydown and event.key == _controls.KEY_LEFT or \
                    joy_hatmotion and event.value == _controls.JOY_LEFT or \
                    joy_axismotion and event.axis == _controls.JOY_AXIS_X and event.value < _controls.JOY_DEADZONE:
                self.sound.play_key_add()
                self.left()
                updated = True

            elif keydown and event.key == _controls.KEY_RIGHT or \
                    joy_hatmotion and event.value == _controls.JOY_RIGHT or \
                    joy_axismotion and event.axis == _controls.JOY_AXIS_X and event.value > -_controls.JOY_DEADZONE:
                self.sound.play_key_add()
                self.right()
                updated = True

            elif keydown and event.key == _controls.KEY_APPLY or \
                    joy_button_down and event.button == _controls.JOY_BUTTON_SELECT:
                self.sound.play_open_menu()
                self.apply(*self._elements[self._index][1:])
                updated = True

            elif self.mouse_enabled and event.type == pygame.MOUSEBUTTONUP:
                if self._rect.collidepoint(*event.pos):
                    # Check if mouse collides left or right as percentage, use only X coordinate
                    mousex, _ = event.pos
                    topleft, _ = self._rect.topleft
                    topright, _ = self._rect.topright
                    dist = mousex - (topleft + self._title_size
                                     )  # Distance from label
                    if dist > 0:  # User clicked the options, not label

                        # Position in percentage, if <0.5 user clicked left
                        pos = dist / float(topright - topleft -
                                           self._title_size)
                        if pos <= 0.5:
                            self.left()
                        else:
                            self.right()
                        updated = True

        return updated
Example #2
0
    def update(
        self, events: Union[List['pygame.event.Event'],
                            Tuple['pygame.event.Event']]
    ) -> bool:
        if self.readonly:
            return False
        updated = False

        for event in events:

            if event.type == pygame.KEYDOWN:  # Check key is valid
                if not check_key_pressed_valid(event):
                    continue

            # Events
            keydown = event.type == pygame.KEYDOWN
            joy_hatmotion = self._joystick_enabled and event.type == pygame.JOYHATMOTION
            joy_axismotion = self._joystick_enabled and event.type == pygame.JOYAXISMOTION
            joy_button_down = self._joystick_enabled and event.type == pygame.JOYBUTTONDOWN

            # Left button
            if keydown and event.key == _controls.KEY_LEFT or \
                    joy_hatmotion and event.value == _controls.JOY_LEFT or \
                    joy_axismotion and event.axis == _controls.JOY_AXIS_X and event.value < _controls.JOY_DEADZONE:
                self._sound.play_key_add()
                self._left()
                updated = True

            # Right button
            elif keydown and event.key == _controls.KEY_RIGHT or \
                    joy_hatmotion and event.value == _controls.JOY_RIGHT or \
                    joy_axismotion and event.axis == _controls.JOY_AXIS_X and event.value > -_controls.JOY_DEADZONE:
                self._sound.play_key_add()
                self._right()
                updated = True

            # Press enter
            elif keydown and event.key == _controls.KEY_APPLY or \
                    joy_button_down and event.button == _controls.JOY_BUTTON_SELECT:
                self._sound.play_open_menu()
                self.apply(*self._elements[self._index][1:])
                updated = True

            # Click on selector
            elif self._mouse_enabled and event.type == pygame.MOUSEBUTTONUP or \
                    self._touchscreen_enabled and event.type == pygame.FINGERUP:

                # Get event position based on input type
                if self._touchscreen_enabled and event.type == pygame.FINGERUP:
                    window_size = self.get_menu().get_window_size()
                    event_pos = (event.x * window_size[0],
                                 event.y * window_size[1])
                else:
                    event_pos = event.pos

                # If collides
                rect = self.get_rect()
                if rect.collidepoint(*event_pos):
                    # Check if mouse collides left or right as percentage, use only X coordinate
                    mousex, _ = event.pos
                    topleft, _ = rect.topleft
                    topright, _ = rect.topright
                    dist = mousex - (topleft + self._title_size
                                     )  # Distance from title
                    if dist > 0:  # User clicked the options, not title
                        # Position in percentage, if <0.5 user clicked left
                        pos = dist / float(topright - topleft -
                                           self._title_size)
                        if pos <= 0.5:
                            self._left()
                        else:
                            self._right()
                        updated = True

        if updated:
            self.apply_update_callbacks()

        return updated
    def update(self, events):
        _input = self._input_string
        _curpos = self._cursor_position
        _disable_remove_separator = True

        key = ''  # Pressed key
        if self._color_type == TYPE_RGB:
            for event in events:  # type: pygame.event.Event
                if event.type == pygame.KEYDOWN:

                    # Check if any key is pressed, if True the event is invalid
                    if not check_key_pressed_valid(event):
                        return True

                    if _disable_remove_separator and len(_input) > 0 and len(
                            _input) > _curpos and (
                                '{0}{0}'.format(self._separator) not in _input
                                or _input[_curpos] == self._separator
                                and len(_input) == _curpos + 1):

                        # Backspace button, delete text from right
                        if event.key == pygame.K_BACKSPACE:
                            if len(_input) >= 1 and _input[
                                    _curpos - 1] == self._separator:
                                return True

                        # Delete button, delete text from left
                        elif event.key == pygame.K_DELETE:
                            if _input[_curpos] == self._separator:
                                return True

                    # Verify only on user key input, the rest of events are checked by TextInput on super call
                    key = str(event.unicode)
                    if key in self._valid_chars:

                        _new_string = (
                            self._input_string[:self._cursor_position] + key +
                            self._input_string[self._cursor_position:])

                        # Cannot be separator at first
                        if len(_input) == 0 and key == self._separator:
                            return False

                        if len(_input) > 1:

                            # Check separators
                            if key == self._separator:

                                # If more than 2 separators
                                _total_separator = 0
                                for _ch in _input:
                                    if _ch == self._separator:
                                        _total_separator += 1
                                if _total_separator >= 2:
                                    return False

                            # Check the number between the current separators, this number must be between 0-255
                            if key != self._separator:
                                _pos_before = 0
                                _pos_after = 0
                                for _i in range(_curpos):
                                    if _new_string[_curpos - _i -
                                                   1] == self._separator:
                                        _pos_before = _curpos - _i
                                        break
                                for _i in range(len(_new_string) - _curpos):
                                    if _new_string[_curpos +
                                                   _i] == self._separator:
                                        _pos_after = _curpos + _i
                                        break
                                if _pos_after == 0:
                                    _pos_after = len(_new_string)
                                _num = _new_string[
                                    _pos_before:_pos_after].replace(',', '')
                                if _num == '':
                                    _num = '0'

                                if int(_num) > 255:  # Number exceeds 25X
                                    return False
                                if _num != str(
                                        int(_num)
                                ) and key == '0':  # User adds 0 at left, example: 12 -> 012
                                    return False
                                if len(_num) > 3:  # Number like 0XXX
                                    return False

        elif self._color_type == TYPE_HEX:
            for event in events:  # type: pygame.event.Event
                if event.type == pygame.KEYDOWN:

                    # Check if any key is pressed, if True the event is invalid
                    if not check_key_pressed_valid(event):
                        return True

                    # Backspace button, delete text from right
                    if event.key == pygame.K_BACKSPACE:
                        if _curpos == 1:
                            return True

                    # Delete button, delete text from left
                    elif event.key == pygame.K_DELETE:
                        if _curpos == 0:
                            return True

                    # Verify only on user key input, the rest of events are checked by TextInput on super call
                    key = str(event.unicode)
                    if key in self._valid_chars:
                        if key == '#':
                            return True
                        if _curpos == 0:
                            return True

        # Update
        updated = super(ColorInput, self).update(events)

        # After
        if self._color_type == TYPE_RGB:

            _total_separator = 0
            for _ch in _input:
                if _ch == self._separator:
                    _total_separator += 1

            # Adds auto separator
            if key == '0' and len(self._input_string) == self._cursor_position and _total_separator < 2 and \
                    (len(self._input_string) == 1 or
                     (len(self._input_string) > 2 and self._input_string[
                         self._cursor_position - 2] == self._separator)):
                self._push_key_input(self._separator,
                                     sounds=False)  # This calls .onchange()

            # Check number is valid (fix) because sometimes the user can type
            # too fast and avoid analysis of the text
            colors = self._input_string.split(self._separator)
            for c in colors:
                if len(c) > 0 and (int(c) > 255 or int(c) < 0):
                    self._input_string = _input
                    self._cursor_position = _curpos
                    break

            if len(colors) == 3:
                self._auto_separator_pos = [0, 1]

            # Add an auto separator if the number can't continue growing and the cursor
            # is at the end of the line
            if _total_separator < 2 and len(
                    self._input_string) == self._cursor_position:
                autopos = len(colors) - 1
                last_num = colors[autopos]
                if (len(last_num) == 2 and int(last_num) > 25 or len(last_num) == 3 and int(last_num) <= 255) and \
                        autopos not in self._auto_separator_pos:
                    self._push_key_input(
                        self._separator,
                        sounds=False)  # This calls .onchange()
                    self._auto_separator_pos.append(autopos)

            # If the user cleared all the string, reset auto separator
            if _total_separator == 0 and \
                    (len(self._input_string) < 2 or len(self._input_string) == 2 and int(colors[0]) <= 25):
                self._auto_separator_pos = []

        return updated
Example #4
0
    def update(self, events: EventVectorType) -> bool:
        if self.readonly or not self.is_visible():
            return False
        input_str = self._input_string
        cursor_pos = self._cursor_position
        disable_remove_separator = True

        key = ''  # Pressed key

        if self._color_type == COLORINPUT_TYPE_RGB:
            for event in events:

                # User writes
                if event.type == pygame.KEYDOWN and self._keyboard_enabled:

                    # Check if any key is pressed, if True the event is invalid
                    if not check_key_pressed_valid(event):
                        return True

                    if disable_remove_separator and len(input_str) > 0 and len(input_str) > cursor_pos and (
                            '{0}{0}'.format(self._separator) not in input_str or
                            input_str[cursor_pos] == self._separator and len(input_str) == cursor_pos + 1
                    ):

                        # Backspace button, delete text from right
                        if event.key == pygame.K_BACKSPACE:
                            if len(input_str) >= 1 and input_str[cursor_pos - 1] == self._separator:
                                return True

                        # Delete button, delete text from left
                        elif event.key == pygame.K_DELETE:
                            if input_str[cursor_pos] == self._separator:
                                return True

                    # Verify only on user key input, the rest of events are checked by TextInput on super call
                    key = str(event.unicode)
                    if key in self._valid_chars:

                        new_string = (
                                self._input_string[:self._cursor_position]
                                + key
                                + self._input_string[self._cursor_position:]
                        )

                        # Cannot be separator at first
                        if len(input_str) == 0 and key == self._separator:
                            return False

                        if len(input_str) > 1:

                            # Check separators
                            if key == self._separator:

                                # If more than 2 separators
                                total_separator = 0
                                for ch in input_str:
                                    if ch == self._separator:
                                        total_separator += 1
                                if total_separator >= 2:
                                    return False

                            # Check the number between the current separators, this number must be between 0-255
                            if key != self._separator:
                                pos_before = 0
                                pos_after = 0
                                for i in range(cursor_pos):
                                    if new_string[cursor_pos - i - 1] == self._separator:
                                        pos_before = cursor_pos - i
                                        break
                                for i in range(len(new_string) - cursor_pos):
                                    if new_string[cursor_pos + i] == self._separator:
                                        pos_after = cursor_pos + i
                                        break
                                if pos_after == 0:
                                    pos_after = len(new_string)
                                num = new_string[pos_before:pos_after].replace(',', '')
                                if num == '':
                                    num = '0'

                                if int(num) > 255:  # Number exceeds 25X
                                    return False
                                if num != str(int(num)) and key == '0':  # User adds 0 at left, example: 12 -> 012
                                    return False
                                if len(num) > 3:  # Number like 0XXX
                                    return False

        elif self._color_type == COLORINPUT_TYPE_HEX:
            self._format_hex()

            for event in events:

                # User writes
                if event.type == pygame.KEYDOWN and self._keyboard_enabled:

                    # Check if any key is pressed, if True the event is invalid
                    if not check_key_pressed_valid(event):
                        return True

                    # Backspace button, delete text from right
                    if event.key == pygame.K_BACKSPACE:
                        if cursor_pos == 1:
                            return True

                    # Delete button, delete text from left
                    elif event.key == pygame.K_DELETE:
                        if cursor_pos == 0:
                            return True

                    # Verify only on user key input, the rest of events are checked by TextInput on super call
                    key = str(event.unicode)
                    if key in self._valid_chars:
                        if key == '#':
                            return True
                        if cursor_pos == 0:
                            return True

        # Update
        updated = super(ColorInput, self).update(events)

        # After
        if self._color_type == COLORINPUT_TYPE_RGB:

            total_separator = 0
            for ch in input_str:
                if ch == self._separator:
                    total_separator += 1

            # Adds auto separator
            if key == '0' and len(self._input_string) == self._cursor_position and total_separator < 2 and \
                    (len(self._input_string) == 1 or
                     (len(self._input_string) > 2 and self._input_string[
                         self._cursor_position - 2] == self._separator)):
                self._push_key_input(self._separator, sounds=False)  # This calls .onchange()

            # Check number is valid (fix) because sometimes the user can type
            # too fast and avoid analysis of the text
            colors = self._input_string.split(self._separator)
            for c in colors:
                if len(c) > 0 and (int(c) > 255 or int(c) < 0):
                    self._input_string = input_str
                    self._cursor_position = cursor_pos
                    break

            if len(colors) == 3:
                self._auto_separator_pos = [0, 1]

            # Add an auto separator if the number can't continue growing and the cursor
            # is at the end of the line
            if total_separator < 2 and len(self._input_string) == self._cursor_position:
                auto_pos = len(colors) - 1
                last_num = colors[auto_pos]
                if (len(last_num) == 2 and int(last_num) > 25 or len(last_num) == 3 and int(last_num) <= 255) and \
                        auto_pos not in self._auto_separator_pos:
                    self._push_key_input(self._separator, sounds=False)  # This calls .onchange()
                    self._auto_separator_pos.append(auto_pos)

            # If the user cleared all the string, reset auto separator
            if total_separator == 0 and \
                    (len(self._input_string) < 2 or len(self._input_string) == 2 and int(colors[0]) <= 25):
                self._auto_separator_pos = []

        if updated:
            self.apply_update_callbacks()

        return updated
Example #5
0
    def update(self, events: EventVectorType) -> bool:
        self.apply_update_callbacks(events)

        if self.readonly or not self.is_visible():
            return False
        updated = False

        for event in events:

            if event.type == pygame.KEYDOWN:  # Check key is valid
                if not check_key_pressed_valid(event):
                    continue

            # Check mouse over
            self._check_mouseover(event)

            # Events
            keydown = self._keyboard_enabled and event.type == pygame.KEYDOWN
            joy_hatmotion = self._joystick_enabled and event.type == pygame.JOYHATMOTION
            joy_axismotion = self._joystick_enabled and event.type == pygame.JOYAXISMOTION
            joy_button_down = self._joystick_enabled and event.type == pygame.JOYBUTTONDOWN

            # Left button
            if keydown and event.key == ctrl.KEY_LEFT or \
                    joy_hatmotion and event.value == ctrl.JOY_LEFT or \
                    joy_axismotion and event.axis == ctrl.JOY_AXIS_X and event.value < ctrl.JOY_DEADZONE:
                self._left()
                updated = True

            # Right button
            elif keydown and event.key == ctrl.KEY_RIGHT or \
                    joy_hatmotion and event.value == ctrl.JOY_RIGHT or \
                    joy_axismotion and event.axis == ctrl.JOY_AXIS_X and event.value > -ctrl.JOY_DEADZONE:
                self._right()
                updated = True

            # Press enter
            elif keydown and event.key == ctrl.KEY_APPLY or \
                    joy_button_down and event.button == ctrl.JOY_BUTTON_SELECT:
                self._sound.play_key_add()
                self.apply(*self._items[self._index][1:])
                updated = True

            # Click on selector; don't consider the mouse wheel (button 4 & 5)
            elif event.type == pygame.MOUSEBUTTONUP and self._mouse_enabled and \
                    event.button in (1, 2, 3) or \
                    event.type == FINGERUP and self._touchscreen_enabled and \
                    self._menu is not None:
                event_pos = get_finger_pos(self._menu, event)

                # If collides
                rect = self.get_rect(to_real_position=True,
                                     apply_padding=False)
                if rect.collidepoint(*event_pos):
                    # Check if mouse collides left or right as percentage, use only X coordinate
                    mouse_x, _ = event.pos
                    topleft, _ = rect.topleft
                    topright, _ = rect.topright
                    dist = mouse_x - (topleft + self._title_size
                                      )  # Distance from title
                    if dist > 0:  # User clicked the options, not title
                        # Position in percentage, if <0.5 user clicked left
                        pos = dist / float(topright - topleft -
                                           self._title_size)
                        if pos <= 0.5:
                            self._left()
                        else:
                            self._right()
                        updated = True

        return updated
Example #6
0
    def update(self, events: EventVectorType) -> bool:
        self.apply_update_callbacks(events)

        if self.readonly or not self.is_visible():
            return False
        updated = False

        for event in events:

            if event.type == pygame.KEYDOWN:  # Check key is valid
                if not check_key_pressed_valid(event):
                    continue

            # Check mouse over
            self._check_mouseover(event)

            # Events
            keydown = self._keyboard_enabled and event.type == pygame.KEYDOWN
            joy_hatmotion = self._joystick_enabled and event.type == pygame.JOYHATMOTION
            joy_axismotion = self._joystick_enabled and event.type == pygame.JOYAXISMOTION

            # Left button
            if keydown and event.key == KEY_LEFT or \
                    joy_hatmotion and event.value == JOY_LEFT or \
                    joy_axismotion and event.axis == JOY_AXIS_X and event.value < JOY_DEADZONE:
                self._left()
                updated = True

            # Right button
            elif keydown and event.key == KEY_RIGHT or \
                    joy_hatmotion and event.value == JOY_RIGHT or \
                    joy_axismotion and event.axis == JOY_AXIS_X and event.value > -JOY_DEADZONE:
                self._right()
                updated = True

            # Press enter
            elif keydown and event.key == KEY_APPLY and self._total_states == 2 or \
                    event.type == pygame.JOYBUTTONDOWN and self._joystick_enabled and \
                    event.button == JOY_BUTTON_SELECT and self._total_states == 2:
                self._sound.play_key_add()
                self._state = int(not self._state)
                self.change()
                updated = True
                self.active = not self.active

            # Click on switch; don't consider the mouse wheel (button 4 & 5)
            elif event.type == pygame.MOUSEBUTTONUP and self._mouse_enabled and event.button in (1, 2, 3) or \
                    event.type == FINGERUP and self._touchscreen_enabled and self._menu is not None:
                event_pos = get_finger_pos(self._menu, event)

                # If collides
                rect = self.get_rect(to_real_position=True,
                                     apply_padding=False)
                if rect.collidepoint(*event_pos):
                    # Check if mouse collides left or right as percentage, use only X coordinate
                    mouse_x, _ = event.pos
                    topleft, _ = rect.topleft
                    topright, _ = rect.topright
                    dist = mouse_x - (
                        topleft + self._switch_margin[0] + self._switch_pos[0]
                    )  # Distance from title
                    if dist > 0:  # User clicked the options, not title
                        target_index = 0
                        best = 1e6
                        # Find the closest position
                        for i in range(self._total_states):
                            dx = abs(self._state_width_accum[i] - dist)
                            if dx < best:
                                target_index = i
                                best = dx
                        if target_index != self._state:
                            self._sound.play_key_add()
                            self._state = target_index
                            self.change()
                            updated = True

        return updated
Example #7
0
    def update(
        self, events: Union[List['pygame.event.Event'],
                            Tuple['pygame.event.Event']]
    ) -> bool:
        if self.readonly:
            return False
        updated = False

        for event in events:

            if event.type == pygame.KEYDOWN:  # Check key is valid
                if not check_key_pressed_valid(event):
                    continue

            # Events
            keydown = self._keyboard_enabled and event.type == pygame.KEYDOWN
            joy_hatmotion = self._joystick_enabled and event.type == pygame.JOYHATMOTION
            joy_axismotion = self._joystick_enabled and event.type == pygame.JOYAXISMOTION

            # Left button
            if keydown and event.key == _controls.KEY_LEFT or \
                    joy_hatmotion and event.value == _controls.JOY_LEFT or \
                    joy_axismotion and event.axis == _controls.JOY_AXIS_X and event.value < _controls.JOY_DEADZONE:
                self._sound.play_key_add()
                self._left()
                updated = True

            # Right button
            elif keydown and event.key == _controls.KEY_RIGHT or \
                    joy_hatmotion and event.value == _controls.JOY_RIGHT or \
                    joy_axismotion and event.axis == _controls.JOY_AXIS_X and event.value > -_controls.JOY_DEADZONE:
                self._sound.play_key_add()
                self._right()
                updated = True

            # Press enter
            elif keydown and event.key == _controls.KEY_APPLY and self._total_states == 2:
                self._sound.play_key_add()
                self._state = int(not self._state)
                self.change()
                updated = True
                self.active = not self.active

            # Click on switch
            elif self._mouse_enabled and event.type == pygame.MOUSEBUTTONUP and event.button in (1, 2, 3) or \
                    self._touchscreen_enabled and event.type == pygame.FINGERUP:  # Don't consider the mouse wheel (button 4 & 5)

                # Get event position based on input type
                if self._touchscreen_enabled and event.type == pygame.FINGERUP:
                    window_size = self.get_menu().get_window_size()
                    event_pos = (event.x * window_size[0],
                                 event.y * window_size[1])
                else:
                    event_pos = event.pos

                # If collides
                rect = self.get_rect()
                if rect.collidepoint(*event_pos):
                    # Check if mouse collides left or right as percentage, use only X coordinate
                    mousex, _ = event.pos
                    topleft, _ = rect.topleft
                    topright, _ = rect.topright
                    dist = mousex - (
                        topleft + self._switch_margin[0] + self._switch_pos[0]
                    )  # Distance from title
                    if dist > 0:  # User clicked the options, not title
                        target_index = 0
                        best = 1e6
                        # Find the closest position
                        for i in range(self._total_states):
                            dx = abs(self._state_width_accum[i] - dist)
                            if dx < best:
                                target_index = i
                                best = dx
                        if target_index != self._state:
                            self._sound.play_key_add()
                            self._state = target_index
                            self.change()

        if updated:
            self.apply_update_callbacks()

        return updated
Example #8
0
    def update(self, events: EventVectorType) -> bool:
        self.apply_update_callbacks(events)

        if self.readonly or not self.is_visible():
            self._readonly_check_mouseover(events)
            return False

        for event in events:

            if event.type == pygame.KEYDOWN:  # Check key is valid
                if self._ignores_keyboard_nonphysical(
                ) and not check_key_pressed_valid(event):
                    continue

            # Check mouse over
            self._check_mouseover(event)

            # Events
            keydown = self._keyboard_enabled and event.type == pygame.KEYDOWN
            joy_hatmotion = self._joystick_enabled and event.type == pygame.JOYHATMOTION
            joy_axismotion = self._joystick_enabled and event.type == pygame.JOYAXISMOTION

            # Left button
            if keydown and self._ctrl.left(event, self) or \
                    joy_hatmotion and self._ctrl.joy_left(event, self) or \
                    joy_axismotion and self._ctrl.joy_axis_x_left(event, self):
                self._left()
                return True

            # Right button
            elif keydown and self._ctrl.right(event, self) or \
                    joy_hatmotion and self._ctrl.joy_right(event, self) or \
                    joy_axismotion and self._ctrl.joy_axis_x_right(event, self):
                self._right()
                return True

            # Press enter
            elif keydown and self._ctrl.apply(event, self) and self._total_states == 2 or \
                    event.type == pygame.JOYBUTTONDOWN and self._joystick_enabled and \
                    self._ctrl.joy_select(event, self) and self._total_states == 2:
                self._sound.play_key_add()
                self._state = int(not self._state)
                self.change()
                self.active = not self.active
                return True

            # Click on switch; don't consider the mouse wheel (button 4 & 5)
            elif event.type == pygame.MOUSEBUTTONUP and self._mouse_enabled and \
                    event.button in (1, 2, 3) or \
                    event.type == FINGERUP and self._touchscreen_enabled and \
                    self._menu is not None:
                event_pos = get_finger_pos(self._menu, event)

                # If collides
                rect = self.get_rect(to_real_position=True,
                                     apply_padding=False)
                if rect.collidepoint(*event_pos):
                    # Check if mouse collides left or right as percentage, use
                    # only X coordinate
                    mouse_x, _ = event_pos
                    topleft, _ = rect.topleft
                    topright, _ = rect.topright
                    # Distance from title
                    dist = mouse_x - (topleft + self._switch_margin[0] +
                                      self._switch_pos[0])

                    if dist > 0:  # User clicked the options, not title
                        # Toggle with only 1 click
                        if self._single_click:
                            if self._single_click_dir:
                                self._left()
                            else:
                                self._right()
                            return True

                        else:
                            target_index = 0
                            best = 1e6
                            # Find the closest position
                            for i in range(self._total_states):
                                dx = abs(self._state_width_accum[i] - dist)
                                if dx < best:
                                    target_index = i
                                    best = dx
                            if target_index != self._state:
                                self._sound.play_key_add()
                                self._state = target_index
                                self.change()
                                return True

        return False