Esempio n. 1
0
    def test_list(self):
        title = to_formatted_text("Title", style="bg:red")
        elements = [
            ListElement("One", on_select=lambda: print("Select")),
            ListElement("Two"),
            ListElement("Three", on_focus=lambda: print("Focus")),
        ]

        list = List(
            title=title,
            elements=elements,
        )

        assert list.title_window.text == "Title"

        expected = dedent("""
            One
            Two
            Three
            """).strip()
        assert to_text(list.list_window) == expected

        list.next()
        assert list.current_element.text == "Two"
        assert to_text(list.list_window) == expected

        list.previous()
        assert list.current_element.text == "One"
        assert to_text(list.list_window) == expected

        list.focus(2)
        assert list.current_element.text == "Three"
        assert to_text(list.list_window) == expected

        list.select(0)
        assert list.current_element.text == "One"
        assert to_text(list.list_window) == expected

        list.select(1)
        assert list.current_element.text == "Two"
        assert to_text(list.list_window) == expected

        mouse_event = MouseEvent(Point(0, 0), MouseEventType.MOUSE_DOWN)
        list.mouse_select(index=0, mouse_event=mouse_event)
        assert list.current_element.text == "Two"
        assert to_text(list.list_window) == expected

        mouse_event.event_type = MouseEventType.MOUSE_UP
        list.mouse_select(index=0, mouse_event=mouse_event)
        assert list.current_element.text == "One"
        assert to_text(list.list_window) == expected
Esempio n. 2
0
    def _mouse(event: E) -> None:
        """
        Handling of mouse events for Windows.
        """
        assert is_windows()  # This key binding should only exist for Windows.

        # Parse data.
        pieces = event.data.split(";")

        event_type = MouseEventType(pieces[0])
        x = int(pieces[1])
        y = int(pieces[2])

        # Make coordinates absolute to the visible part of the terminal.
        output = event.app.renderer.output

        from prompt_toolkit.output.win32 import Win32Output

        if isinstance(output, Win32Output):
            screen_buffer_info = output.get_win32_screen_buffer_info()
            rows_above_cursor = (
                screen_buffer_info.dwCursorPosition.Y - event.app.renderer._cursor_pos.y
            )
            y -= rows_above_cursor

            # Call the mouse event handler.
            handler = event.app.renderer.mouse_handlers.mouse_handlers[x, y]
            handler(MouseEvent(position=Point(x=x, y=y), event_type=event_type))
Esempio n. 3
0
 def test_no_mouse_handler(self):
     mouse_event = MouseEvent(Point(0, 0), MouseEventType.MOUSE_UP)
     handler = mock.MagicMock()
     formatted_text = to_formatted_text([("", "hello"),
                                         ("", "world", lambda x: handler(x))
                                         ])
     text_area = FormattedTextArea(formatted_text)
     text_area.control.mouse_handler(mouse_event)
     handler.assert_not_called()
 def new_handler(event: MouseEvent) -> None:
     new_event = MouseEvent(
         position=Point(
             x=event.position.x - xpos,
             y=event.position.y + self.vertical_scroll - ypos,
         ),
         event_type=event.event_type,
     )
     handler(new_event)
Esempio n. 5
0
        def mouse_handler(cli, mouse_event):
            """ Wrapper around the mouse_handler of the `UIControl` that turns
            absolute coordinates into relative coordinates. """
            position = mouse_event.position

            # Call the mouse handler of the UIControl first.
            self._mouse_handler(
                cli,
                MouseEvent(position=Point(x=position.x - write_position.xpos,
                                          y=position.y - write_position.ypos +
                                          vertical_scroll),
                           event_type=mouse_event.event_type))
Esempio n. 6
0
    def test_mouse_handler(self):
        handler = mock.MagicMock()
        handler_two = mock.MagicMock()
        mouse_event = MouseEvent(Point(0, 0), MouseEventType.MOUSE_UP)
        formatted_text = to_formatted_text([
            ("", "hello", lambda x: handler(x)),
            ("", "world", lambda x: handler_two(x)),
        ])
        text_area = FormattedTextArea(formatted_text)

        # Click on first character.
        text_area.control.mouse_handler(mouse_event)
        handler.assert_called_once()
        handler_two.assert_not_called()

        # Click outside the text area.
        mouse_event = MouseEvent(Point(99, 99), MouseEventType.MOUSE_UP)
        handler.reset_mock()
        handler_two.reset_mock()
        text_area.control.mouse_handler(mouse_event)
        handler.assert_not_called()
        handler_two.assert_not_called()
Esempio n. 7
0
    def test_test_block_edit_action_none(self, click_edit):
        toc = self.chapters[1].toc()
        section = toc[1][0]
        renderer = Renderer(tui=self.tui, section=section, width=37)
        renderer.render()
        text = "He's the creator of something..."
        node = section.children[1]
        assert node.tagname == "TestBlock"
        assert node.text() == text

        click_edit.return_value = None

        mouse_event = MouseEvent(Point(0, 0), MouseEventType.MOUSE_UP)
        renderer._edit_action(node, mouse_event)
        click_edit.assert_called_once_with(
            text=text,
            extension=".txt",
        )
        assert node.text() == text
Esempio n. 8
0
    def _(event: E) -> None:
        """
        Handling of mouse events for Windows.
        """
        assert is_windows()  # This key binding should only exist for Windows.

        # Parse data.
        event_type, x, y = event.data.split(';')
        x = int(x)
        y = int(y)

        # Make coordinates absolute to the visible part of the terminal.
        screen_buffer_info = event.app.renderer.output.get_win32_screen_buffer_info()
        rows_above_cursor = screen_buffer_info.dwCursorPosition.Y - event.app.renderer._cursor_pos.y
        y -= rows_above_cursor

        # Call the mouse event handler.
        handler = event.app.renderer.mouse_handlers.mouse_handlers[x, y]
        handler(MouseEvent(position=Point(x=x, y=y), event_type=event_type))
Esempio n. 9
0
        def mouse_handler(cli, mouse_event):
            """ Wrapper around the mouse_handler of the `UIControl` that turns
            absolute coordinates into relative coordinates. """
            position = mouse_event.position

            # Call the mouse handler of the UIControl first.
            result = self.content.mouse_handler(
                cli,
                MouseEvent(position=Point(x=position.x - write_position.xpos -
                                          sum(left_margin_widths),
                                          y=position.y - write_position.ypos +
                                          self.vertical_scroll),
                           event_type=mouse_event.event_type))

            # If it returns NotImplemented, handle it here.
            if result == NotImplemented:
                return self._mouse_handler(cli, mouse_event)

            return result
Esempio n. 10
0
    def _mouse(event: E) -> "NotImplementedOrNone":
        """
        Handling of mouse events for Windows.
        """
        # This key binding should only exist for Windows.
        if sys.platform == "win32":
            # Parse data.
            pieces = event.data.split(";")

            button = MouseButton(pieces[0])
            event_type = MouseEventType(pieces[1])
            x = int(pieces[2])
            y = int(pieces[3])

            # Make coordinates absolute to the visible part of the terminal.
            output = event.app.renderer.output

            from prompt_toolkit.output.win32 import Win32Output
            from prompt_toolkit.output.windows10 import Windows10_Output

            if isinstance(output, (Win32Output, Windows10_Output)):
                screen_buffer_info = output.get_win32_screen_buffer_info()
                rows_above_cursor = (screen_buffer_info.dwCursorPosition.Y -
                                     event.app.renderer._cursor_pos.y)
                y -= rows_above_cursor

                # Call the mouse event handler.
                # (Can return `NotImplemented`.)
                handler = event.app.renderer.mouse_handlers.mouse_handlers[y][
                    x]

                return handler(
                    MouseEvent(
                        position=Point(x=x, y=y),
                        event_type=event_type,
                        button=button,
                        modifiers=UNKNOWN_MODIFIER,
                    ))

        # No mouse handler found. Return `NotImplemented` so that we don't
        # invalidate the UI.
        return NotImplemented
Esempio n. 11
0
    def _(event):
        """
        Handling of incoming mouse event.
        """
        # Typical:   "Esc[MaB*"
        # Urxvt:     "Esc[96;14;13M"
        # Xterm SGR: "Esc[<64;85;12M"

        # Parse incoming packet.
        if event.data[2] == 'M':
            # Typical.
            mouse_event, x, y = map(ord, event.data[3:])
            mouse_event = {
                32: MouseEventType.MOUSE_DOWN,
                35: MouseEventType.MOUSE_UP,
                96: MouseEventType.SCROLL_UP,
                97: MouseEventType.SCROLL_DOWN,
            }.get(mouse_event)

            # Handle situations where `PosixStdinReader` used surrogateescapes.
            if x >= 0xdc00: x-= 0xdc00
            if y >= 0xdc00: y-= 0xdc00

            x -= 32
            y -= 32
        else:
            # Urxvt and Xterm SGR.
            # When the '<' is not present, we are not using the Xterm SGR mode,
            # but Urxvt instead.
            data = event.data[2:]
            if data[:1] == '<':
                sgr = True
                data = data[1:]
            else:
                sgr = False

            # Extract coordinates.
            mouse_event, x, y = map(int, data[:-1].split(';'))
            m = data[-1]

            # Parse event type.
            if sgr:
                mouse_event = {
                    (0, 'M'): MouseEventType.MOUSE_DOWN,
                    (0, 'm'): MouseEventType.MOUSE_UP,
                    (64, 'M'): MouseEventType.SCROLL_UP,
                    (65, 'M'): MouseEventType.SCROLL_DOWN,
                }.get((mouse_event, m))
            else:
                mouse_event = {
                    32: MouseEventType.MOUSE_DOWN,
                    35: MouseEventType.MOUSE_UP,
                    96: MouseEventType.SCROLL_UP,
                    97: MouseEventType.SCROLL_DOWN,
                    }.get(mouse_event)

        x -= 1
        y -= 1

        # Only handle mouse events when we know the window height.
        if event.cli.renderer.height_is_known and mouse_event is not None:
            # Take region above the layout into account. The reported
            # coordinates are absolute to the visible part of the terminal.
            try:
                y -= event.cli.renderer.rows_above_layout
            except HeightIsUnknownError:
                return

            # Call the mouse handler from the renderer.
            handler = event.cli.renderer.mouse_handlers.mouse_handlers[x,y]
            handler(event.cli, MouseEvent(position=Point(x=x, y=y),
                                          event_type=mouse_event))
Esempio n. 12
0
    def _(event: E) -> "NotImplementedOrNone":
        """
        Handling of incoming mouse event.
        """
        # TypicaL:   "eSC[MaB*"
        # Urxvt:     "Esc[96;14;13M"
        # Xterm SGR: "Esc[<64;85;12M"

        # Parse incoming packet.
        if event.data[2] == "M":
            # Typical.
            mouse_event, x, y = map(ord, event.data[3:])

            # TODO: Is it possible to add modifiers here?
            mouse_button, mouse_event_type, mouse_modifiers = typical_mouse_events[
                mouse_event]

            # Handle situations where `PosixStdinReader` used surrogateescapes.
            if x >= 0xDC00:
                x -= 0xDC00
            if y >= 0xDC00:
                y -= 0xDC00

            x -= 32
            y -= 32
        else:
            # Urxvt and Xterm SGR.
            # When the '<' is not present, we are not using the Xterm SGR mode,
            # but Urxvt instead.
            data = event.data[2:]
            if data[:1] == "<":
                sgr = True
                data = data[1:]
            else:
                sgr = False

            # Extract coordinates.
            mouse_event, x, y = map(int, data[:-1].split(";"))
            m = data[-1]

            # Parse event type.
            if sgr:
                try:
                    (
                        mouse_button,
                        mouse_event_type,
                        mouse_modifiers,
                    ) = xterm_sgr_mouse_events[mouse_event, m]
                except KeyError:
                    return NotImplemented

            else:
                # Some other terminals, like urxvt, Hyper terminal, ...
                (
                    mouse_button,
                    mouse_event_type,
                    mouse_modifiers,
                ) = urxvt_mouse_events.get(
                    mouse_event,
                    (UNKNOWN_BUTTON, MOUSE_MOVE, UNKNOWN_MODIFIER))

        x -= 1
        y -= 1

        # Only handle mouse events when we know the window height.
        if event.app.renderer.height_is_known and mouse_event_type is not None:
            # Take region above the layout into account. The reported
            # coordinates are absolute to the visible part of the terminal.
            from prompt_toolkit.renderer import HeightIsUnknownError

            try:
                y -= event.app.renderer.rows_above_layout
            except HeightIsUnknownError:
                return NotImplemented

            # Call the mouse handler from the renderer.

            # Note: This can return `NotImplemented` if no mouse handler was
            #       found for this position, or if no repainting needs to
            #       happen. this way, we avoid excessive repaints during mouse
            #       movements.
            handler = event.app.renderer.mouse_handlers.mouse_handlers[y][x]
            return handler(
                MouseEvent(
                    position=Point(x=x, y=y),
                    event_type=mouse_event_type,
                    button=mouse_button,
                    modifiers=mouse_modifiers,
                ))

        return NotImplemented
Esempio n. 13
0
    def _(event: E) -> None:
        """
        Handling of incoming mouse event.
        """
        # TypicaL:   "eSC[MaB*"
        # Urxvt:     "Esc[96;14;13M"
        # Xterm SGR: "Esc[<64;85;12M"

        # Parse incoming packet.
        if event.data[2] == "M":
            # Typical.
            mouse_event, x, y = map(ord, event.data[3:])

            # TODO: Is it possible to add modifiers here?
            mouse_button, mouse_event_type, mouse_modifier = typical_mouse_events[
                mouse_event]

            # Handle situations where `PosixStdinReader` used surrogateescapes.
            if x >= 0xDC00:
                x -= 0xDC00
            if y >= 0xDC00:
                y -= 0xDC00

            x -= 32
            y -= 32
        else:
            # Urxvt and Xterm SGR.
            # When the '<' is not present, we are not using the Xterm SGR mode,
            # but Urxvt instead.
            data = event.data[2:]
            if data[:1] == "<":
                sgr = True
                data = data[1:]
            else:
                sgr = False

            # Extract coordinates.
            mouse_event, x, y = map(int, data[:-1].split(";"))
            m = data[-1]

            # Parse event type.
            if sgr:
                mouse_button, mouse_event_type, mouse_modifier = xterm_sgr_mouse_events[
                    mouse_event, m]
            else:
                # TODO: I don't know when this is triggered or how this mode works (though my Hyper terminal seems to use it), so I marked the buttons and modifiers UNKNOWN.
                # By replacing these UNKNOWN values with the correct values in urxvt_mouse_events, we can get more functionality in different terminal varieties
                mouse_button, mouse_event_type, mouse_modifier = urxvt_mouse_events.get(
                    mouse_event,
                    (UNKNOWN_BUTTON, MOUSE_MOVE, UNKNOWN_MODIFIER))

        x -= 1
        y -= 1

        # Only handle mouse events when we know the window height.
        if event.app.renderer.height_is_known and mouse_event_type is not None:
            # Take region above the layout into account. The reported
            # coordinates are absolute to the visible part of the terminal.
            from prompt_toolkit.renderer import HeightIsUnknownError

            try:
                y -= event.app.renderer.rows_above_layout
            except HeightIsUnknownError:
                return

            # Call the mouse handler from the renderer.
            handler = event.app.renderer.mouse_handlers.mouse_handlers[y][x]
            handler(
                MouseEvent(
                    position=Point(x=x, y=y),
                    event_type=mouse_event_type,
                    button=mouse_button,
                    modifier=mouse_modifier,
                ))