87 lines
2.8 KiB
Python
87 lines
2.8 KiB
Python
|
from typing import Dict, Optional
|
||
|
|
||
|
import pyglet
|
||
|
from pyglet.font import base
|
||
|
|
||
|
|
||
|
class UserGlyphRenderer(base.GlyphRenderer):
|
||
|
def __init__(self, font: 'UserDefinedFont'):
|
||
|
self._font = font
|
||
|
self._font.glyphs[self._font.default_char] = self.render(self._font.default_char)
|
||
|
super().__init__(font)
|
||
|
|
||
|
def render(self, text: str):
|
||
|
image_data = self._font.mappings[text]
|
||
|
glyph = self._font.create_glyph(image_data)
|
||
|
glyph.set_bearings(-self._font.descent, 0, image_data.width)
|
||
|
return glyph
|
||
|
|
||
|
|
||
|
class UserDefinedFont(base.Font):
|
||
|
"""A basic UserDefinedFont, it takes a mappings of ImageData """
|
||
|
glyph_renderer_class = UserGlyphRenderer
|
||
|
|
||
|
def __init__(self, mappings: Dict[str, pyglet.image.ImageData], default_char: str, name: str, ascent: float,
|
||
|
descent: float, size: float, bold: bool = False, italic: bool = False, stretch: bool = False,
|
||
|
dpi: int = None,
|
||
|
locale: Optional[str] = None):
|
||
|
super().__init__()
|
||
|
self._name = name
|
||
|
self.mappings: Dict[str, pyglet.image.ImageData] = mappings
|
||
|
|
||
|
if default_char not in self.mappings:
|
||
|
raise Exception(f"Default character: '{default_char}' must exist within your mappings.")
|
||
|
|
||
|
if ascent is None or descent is None:
|
||
|
image = list(mappings.values())[0]
|
||
|
|
||
|
if ascent is None:
|
||
|
ascent = image.height
|
||
|
|
||
|
if descent is None:
|
||
|
descent = 0
|
||
|
|
||
|
self.ascent = ascent
|
||
|
self.descent = descent
|
||
|
self.default_char = default_char
|
||
|
|
||
|
self.bold = bold
|
||
|
self.italic = italic
|
||
|
self.stretch = stretch
|
||
|
self.dpi = dpi
|
||
|
self.size = size
|
||
|
self.locale = locale
|
||
|
|
||
|
@property
|
||
|
def name(self):
|
||
|
return self._name
|
||
|
|
||
|
def get_glyphs(self, text):
|
||
|
"""Create and return a list of Glyphs for `text`.
|
||
|
|
||
|
If any characters do not have a known glyph representation in this
|
||
|
font, a substitution will be made.
|
||
|
|
||
|
:Parameters:
|
||
|
`text` : str or unicode
|
||
|
Text to render.
|
||
|
|
||
|
:rtype: list of `Glyph`
|
||
|
"""
|
||
|
glyph_renderer = None
|
||
|
glyphs = [] # glyphs that are committed.
|
||
|
for c in base.get_grapheme_clusters(str(text)):
|
||
|
# Get the glyph for 'c'. Hide tabs (Windows and Linux render
|
||
|
# boxes)
|
||
|
if c == '\t':
|
||
|
c = ' '
|
||
|
if c not in self.glyphs:
|
||
|
if not glyph_renderer:
|
||
|
glyph_renderer = self.glyph_renderer_class(self)
|
||
|
if c not in self.mappings:
|
||
|
c = self.default_char
|
||
|
else:
|
||
|
self.glyphs[c] = glyph_renderer.render(c)
|
||
|
glyphs.append(self.glyphs[c])
|
||
|
return glyphs
|