class Button(MouseListener): def __init__(self, text, position, dimensions): self._hovered = False self._mouse_downed = False self._label = Label(position, dimensions, text, font_size=dimensions[1], padding=(constants.BUTTON_TEXT_PADDING, constants.BUTTON_TEXT_PADDING)) self._hit_box = Rect(position, dimensions) self._position = position self._dimensions = dimensions super().__init__() def handle_mouse_motion(self, coords): self._hovered = self._hit_box.collidepoint(coords) def handle_mouse_button_up(self, coords): clicked = False if self._hovered and self._mouse_downed: clicked = True self._mouse_downed = False self._hovered = False return clicked def handle_mouse_button_down(self, coords): if self._hovered: self._mouse_downed = True def draw(self, screen): if self._hovered: border = constants.GREY background = constants.WHITE else: border = constants.WHITE background = constants.GREY screen.fill(border, self._hit_box) screen.fill( background, self._hit_box.inflate(-constants.BUTTON_BORDER_WEIGHT, -constants.BUTTON_BORDER_WEIGHT)) self._label.draw(screen)
def draw_rect(surface, color, rect, image, radius=0.4): """ surface : destination rect : rectangle color : rgb or rgba radius : 0 <= radius <= 1 """ rect = Rect(rect) color = Color(*color) alpha = color.a color.a = 0 pos = rect.topleft rect.topleft = 0, 0 rectangle = Surface(rect.size, SRCALPHA) circle = Surface([min(rect.size) * 3] * 2, SRCALPHA) draw.ellipse(circle, (0, 0, 0), circle.get_rect(), 0) circle = transform.smoothscale(circle, [int(min(rect.size) * radius)] * 2) radius = rectangle.blit(circle, (0, 0)) radius.bottomright = rect.bottomright rectangle.blit(circle, radius) radius.topright = rect.topright rectangle.blit(circle, radius) radius.bottomleft = rect.bottomleft rectangle.blit(circle, radius) rectangle.fill((0, 0, 0), rect.inflate(-radius.w, 0)) rectangle.fill((0, 0, 0), rect.inflate(0, -radius.h)) rectangle.fill(color, special_flags=BLEND_RGBA_MAX) rectangle.fill((255, 255, 255, alpha), special_flags=BLEND_RGBA_MIN) rectangle.blit(image, rect) return surface.blit(rectangle, pos)
class _TextBox(_Component): def __init__(self, font: Font, size: Vec2, text: str, border_color: Vec3, text_color: Vec3, sound_player: SoundPlayer): super().__init__(Surface(size)) self.surface.set_alpha(180) self._container_rect = Rect((0, 0), size) pad = 30 self._text_area = self._container_rect.inflate(-pad, -pad) self._font = font self._border_color = border_color self._text_color = text_color self._sound_player = sound_player self._lines = self._split_into_lines(text) self._cursor = 0 self._max_cursor_position = max(0, len(text) - 1) self._periodic_cursor_advance = PeriodicAction(Millis(40), self._advance_cursor) self._redraw() def _advance_cursor(self): if self._cursor < self._max_cursor_position: self._sound_player.play_text_blip() self._cursor += 1 self._redraw() def update(self, elapsed_time: Millis): self._periodic_cursor_advance.update(elapsed_time) def set_cursor_to_end(self): self._cursor = self._max_cursor_position self._redraw() def is_cursor_at_end(self) -> bool: return self._cursor == self._max_cursor_position def _split_into_lines(self, text) -> List[str]: return list( layout_text_in_area(text, lambda t: self._font.size(t)[0], self._text_area.width)) def _redraw(self): self.surface.fill(BLACK) pygame.draw.rect(self.surface, self._border_color, self._container_rect, width=1, border_radius=2) x, y = self._text_area.topleft num_chars_rendered = 0 for line in self._lines: remaining = self._cursor + 1 - num_chars_rendered if remaining <= 0: return part_of_line = line[:remaining] rendered_line = self._font.render(part_of_line, True, self._text_color) self.surface.blit(rendered_line, (x, y)) y += rendered_line.get_height() num_chars_rendered += len(part_of_line)
def are_rooms_too_close(room1: Rect, room2: Rect): return room1.inflate(2, 2).colliderect(room2.inflate(2, 2))