Example #1
0
    def render(self, width, height) -> Screen:
        render_screen = Screen(width, height)
        self._render_headers(render_screen)

        for index, row in enumerate(self.rows):
            self._render_row(row, index + 2, render_screen)
        return render_screen
Example #2
0
    def get_rendered_screen(self, width, height):
        screen = Screen(width, height)
        screen_width = screen.width
        column_widths = self.get_column_widths(screen_width)
        column_headers = self.get_column_headers()
        header_line = ""
        under_line = ""
        for width, header in zip(column_widths, column_headers):
            header_line += header.center(width - 1)[: width - 1] + Border.NORMAL[Border.VERTICAL]
            under_line += Border.NORMAL[Border.HORIZONTAL] * (width - 1) + Border.NORMAL[Border.INTERSECTION]
        screen.draw((0, 0), header_line)
        screen.draw((0, 1), under_line)

        for row_index in range(height):
            line = ""
            for column_index, column_width in enumerate(column_widths):
                line += (
                    " "
                    + self.columns[column_index].formatData(self.get_cell(column_index, row_index), column_width)
                    + Border.NORMAL[Border.VERTICAL]
                )
            line = line
            screen.draw(Point(0, row_index + 2), line)
        return screen
Example #3
0
    def render(self, width, height) -> Screen:
        render_screen = Screen(width, height)
        scroll_threshold = int(height / 2)

        sub_contents = self.contents
        if self.pointer < height - scroll_threshold:
            sub_contents = self.contents[:height]
        elif self.pointer > len(self.contents) - scroll_threshold:
            sub_contents = self.contents[-height:]
        else:
            sub_contents = self.contents[self.pointer - height + scroll_threshold : self.pointer + scroll_threshold]

        for index, item in enumerate(sub_contents):
            render_screen = self._render_item(Point(0, index), item, render_screen)
        if sub_contents[0] != self.contents[0]:
            render_screen.draw((-1, 0), unicodedata.lookup("UPWARDS ARROW"))
        if sub_contents[-1] != self.contents[-1]:
            render_screen.draw((-1, -1), unicodedata.lookup("DOWNWARDS ARROW"))
        return render_screen
Example #4
0
class SilicaWindowManager:
    """
    Main object that handles window manager state.
    """

    DEFAULT_DELAY = 0.01  # Delay in seconds between full redraws

    def __init__(self):
        self._windows = {}
        self.viewport = Screen(0, 0)
        self._recalculate_screen_size()
        self.set_delay(self.DEFAULT_DELAY)

    def setup(self):
        """
        Explicitly prepare the terminal for drawing to. This will mess up
        the terminal for normal operations, and will need to be reversed on
        exit by calling cleanup()
        """
        self._curses_setup()

    def set_delay(self, new_delay):
        self.delay = new_delay  # seconds

    def _curses_setup(self):
        self.scr = curses.initscr()
        curses.start_color()
        curses.use_default_colors()
        for i in range(0, curses.COLORS):
            curses.init_pair(i + 1, i, -1)
        curses.noecho()
        curses.cbreak()
        curses.curs_set(0)
        self.scr.keypad(True)
        self.scr.scrollok(False)
        self.scr.nodelay(True)

    @staticmethod
    def cleanup():
        curses.echo()
        curses.nocbreak()
        curses.endwin()
        curses.curs_set(1)

    def _recalculate_screen_size(self):
        """
        Updates viewport size to be the current terminal size and recalculates all windows.
        """
        x, y = os.get_terminal_size()
        self.viewport.width = x
        self.viewport.height = y
        for window in self._windows.values():
            window._generate_screen()

    def add_window(self, screenspace_rect, identifier) -> Window:
        return self._add_window(
            ScreenspaceRect(*screenspace_rect, self.viewport), identifier)

    def add_centered_window(self, centered_rect, identifier):
        return self._add_window(CenteredRect(*centered_rect, self.viewport),
                                identifier)

    def _add_window(self, rect, identifier):
        if identifier in self._windows.keys():
            raise ValueError("A window with this identifier already exists")

        new_window = Window(rect)
        new_window.identifier = identifier

        z_index = 0
        for window in self._windows.values():
            z_index = max(window.z_index, z_index + 1)
        new_window.z_index = z_index

        self._windows[identifier] = new_window
        return new_window

    def get_window(self, identifier):
        try:
            return self._windows[identifier]
        except KeyError:
            raise KeyError("No window with this identifier exists")

    def get_keypress(self):
        return KeyPress(self.scr.getch())

    def process(self):
        self.draw_windows()
        self.render()
        self.scr.refresh()
        self._recalculate_screen_size()
        time.sleep(self.delay)

    def draw_windows(self):
        for window in sorted(self._windows.values(),
                             key=operator.attrgetter("z_index")):
            if not window.visible:
                continue
            rendered_window = window.render()
            self.viewport.draw(window.rect.origin, rendered_window)
            window.screen.clear()

    def safe_error(self, e):
        self.cleanup()
        raise e

    def render(self):
        for y_index, line in enumerate(self.viewport.as_list()):
            try:
                if y_index == self.viewport.size.height - 1:
                    self.scr.insnstr(y_index, self.viewport.size.width - 1,
                                     line[-1].character, 0)
                    line = line[:-1]
                for x_index, screencell in enumerate(line):
                    self.scr.addstr(y_index, x_index, screencell.character,
                                    screencell.attributes.to_curses())
            except curses.error as e:
                pass
Example #5
0
 def __init__(self):
     self._windows = {}
     self.viewport = Screen(0, 0)
     self._recalculate_screen_size()
     self.set_delay(self.DEFAULT_DELAY)
Example #6
0
class Window:
    def __init__(self, rect, z_index=0):
        self.visible = True
        self.title = ""
        self.rect = rect
        self._generate_screen()
        self.theme = Border.NORMAL
        self.identifier = None
        self.z_index = z_index

    @property
    def width(self):
        return self.rect.width

    @property
    def height(self):
        return self.rect.height

    def _generate_screen(self):
        self.screen = Screen(self.rect.width - 2, self.rect.height - 2)

    def draw(self, *args, **kwargs):
        self.screen.draw(*args, **kwargs)

    def render(self) -> Screen:
        render_screen = Screen(self.rect.width, self.rect.height)

        top_edge = (self.theme[Border.TOPLEFT] +
                    self.theme[Border.HORIZONTAL] * self.screen.width +
                    self.theme[Border.TOPRIGHT])

        if self.title != "":
            top_edge = (self.theme[Border.TOPLEFT] +
                        " {title} ".format(title=self.title).center(
                            self.screen.width, self.theme[Border.HORIZONTAL]) +
                        self.theme[Border.TOPRIGHT])

        bottom_edge = (self.theme[Border.BOTTOMLEFT] +
                       self.theme[Border.HORIZONTAL] * self.screen.width +
                       self.theme[Border.BOTTOMRIGHT])

        render_screen.draw((0, 0), top_edge)
        for y in range(self.screen.height):
            render_screen.draw((0, y + 1), self.theme[Border.VERTICAL])
            render_screen.draw(Point(self.screen.width + 1, y + 1),
                               self.theme[Border.VERTICAL])
        render_screen.draw((0, self.rect.height - 1), bottom_edge)
        render_screen.draw(Point(1, 1), self.screen)

        return render_screen

    def auto_title(self):
        try:
            self.title = str(self.identifier)
            return self
        except ValueError:
            raise TypeError("Window identifier must be a valid string")

    def set_title(self, new_title):
        self.title = new_title
        return self

    def set_theme(self, theme_name):
        self.theme = Border.get_theme(theme_name)
        return self
Example #7
0
    def render(self) -> Screen:
        render_screen = Screen(self.rect.width, self.rect.height)

        top_edge = (self.theme[Border.TOPLEFT] +
                    self.theme[Border.HORIZONTAL] * self.screen.width +
                    self.theme[Border.TOPRIGHT])

        if self.title != "":
            top_edge = (self.theme[Border.TOPLEFT] +
                        " {title} ".format(title=self.title).center(
                            self.screen.width, self.theme[Border.HORIZONTAL]) +
                        self.theme[Border.TOPRIGHT])

        bottom_edge = (self.theme[Border.BOTTOMLEFT] +
                       self.theme[Border.HORIZONTAL] * self.screen.width +
                       self.theme[Border.BOTTOMRIGHT])

        render_screen.draw((0, 0), top_edge)
        for y in range(self.screen.height):
            render_screen.draw((0, y + 1), self.theme[Border.VERTICAL])
            render_screen.draw(Point(self.screen.width + 1, y + 1),
                               self.theme[Border.VERTICAL])
        render_screen.draw((0, self.rect.height - 1), bottom_edge)
        render_screen.draw(Point(1, 1), self.screen)

        return render_screen
Example #8
0
 def _generate_screen(self):
     self.screen = Screen(self.rect.width - 2, self.rect.height - 2)