Ejemplo n.º 1
0
    def __init__(self, file_name, conf):

        self.file_name = file_name
        self.map = self.load(file_name)

        self.config = conf  # type: Config

        self.screen = self.get_screen()  # type: pygame.SurfaceType
        self.clock = pygame.time.Clock()
        self.dirty_rects = []

        self._offset = self.get_default_offset()
        self.start_drag_pos = None  # type: Pos
        self.start_drag_offset = None  # type: Pos
        self.left_bar_pos = 42.1  # placeholder

        self.cursor = Pos(0, 0)
        self.overtype = True

        self.exit = False

        repeat_every(10)(self.save)

        # Log if the FPS drops
        @repeat_every(1, start_offset=1)
        def get_fps():
            fps = self.clock.get_fps()
            if fps < self.FPS / 2:
                logging.warning('Low fps: %s', fps)

        self.reset_screen()
Ejemplo n.º 2
0
    def update_left_bar(self):
        """Check if the left bar has changed and if so, draw it agin on next render."""
        pos = self.map_to_screen_pos(Pos(self.map.col_min, 0))[0] - 1

        if self.left_bar_pos != pos:
            rect = self.get_left_bar_rect()
            self.dirty_rects.append(rect)
            rect = rect.copy()
            rect.x = pos
            self.dirty_rects.append(rect)
            self.left_bar_pos = rect.x
Ejemplo n.º 3
0
    def render(self):

        # clear the dirt
        for rect in self.dirty_rects:
            self.screen.fill(COLORS.BACKGROUND, rect)

        # render what we need

        cursor_rendered = False
        # use a copy because the list can grow and we don't care about the new rects
        dirty_rects = self.dirty_rects[:]
        for pos, char in self.map:
            for dirt_rect in dirty_rects:

                pos = Pos(pos)
                rect = self.map_to_screen_rect(pos)

                # if we need to rerender this part of the screen
                if rect.colliderect(dirt_rect):

                    bg = COLORS.BACKGROUND
                    color = COLORS.TEXT
                    if pos == self.cursor and self.overtype:
                        bg, color = color, bg
                        cursor_rendered = True

                    surf = MAINFONT.render_char(char, color, bg)
                    self.screen.blit(surf, rect)

                    # try to minimize the overlappings would be nice
                    if not dirt_rect.contains(rect):
                        self.dirty_rects.append(rect)
                    break

        cursor_rect = self.map_to_screen_rect(self.cursor)
        if not cursor_rendered and self.has_dirt(cursor_rect):
            if self.overtype:
                char = self.map[self.cursor.row, self.cursor.col]

                surf = MAINFONT.render_char(char, COLORS.BACKGROUND,
                                            COLORS.TEXT)
                self.screen.blit(surf, cursor_rect)
            else:
                rect = self.map_to_screen_rect(self.cursor)
                rect.width = 2
                self.screen.fill(COLORS.TEXT, rect)

            self.dirty_rects.append(cursor_rect)

        left_bar_rect = self.get_left_bar_rect()
        if self.has_dirt(left_bar_rect):
            self.screen.fill(COLORS.TEXT, left_bar_rect)
            self.dirty_rects.append(left_bar_rect)
Ejemplo n.º 4
0
    def set_size(self, new_size):
        """Chage the size of the font but keep it between 80 and 2."""
        # clamp the size
        self.font_size = min(80, max(2, round(new_size)))

        # clear all caches
        self.render_char.cache_clear()
        self.render_text.cache_clear()
        for dep in self._dependant_caches:
            dep.cache_clear()

        font = pygame.font.Font(self.font_name, self.font_size)
        self.char_size = Pos(font.size("."))
        self.font = font
        return font
Ejemplo n.º 5
0
    def set_cursor(self, x, y):
        self.dirty_rects.append(self.map_to_screen_rect(self.cursor))
        self.cursor = Pos(x, y)
        new_rect = pygame.Rect(self.map_to_screen_rect(self.cursor))
        self.dirty_rects.append(new_rect)

        screen_rect = self.screen.get_rect()  # type: pygame.rect.RectType
        if new_rect.x < 0:
            # the modulo part it to keep the grid aligned with what it was before,
            # just changing by a mutliple of charsize
            self.offset -= new_rect.x - new_rect.x % MAINFONT.char_size.x, 0
        elif new_rect.right > screen_rect.right:
            # don't ask why it works
            self.offset += (
                (screen_rect.right - new_rect.left) // MAINFONT.char_size.x -
                1) * MAINFONT.char_size.x, 0

        if new_rect.y < 0:
            self.offset -= 0, new_rect.y - new_rect.y % MAINFONT.char_size.y
        elif new_rect.bottom > screen_rect.bottom:
            self.offset += 0, (
                (screen_rect.bottom - new_rect.top) // MAINFONT.char_size.y -
                1) * MAINFONT.char_size.y
Ejemplo n.º 6
0
 def get_mouse_pos(self):
     x, y = pygame.mouse.get_pos()
     if self.config.retina:
         x *= 2
         y *= 2
     return Pos(x, y)
Ejemplo n.º 7
0
 def get_default_offset(self):
     return Pos(250, 15)
Ejemplo n.º 8
0
 def map_cursor(self):
     """Get the position of the cursor in the map ((row, col) instead of (x, y))."""
     return Pos(self.cursor.row, self.cursor.col)
Ejemplo n.º 9
0
    def update(self):

        mouse = self.get_mouse_pos()

        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                return self.quit()

            elif e.type == pygame.KEYDOWN:
                if e.key == pygame.K_ESCAPE:
                    return self.quit()
                elif e.key == pygame.K_RIGHT:
                    self.move_cursor(1, 0)
                elif e.key == pygame.K_LEFT:
                    self.move_cursor(-1, 0)
                elif e.key == pygame.K_UP:
                    self.move_cursor(0, -1)
                elif e.key == pygame.K_DOWN:
                    self.move_cursor(0, 1)
                elif e.key == pygame.K_RETURN:
                    self.map.insert(self.map_cursor, '\n')
                    self.set_cursor(self.map.col_min, self.cursor.row + 1)
                    self.reset_screen()
                elif e.key == pygame.K_BACKSPACE:
                    self.move_cursor(-1, 0)
                    self.map.suppr((self.cursor.row, self.cursor.col))
                    self.reset_screen()
                elif e.key == pygame.K_DELETE:
                    self.map.suppr((self.cursor.row, self.cursor.col))
                    self.reset_screen()
                elif e.key == pygame.K_INSERT:
                    self.overtype = not self.overtype
                    self.dirty_rects.append(
                        self.map_to_screen_rect(self.cursor))
                elif e.key == pygame.K_F5:
                    self.launch_debugger()
                elif e.mod & pygame.KMOD_CTRL:
                    if e.key == pygame.K_r:  # reset position and size
                        self.offset = self.get_default_offset()
                        self.start_drag_pos = None
                        self.start_drag_offset = None
                        self.cursor = Pos(0, 0)
                        self.set_font_size(DEFAULT_FONT_SIZE)
                    elif e.key == pygame.K_EQUALS:  # I would like the + but apparently it doesn't work
                        self.change_font_size(1)
                    elif e.key == pygame.K_MINUS:
                        self.change_font_size(-1)
                    elif e.key == pygame.K_s:
                        self.save()
                else:
                    s = e.unicode  # type: str
                    if s and s.isprintable():
                        if self.overtype:
                            self.map[self.cursor.row, self.cursor.col] = s
                            # no need to update more than where the cursor was and it's done by move.cursor
                        else:
                            self.map.insert(self.map_cursor, s)
                            self.reset_screen()

                        self.move_cursor(1, 0)
                        self.update_left_bar()

            elif e.type == pygame.MOUSEBUTTONDOWN:
                if e.button == 1:
                    self.set_cursor(
                        *self.screen_to_map_pos(self.get_mouse_pos()))
                elif e.button == 3:
                    self.start_drag_pos = mouse
                    self.start_drag_offset = self.offset
                    self.reset_screen()
            elif e.type == pygame.MOUSEBUTTONUP:
                if e.button == 3:
                    self.start_drag_pos = None
                    self.start_drag_offset = None
                    self.reset_screen()

        # drag the code if needed
        if self.start_drag_pos is not None:
            actual_pos = mouse
            dx, dy = actual_pos - self.start_drag_pos

            if abs(dx) < 20:
                dx = 0
            if abs(dy) < 20:
                dy = 0

            self.offset = self.start_drag_offset + (dx, dy)