Skip to content

Commit

Permalink
Merge pull request #484 from MyreMylar/add-font-antialias
Browse files Browse the repository at this point in the history
Add antialias disabling support to fonts
  • Loading branch information
MyreMylar authored Jan 5, 2024
2 parents fd8561b + 6a9f189 commit f1cedab
Show file tree
Hide file tree
Showing 9 changed files with 85 additions and 38 deletions.
10 changes: 7 additions & 3 deletions pygame_gui/core/gui_font_freetype.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,13 @@ def __init__(self, file: Optional[FileArg], size: Union[int, float],

self.point_size = size

if force_style and style is not None:
self.__internal_font.strong = style['bold']
self.__internal_font.oblique = style['italic']
if style is not None:
self.__internal_font.antialiased = style['antialiased']

if force_style:
self.__internal_font.strong = style['bold']
self.__internal_font.oblique = style['italic']


@property
def underline(self) -> bool:
Expand Down
11 changes: 8 additions & 3 deletions pygame_gui/core/interfaces/font_dictionary_interface.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ class IUIFontDictionaryInterface(metaclass=ABCMeta):

@abstractmethod
def find_font(self, font_size: int, font_name: str,
bold: bool = False, italic: bool = False) -> IGUIFontInterface:
bold: bool = False, italic: bool = False,
antialiased: bool = True) -> IGUIFontInterface:
"""
Find a loaded font from the font dictionary. Will load a font if it does not already exist
and we have paths to the needed files, however it will issue a warning after doing so
Expand All @@ -27,6 +28,7 @@ def find_font(self, font_size: int, font_name: str,
:param font_name: The name of the font to find.
:param bold: Whether the font is bold or not.
:param italic: Whether the font is italic or not.
:param antialiased: Whether the font is antialiased or not.
:return IGUIFontInterface: Returns either the font we asked for, or the default font.
Expand All @@ -42,14 +44,15 @@ def get_default_font(self) -> IGUIFontInterface:
"""

@abstractmethod
def create_font_id(self, font_size: int, font_name: str, bold: bool, italic: bool) -> str:
def create_font_id(self, font_size: int, font_name: str, bold: bool, italic: bool, antialiased: bool = True) -> str:
"""
Create an id for a particularly styled and sized font from those characteristics.
:param font_size: The size of the font.
:param font_name: The name of the font.
:param bold: Whether the font is bold styled or not.
:param italic: Whether the font is italic styled or not.
:param antialiased: Whether the font is antialiased or not.
:return str: The finished font id.
Expand All @@ -58,7 +61,8 @@ def create_font_id(self, font_size: int, font_name: str, bold: bool, italic: boo
@abstractmethod
def preload_font(self, font_size: int, font_name: str,
bold: bool = False, italic: bool = False,
force_immediate_load: bool = False):
force_immediate_load: bool = False,
antialiased: bool = True):
"""
Lets us load a font at a particular size and style before we use it. While you can get
away with relying on dynamic font loading during development, it is better to eventually
Expand All @@ -70,6 +74,7 @@ def preload_font(self, font_size: int, font_name: str,
:param italic: Whether the font is italic styled or not.
:param force_immediate_load: bypasses any asynchronous threaded loading setup to immediately
load the font on the main thread.
:param antialiased: Whether the font is antialiased or not.
"""

Expand Down
7 changes: 5 additions & 2 deletions pygame_gui/core/text/html_parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ def __init__(self,
self.default_style['link_href'] = ''
self.default_style['shadow_data'] = None
self.default_style['effect_id'] = None
self.default_style['antialiased'] = True

# this is the style used before any html is loaded
self.push_style('default_style', self.default_style)
Expand Down Expand Up @@ -247,7 +248,8 @@ def _handle_line_break(self):
font_name=self.current_style['font_name'],
font_size=self.current_style['font_size'],
bold=self.current_style['bold'],
italic=self.current_style['italic'])
italic=self.current_style['italic'],
antialiased=self.current_style['antialiased'])
dimensions = (current_font.get_rect(' ').width,
int(round(self.current_style['font_size'] *
self.line_spacing)))
Expand Down Expand Up @@ -406,7 +408,8 @@ def create_styled_text_chunk(self, text: str):
font_name=self.current_style['font_name'],
font_size=self.current_style['font_size'],
bold=self.current_style['bold'],
italic=self.current_style['italic'])
italic=self.current_style['italic'],
antialiased=self.current_style['antialiased'])

if self.current_style['link']:
should_underline = (self.current_style['underline'] or
Expand Down
18 changes: 15 additions & 3 deletions pygame_gui/core/ui_appearance_theme.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,21 +210,25 @@ def _load_fonts(self):
font_id = self.font_dict.create_font_id(font_info['size'],
font_info['name'],
font_info['bold'],
font_info['italic'])
font_info['italic'],
font_info['antialiased'])

if font_id not in self.font_dict.loaded_fonts:
self.font_dict.preload_font(font_info['size'],
font_info['name'],
font_info['bold'],
font_info['italic'])
font_info['italic'],
False,
font_info['antialiased'])

if element_key not in self.ele_font_res:
self.ele_font_res[element_key] = {}
self.ele_font_res[element_key][locale_key] = self.font_dict.find_font_resource(
font_info['size'],
font_info['name'],
font_info['bold'],
font_info['italic'])
font_info['italic'],
font_info['antialiased'])

def _load_images(self):
"""
Expand Down Expand Up @@ -939,6 +943,14 @@ def _load_element_font_data_from_theme(self,
if 'italic' not in font_info_dict:
font_info_dict['italic'] = False

if 'antialiased' in file_dict:
try:
font_info_dict['antialiased'] = bool(int(file_dict['antialiased']))
except ValueError:
font_info_dict['antialiased'] = True
if 'antialiased' not in font_info_dict:
font_info_dict['antialiased'] = True

if 'regular_path' in file_dict:
font_info_dict['regular_path'] = file_dict['regular_path']
if 'bold_path' in file_dict:
Expand Down
53 changes: 36 additions & 17 deletions pygame_gui/core/ui_font_dictionary.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def __init__(self, size: int, name: str, style: str,
self.size = size
self.name = name
self.style = style
self.idx = (self.name + '_' + self.style + '_' + str(self.size))
self.idx = (self.name + '_' + self.style + '_' + 'aa_' + str(self.size))

self.regular_file_name = regular_file_name
self.bold_file_name = bold_file_name
Expand Down Expand Up @@ -155,7 +155,7 @@ def _load_default_font(self):
default_font_res = FontResource(
font_id=self.default_font.idx,
size=self.default_font.size,
style={'bold': False, 'italic': False},
style={'bold': False, 'italic': False, 'antialiased': True},
location=(
PackageResource(package='pygame_gui.data',
resource=self.default_font.regular_file_name),
Expand All @@ -177,7 +177,7 @@ def _load_default_font(self):
resource=self.default_font.bold_italic_file_name), False)]

def find_font(self, font_size: int, font_name: str,
bold: bool = False, italic: bool = False) -> IGUIFontInterface:
bold: bool = False, italic: bool = False, antialiased: bool = True) -> IGUIFontInterface:
"""
Find a loaded font from the font dictionary. Will load a font if it does not already exist
and we have paths to the needed files, however it will issue a warning after doing so
Expand All @@ -191,14 +191,15 @@ def find_font(self, font_size: int, font_name: str,
:param font_name: The name of the font to find.
:param bold: Whether the font is bold or not.
:param italic: Whether the font is italic or not.
:param antialiased: Whether the font is antialiased or not.
:return IGUIFontInterface: Returns either the font we asked for, or the default font.
"""
return self.find_font_resource(font_size, font_name, bold, italic).loaded_font
return self.find_font_resource(font_size, font_name, bold, italic, antialiased).loaded_font

def find_font_resource(self, font_size: int, font_name: str,
bold: bool = False, italic: bool = False) -> FontResource:
bold: bool = False, italic: bool = False, antialiased: bool = True) -> FontResource:
"""
Find a loaded font resource from the font dictionary. Will load a font if it does not
already exist and we have paths to the needed files, however it will issue a warning
Expand All @@ -212,11 +213,12 @@ def find_font_resource(self, font_size: int, font_name: str,
:param font_name: The name of the font to find.
:param bold: Whether the font is bold or not.
:param italic: Whether the font is italic or not.
:param antialiased: Whether the font is antialiased or not.
:return FontResource: Returns either the font resource we asked for, or the default font.
"""
font_id = self.create_font_id(font_size, font_name, bold, italic)
font_id = self.create_font_id(font_size, font_name, bold, italic, antialiased)

if font_id not in self.used_font_ids:
self.used_font_ids.append(font_id) # record font usage for optimisation purposes
Expand All @@ -233,15 +235,21 @@ def find_font_resource(self, font_size: int, font_name: str,
elif italic:
style_string = "italic"

font_aliasing = "0"
if antialiased:
font_aliasing = "1"

warning_string = ('Finding font with id: ' +
font_id +
" that is not already loaded.\n"
"Preload this font with {'name': "
"'" + font_name + "',"
" 'point_size': " + str(font_size) + ","
" 'style': '" + style_string + "'}")
" 'style': '" + style_string + "'," +
" 'antialiased': '" + font_aliasing +
"'}")
warnings.warn(warning_string, UserWarning)
self.preload_font(font_size, font_name, bold, italic, force_immediate_load=True)
self.preload_font(font_size, font_name, bold, italic, force_immediate_load=True, antialiased=antialiased)
return self.loaded_fonts[font_id]
else:
return self.loaded_fonts[self.default_font.idx]
Expand All @@ -255,14 +263,15 @@ def get_default_font(self) -> IGUIFontInterface:
"""
return self.find_font(self.default_font.size, self.default_font.name)

def create_font_id(self, font_size: int, font_name: str, bold: bool, italic: bool) -> str:
def create_font_id(self, font_size: int, font_name: str, bold: bool, italic: bool, antialiased: bool = True) -> str:
"""
Create an id for a particularly styled and sized font from those characteristics.
:param font_size: The size of the font.
:param font_name: The name of the font.
:param bold: Whether the font is bold styled or not.
:param italic: Whether the font is italic styled or not.
:param antialiased: Whether the font is antialiased or not.
:return str: The finished font id.
Expand All @@ -278,11 +287,16 @@ def create_font_id(self, font_size: int, font_name: str, bold: bool, italic: boo
font_style_string = "italic"
else:
font_style_string = "regular"
return font_name + "_" + font_style_string + "_" + str(font_size)

font_aliasing = "non_aa"
if antialiased:
font_aliasing = "aa"

return font_name + "_" + font_style_string + "_" + font_aliasing + "_" + str(font_size)

def preload_font(self, font_size: int, font_name: str,
bold: bool = False, italic: bool = False,
force_immediate_load: bool = False):
force_immediate_load: bool = False, antialiased: bool = True):
"""
Lets us load a font at a particular size and style before we use it. While you can get
away with relying on dynamic font loading during development, it is better to eventually
Expand All @@ -294,9 +308,10 @@ def preload_font(self, font_size: int, font_name: str,
:param italic: Whether the font is italic styled or not.
:param force_immediate_load: resource loading setup to immediately
load the font on the main thread.
:param antialiased: Whether the font is antialiased or not.
"""
font_id = self.create_font_id(font_size, font_name, bold, italic)
font_id = self.create_font_id(font_size, font_name, bold, italic, antialiased)
if font_id in self.loaded_fonts: # font already loaded
warnings.warn('Trying to pre-load font id: ' +
font_id +
Expand All @@ -312,29 +327,33 @@ def preload_font(self, font_size: int, font_name: str,
font_id,
font_size,
font_style={'bold': True,
'italic': True},
'italic': True,
'antialiased': antialiased},
force_immediate_load=force_immediate_load)

elif bold:
self._load_single_font_style(bold_path,
font_id,
font_size,
font_style={'bold': True,
'italic': False},
'italic': False,
'antialiased': antialiased},
force_immediate_load=force_immediate_load)
elif italic:
self._load_single_font_style(italic_path,
font_id,
font_size,
font_style={'bold': False,
'italic': True},
'italic': True,
'antialiased': antialiased},
force_immediate_load=force_immediate_load)
else:
self._load_single_font_style(regular_path,
font_id,
font_size,
font_style={'bold': False,
'italic': False},
'italic': False,
'antialiased': antialiased},
force_immediate_load=force_immediate_load)
else:
warnings.warn('Trying to pre-load font id:' + font_id + ' with no paths set')
Expand All @@ -351,7 +370,7 @@ def _load_single_font_style(self,
:param font_loc: Path to the font file.
:param font_id: id for the font in the loaded fonts dictionary.
:param font_size: pygame font size.
:param font_style: style dictionary (italic, bold, both or neither)
:param font_style: style dictionary (italic, bold, antialiased, all, some or none)
"""
resource = FontResource(font_id=font_id,
Expand Down
3 changes: 2 additions & 1 deletion pygame_gui/elements/ui_text_box.py
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,8 @@ def parse_html_into_style_data(self):
font_name=self.parser.default_style['font_name'],
font_size=self.parser.default_style['font_size'],
bold=self.parser.default_style['bold'],
italic=self.parser.default_style['italic'])
italic=self.parser.default_style['italic'],
antialiased=self.parser.default_style['antialiased'],)
default_font_data = {"font": default_font,
"font_colour": self.parser.default_style['font_colour'],
"bg_colour": self.parser.default_style['bg_colour']
Expand Down
7 changes: 5 additions & 2 deletions pygame_gui/ui_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -381,7 +381,7 @@ def preload_fonts(self, font_list: List[Dict[str, Union[str, int, float]]]):
'fira_code' font) you must first add the paths to the files for those fonts, then load the
specific fonts with a list of font descriptions in a dictionary form like so:
``{'name': 'fira_code', 'point_size': 12, 'style': 'bold_italic'}``
``{'name': 'fira_code', 'point_size': 12, 'style': 'bold_italic', 'antialiased': 1}``
You can specify size either in pygame.Font point sizes with 'point_size', or in HTML style
sizes with 'html_size'. Style options are:
Expand All @@ -401,20 +401,23 @@ def preload_fonts(self, font_list: List[Dict[str, Union[str, int, float]]]):
bold = False
italic = False
size = 14
antialiased = True
if 'name' in font:
name = font['name']
if 'style' in font:
if 'bold' in font['style']:
bold = True
if 'italic' in font['style']:
italic = True
if 'antialiased' in font:
antialiased = bool(int(font['antialiased']))
if 'html_size' in font:
font_dict = self.ui_theme.get_font_dictionary()
size = font_dict.convert_html_to_point_size(font['html_size'])
elif 'point_size' in font:
size = font['point_size']

self.ui_theme.get_font_dictionary().preload_font(size, name, bold, italic)
self.ui_theme.get_font_dictionary().preload_font(size, name, bold, italic, False, antialiased)

def print_unused_fonts(self):
"""
Expand Down
Loading

0 comments on commit f1cedab

Please sign in to comment.