def _rebuild_shadow(self, new_image, text_render_rect): shadow_text_render = render_white_text_alpha_black_bg(self.font, self.text) apply_colour_to_surface(self.text_shadow_colour, shadow_text_render) for y_pos in range(-self.text_shadow_size, self.text_shadow_size + 1): shadow_text_rect = pygame.Rect((text_render_rect.x + self.text_shadow_offset[0], text_render_rect.y + self.text_shadow_offset[1] + y_pos), text_render_rect.size) basic_blit(new_image, shadow_text_render, shadow_text_rect) for x_pos in range(-self.text_shadow_size, self.text_shadow_size + 1): shadow_text_rect = pygame.Rect((text_render_rect.x + self.text_shadow_offset[0] + x_pos, text_render_rect.y + self.text_shadow_offset[1]), text_render_rect.size) basic_blit(new_image, shadow_text_render, shadow_text_rect) for x_and_y in range(-self.text_shadow_size, self.text_shadow_size + 1): shadow_text_rect = pygame.Rect( (text_render_rect.x + self.text_shadow_offset[0] + x_and_y, text_render_rect.y + self.text_shadow_offset[1] + x_and_y), text_render_rect.size) basic_blit(new_image, shadow_text_render, shadow_text_rect) for x_and_y in range(-self.text_shadow_size, self.text_shadow_size + 1): shadow_text_rect = pygame.Rect( (text_render_rect.x + self.text_shadow_offset[0] - x_and_y, text_render_rect.y + self.text_shadow_offset[1] + x_and_y), text_render_rect.size) basic_blit(new_image, shadow_text_render, shadow_text_rect)
def redraw(self): """ Renders the 'chunk' text to the 'rendered_chunk' surface. """ if self.style.underline or (self.is_hovered and self.link_hover_underline) or \ (self.link_normal_underline and not self.is_hovered): self.font.set_underline(True) if len(self.chunk) > 0: if isinstance(self.colour, ColourGradient): self.rendered_chunk = render_white_text_alpha_black_bg(self.font, self.chunk) self.colour.apply_gradient_to_surface(self.rendered_chunk) else: if isinstance(self.bg_colour, ColourGradient) or self.bg_colour.a != 255: self.rendered_chunk = render_white_text_alpha_black_bg(self.font, self.chunk) apply_colour_to_surface(self.colour, self.rendered_chunk) else: self.rendered_chunk = self.font.render(self.chunk, True, self.colour, self.bg_colour).convert_alpha() else: self.rendered_chunk = pygame.surface.Surface((0, 0), flags=pygame.SRCALPHA, depth=32) self.font.set_underline(False) new_metrics = self.font.metrics(self.chunk) new_ascent = self.font.get_ascent() new_width = self.font.size(self.chunk)[0] new_height = self.font.size(self.chunk)[1] new_advance = sum(new_metrics[i][4] for i in range(len(self.chunk)) if len(new_metrics[i]) == 5) if (new_ascent == self.ascent and new_width == self.width and new_height == self.height and new_advance == self.advance): self.metrics_changed_after_redraw = False else: self.metrics_changed_after_redraw = True self.ascent = new_ascent self.width = new_width self.height = new_height self.advance = new_advance self.rect = pygame.Rect(self.position, (self.width, self.height))
def _redraw_unselected_text(self): """ Redraw text where none has been selected by a user. """ self.text_surface = render_white_text_alpha_black_bg(font=self.font, text=self.text) if self.is_enabled: if isinstance(self.text_colour, ColourGradient): self.text_colour.apply_gradient_to_surface(self.text_surface) else: apply_colour_to_surface(self.text_colour, self.text_surface) else: if isinstance(self.disabled_text_colour, ColourGradient): self.disabled_text_colour.apply_gradient_to_surface( self.text_surface) else: apply_colour_to_surface(self.disabled_text_colour, self.text_surface)
def _draw_text_with_grad_or_col( self, text: str, col_or_grad: Union[ColourGradient, pygame.Color] ) -> pygame.surface.Surface: """ Draw text to a surface using either a colour or gradient. :param text: The text to render. :param col_or_grad: A colour or a colour gradient. :return: A surface with the text on. """ text_surface = render_white_text_alpha_black_bg(font=self.font, text=text) if isinstance(col_or_grad, ColourGradient): col_or_grad.apply_gradient_to_surface(text_surface) else: apply_colour_to_surface(col_or_grad, text_surface) return text_surface
def set_visual_debug_mode(self, activate_mode: bool): """ Enables a debug mode for the element which displays layer information on top of it in a tiny font. :param activate_mode: True or False to enable or disable the mode. """ if activate_mode: default_font = self.ui_manager.get_theme().get_font_dictionary( ).get_default_font() layer_text_render = render_white_text_alpha_black_bg( default_font, "UI Layer: " + str(self._layer)) if self.image is not None: self.pre_debug_image = self.image.copy() # check if our surface is big enough to hold the debug info, # if not make a new, bigger copy make_new_larger_surface = False surf_width = self.image.get_width() surf_height = self.image.get_height() if self.image.get_width() < layer_text_render.get_width(): make_new_larger_surface = True surf_width = layer_text_render.get_width() if self.image.get_height() < layer_text_render.get_height(): make_new_larger_surface = True surf_height = layer_text_render.get_height() if make_new_larger_surface: new_surface = pygame.surface.Surface( (surf_width, surf_height), flags=pygame.SRCALPHA, depth=32) basic_blit(new_surface, self.image, (0, 0)) self.set_image(new_surface) basic_blit(self.image, layer_text_render, (0, 0)) else: self.set_image(layer_text_render) self._visual_debug_mode = True else: self.rebuild() self._visual_debug_mode = False
def rebuild(self): """ Re-render the text to the label's underlying sprite image. This allows us to change what the displayed text is or remake it with different theming (if the theming has changed). """ text_size = self.font.size(self.text) if text_size[1] > self.relative_rect.height or text_size[0] > self.relative_rect.width: width_overlap = self.relative_rect.width - text_size[0] height_overlap = self.relative_rect.height - text_size[1] warn_text = ('Label Rect is too small for text: ' '' + self.text + ' - size diff: ' + str((width_overlap, height_overlap))) warnings.warn(warn_text, UserWarning) new_image = pygame.surface.Surface(self.relative_rect.size, flags=pygame.SRCALPHA, depth=32) if isinstance(self.bg_colour, ColourGradient): new_image.fill(pygame.Color('#FFFFFFFF')) self.bg_colour.apply_gradient_to_surface(new_image) text_render = render_white_text_alpha_black_bg(self.font, self.text) if self.is_enabled: if isinstance(self.text_colour, ColourGradient): self.text_colour.apply_gradient_to_surface(text_render) else: apply_colour_to_surface(self.text_colour, text_render) else: if isinstance(self.disabled_text_colour, ColourGradient): self.disabled_text_colour.apply_gradient_to_surface(text_render) else: apply_colour_to_surface(self.disabled_text_colour, text_render) else: new_image.fill(self.bg_colour) if self.is_enabled: if isinstance(self.text_colour, ColourGradient): text_render = render_white_text_alpha_black_bg(self.font, self.text) self.text_colour.apply_gradient_to_surface(text_render) else: if self.bg_colour.a != 255 or self.text_shadow: text_render = render_white_text_alpha_black_bg(self.font, self.text) apply_colour_to_surface(self.text_colour, text_render) else: text_render = self.font.render(self.text, True, self.text_colour, self.bg_colour) text_render = text_render.convert_alpha() else: if isinstance(self.disabled_text_colour, ColourGradient): text_render = render_white_text_alpha_black_bg(self.font, self.text) self.disabled_text_colour.apply_gradient_to_surface(text_render) else: if self.bg_colour.a != 255 or self.text_shadow: text_render = render_white_text_alpha_black_bg(self.font, self.text) apply_colour_to_surface(self.disabled_text_colour, text_render) else: text_render = self.font.render(self.text, True, self.disabled_text_colour, self.bg_colour) text_render = text_render.convert_alpha() text_render_rect = text_render.get_rect(centerx=int(self.rect.width / 2), centery=int(self.rect.height / 2)) if self.text_shadow: self._rebuild_shadow(new_image, text_render_rect) basic_blit(new_image, text_render, text_render_rect) self.set_image(new_image)
def rebuild_images_and_text(self, image_state_str: str, state_str: str, text_colour_state_str: str): """ Rebuilds any text or image used by a specific state in the drawable shape. Effectively this means adding them on top of whatever is already in the state's surface. As such it should generally be called last in the process of building up a finished drawable shape state. :param image_state_str: image ID of the state we are going to be adding images and text to. :param state_str: normal ID of the state we are going to be adding images and text to. :param text_colour_state_str: text ID of the state we are going to be adding images and text to. """ # Draw any themed images if image_state_str in self.theming and self.theming[ image_state_str] is not None: image_rect = self.theming[image_state_str].get_rect() image_rect.center = (int(self.containing_rect.width / 2), int(self.containing_rect.height / 2)) basic_blit(self.states[state_str].surface, self.theming[image_state_str], image_rect) # Draw any text if 'text' in self.theming and 'font' in self.theming and self.theming[ 'text'] is not None: if len(self.theming['text'] ) > 0 and text_colour_state_str in self.theming: text_surface = render_white_text_alpha_black_bg( font=self.theming['font'], text=self.theming['text']) if isinstance(self.theming[text_colour_state_str], ColourGradient): self.theming[ text_colour_state_str].apply_gradient_to_surface( text_surface) else: apply_colour_to_surface( self.theming[text_colour_state_str], text_surface) else: text_surface = None if 'text_shadow' in self.theming: text_shadow = render_white_text_alpha_black_bg( font=self.theming['font'], text=self.theming['text']) apply_colour_to_surface(self.theming['text_shadow'], text_shadow) basic_blit( self.states[state_str].surface, text_shadow, (self.aligned_text_rect.x, self.aligned_text_rect.y + 1)) basic_blit( self.states[state_str].surface, text_shadow, (self.aligned_text_rect.x, self.aligned_text_rect.y - 1)) basic_blit( self.states[state_str].surface, text_shadow, (self.aligned_text_rect.x + 1, self.aligned_text_rect.y)) basic_blit( self.states[state_str].surface, text_shadow, (self.aligned_text_rect.x - 1, self.aligned_text_rect.y)) if text_surface is not None and self.aligned_text_rect is not None: basic_blit(self.states[state_str].surface, text_surface, self.aligned_text_rect)
def _redraw_selected_text(self): """ Redraw text where some has been selected by a user. """ low_end = min(self.select_range[0], self.select_range[1]) high_end = max(self.select_range[0], self.select_range[1]) pre_select_area_text = self.text[:low_end] select_area_text = self.text[low_end:high_end] post_select_area_text = self.text[high_end:] pre_select_area_surface = None post_select_area_surface = None overall_size = self.font.size(self.text) advances = [ letter_metrics[4] for letter_metrics in self.font.metrics(self.text) ] pre_select_width = sum(advances[:low_end]) select_area_width = sum(advances[low_end:high_end]) if len(pre_select_area_text) > 0: pre_select_area_surface = self._draw_text_with_grad_or_col( pre_select_area_text, self.text_colour) if isinstance(self.selected_bg_colour, ColourGradient): select_area_surface = pygame.surface.Surface( (select_area_width, overall_size[1]), flags=pygame.SRCALPHA, depth=32) select_area_surface.fill(pygame.Color('#FFFFFFFF')) self.selected_bg_colour.apply_gradient_to_surface( select_area_surface) alpha_text = self._draw_text_with_grad_or_col( select_area_text, self.selected_text_colour) basic_blit(select_area_surface, alpha_text, (0, 0)) else: if isinstance(self.selected_text_colour, ColourGradient): select_area_surface = pygame.surface.Surface( (select_area_width, overall_size[1]), flags=pygame.SRCALPHA, depth=32) select_area_surface.fill(self.selected_bg_colour) alpha_text = render_white_text_alpha_black_bg( font=self.font, text=select_area_text) self.selected_text_colour.apply_gradient_to_surface(alpha_text) basic_blit(select_area_surface, alpha_text, (0, 0)) else: select_area_surface = self.font.render( select_area_text, True, self.selected_text_colour, self.selected_bg_colour).convert_alpha() if len(post_select_area_text) > 0: post_select_area_surface = self._draw_text_with_grad_or_col( post_select_area_text, self.text_colour) self.text_surface = pygame.surface.Surface(overall_size, flags=pygame.SRCALPHA, depth=32) if isinstance(self.background_colour, ColourGradient): self.text_image.fill(pygame.Color("#FFFFFFFF")) self.background_colour.apply_gradient_to_surface(self.text_image) else: self.text_image.fill(self.background_colour) if pre_select_area_surface is not None: basic_blit(self.text_surface, pre_select_area_surface, (0, 0)) basic_blit(self.text_surface, select_area_surface, (pre_select_width, 0)) if post_select_area_surface is not None: basic_blit(self.text_surface, post_select_area_surface, (pre_select_width + select_area_width, 0))
def __init__(self, font_size: int, font_name: str, chunk: str, style: CharStyle, colour: Union[pygame.Color, ColourGradient], bg_colour: Union[pygame.Color, ColourGradient], is_link: bool, link_href: str, link_style: CharStyle, position: Tuple[int, int], font_dictionary: UIFontDictionary): self.style = style self.chunk = chunk self.font_size = font_size self.font_name = font_name self.is_link = is_link self.link_href = link_href self.link_style = link_style self.font = font_dictionary.find_font(font_size, font_name, self.style.bold, self.style.italic) if self.is_link: self.normal_colour = self.link_style['link_text'] self.hover_colour = self.link_style['link_hover'] self.selected_colour = self.link_style['link_selected'] self.link_normal_underline = self.link_style['link_normal_underline'] self.link_hover_underline = self.link_style['link_hover_underline'] else: self.normal_colour = colour self.hover_colour = None self.selected_colour = None self.link_normal_underline = False self.link_hover_underline = False self.colour = self.normal_colour self.bg_colour = bg_colour self.position = position self.is_hovered = False self.is_selected = False if self.style.underline or (self.is_hovered and self.link_hover_underline) or \ (self.link_normal_underline and not self.is_hovered): self.font.set_underline(True) if len(self.chunk) > 0: if not isinstance(self.colour, ColourGradient): if isinstance(self.bg_colour, ColourGradient) or self.bg_colour.a != 255: self.rendered_chunk = render_white_text_alpha_black_bg(self.font, self.chunk) apply_colour_to_surface(self.colour, self.rendered_chunk) else: self.rendered_chunk = self.font.render(self.chunk, True, self.colour, self.bg_colour).convert_alpha() else: self.rendered_chunk = render_white_text_alpha_black_bg(self.font, self.chunk) self.colour.apply_gradient_to_surface(self.rendered_chunk) else: self.rendered_chunk = pygame.surface.Surface((0, 0), flags=pygame.SRCALPHA, depth=32) metrics = self.font.metrics(self.chunk) self.ascent = self.font.get_ascent() self.width = self.font.size(self.chunk)[0] self.height = self.font.size(self.chunk)[1] self.advance = 0 for i in range(len(self.chunk)): if len(metrics[i]) == 5: self.advance += metrics[i][4] self.rect = pygame.Rect(self.position, (self.width, self.height)) self.metrics_changed_after_redraw = False self.unset_underline_style()