pyglet 2.1.13__py3-none-any.whl → 3.0.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyglet/__init__.py +67 -61
- pyglet/__init__.pyi +15 -8
- pyglet/app/__init__.py +22 -13
- pyglet/app/async_app.py +212 -0
- pyglet/app/base.py +2 -1
- pyglet/app/{xlib.py → linux.py} +3 -3
- pyglet/config/__init__.py +101 -0
- pyglet/config/gl/__init__.py +30 -0
- pyglet/config/gl/egl.py +120 -0
- pyglet/config/gl/macos.py +262 -0
- pyglet/config/gl/windows.py +267 -0
- pyglet/config/gl/x11.py +142 -0
- pyglet/customtypes.py +43 -2
- pyglet/display/__init__.py +8 -6
- pyglet/display/base.py +3 -63
- pyglet/display/cocoa.py +12 -17
- pyglet/display/emscripten.py +39 -0
- pyglet/display/headless.py +23 -30
- pyglet/display/wayland.py +157 -0
- pyglet/display/win32.py +5 -21
- pyglet/display/xlib.py +19 -27
- pyglet/display/xlib_vidmoderestore.py +2 -2
- pyglet/enums.py +183 -0
- pyglet/event.py +0 -1
- pyglet/experimental/geoshader_sprite.py +15 -13
- pyglet/experimental/hidraw.py +6 -15
- pyglet/experimental/multitexture_sprite.py +31 -19
- pyglet/experimental/particles.py +13 -35
- pyglet/font/__init__.py +251 -85
- pyglet/font/base.py +116 -61
- pyglet/font/dwrite/__init__.py +349 -204
- pyglet/font/dwrite/dwrite_lib.py +27 -5
- pyglet/font/fontconfig.py +14 -6
- pyglet/font/freetype.py +138 -87
- pyglet/font/freetype_lib.py +19 -0
- pyglet/font/group.py +179 -0
- pyglet/font/harfbuzz/__init__.py +3 -3
- pyglet/font/pyodide_js.py +310 -0
- pyglet/font/quartz.py +319 -126
- pyglet/font/ttf.py +45 -3
- pyglet/font/user.py +14 -19
- pyglet/font/win32.py +45 -21
- pyglet/graphics/__init__.py +8 -787
- pyglet/graphics/allocation.py +115 -1
- pyglet/graphics/api/__init__.py +77 -0
- pyglet/graphics/api/base.py +299 -0
- pyglet/graphics/api/gl/__init__.py +58 -0
- pyglet/graphics/api/gl/base.py +24 -0
- pyglet/graphics/{vertexbuffer.py → api/gl/buffer.py} +104 -159
- pyglet/graphics/api/gl/cocoa/context.py +76 -0
- pyglet/graphics/api/gl/context.py +391 -0
- pyglet/graphics/api/gl/default_shaders.py +0 -0
- pyglet/graphics/api/gl/draw.py +627 -0
- pyglet/graphics/api/gl/egl/__init__.py +0 -0
- pyglet/graphics/api/gl/egl/context.py +92 -0
- pyglet/graphics/api/gl/enums.py +76 -0
- pyglet/graphics/api/gl/framebuffer.py +315 -0
- pyglet/graphics/api/gl/gl.py +5463 -0
- pyglet/graphics/api/gl/gl_info.py +188 -0
- pyglet/graphics/api/gl/global_opengl.py +226 -0
- pyglet/{gl → graphics/api/gl}/lib.py +34 -18
- pyglet/graphics/api/gl/shader.py +1476 -0
- pyglet/graphics/api/gl/shapes.py +55 -0
- pyglet/graphics/api/gl/sprite.py +102 -0
- pyglet/graphics/api/gl/state.py +219 -0
- pyglet/graphics/api/gl/text.py +190 -0
- pyglet/graphics/api/gl/texture.py +1526 -0
- pyglet/graphics/{vertexarray.py → api/gl/vertexarray.py} +11 -13
- pyglet/graphics/api/gl/vertexdomain.py +751 -0
- pyglet/graphics/api/gl/win32/__init__.py +0 -0
- pyglet/graphics/api/gl/win32/context.py +108 -0
- pyglet/graphics/api/gl/win32/wgl_info.py +24 -0
- pyglet/graphics/api/gl/xlib/__init__.py +0 -0
- pyglet/graphics/api/gl/xlib/context.py +174 -0
- pyglet/{gl → graphics/api/gl/xlib}/glx_info.py +26 -31
- pyglet/graphics/api/gl1/__init__.py +0 -0
- pyglet/{gl → graphics/api/gl1}/gl_compat.py +3 -2
- pyglet/graphics/api/gl2/__init__.py +0 -0
- pyglet/graphics/api/gl2/buffer.py +320 -0
- pyglet/graphics/api/gl2/draw.py +600 -0
- pyglet/graphics/api/gl2/global_opengl.py +122 -0
- pyglet/graphics/api/gl2/shader.py +200 -0
- pyglet/graphics/api/gl2/shapes.py +51 -0
- pyglet/graphics/api/gl2/sprite.py +79 -0
- pyglet/graphics/api/gl2/text.py +175 -0
- pyglet/graphics/api/gl2/vertexdomain.py +364 -0
- pyglet/graphics/api/webgl/__init__.py +233 -0
- pyglet/graphics/api/webgl/buffer.py +302 -0
- pyglet/graphics/api/webgl/context.py +234 -0
- pyglet/graphics/api/webgl/draw.py +590 -0
- pyglet/graphics/api/webgl/enums.py +76 -0
- pyglet/graphics/api/webgl/framebuffer.py +360 -0
- pyglet/graphics/api/webgl/gl.py +1537 -0
- pyglet/graphics/api/webgl/gl_info.py +130 -0
- pyglet/graphics/api/webgl/shader.py +1346 -0
- pyglet/graphics/api/webgl/shapes.py +92 -0
- pyglet/graphics/api/webgl/sprite.py +102 -0
- pyglet/graphics/api/webgl/state.py +227 -0
- pyglet/graphics/api/webgl/text.py +187 -0
- pyglet/graphics/api/webgl/texture.py +1227 -0
- pyglet/graphics/api/webgl/vertexarray.py +54 -0
- pyglet/graphics/api/webgl/vertexdomain.py +616 -0
- pyglet/graphics/api/webgl/webgl_js.pyi +307 -0
- pyglet/{image → graphics}/atlas.py +33 -32
- pyglet/graphics/base.py +10 -0
- pyglet/graphics/buffer.py +245 -0
- pyglet/graphics/draw.py +578 -0
- pyglet/graphics/framebuffer.py +26 -0
- pyglet/graphics/instance.py +178 -69
- pyglet/graphics/shader.py +267 -1553
- pyglet/graphics/state.py +83 -0
- pyglet/graphics/texture.py +703 -0
- pyglet/graphics/vertexdomain.py +695 -538
- pyglet/gui/ninepatch.py +10 -10
- pyglet/gui/widgets.py +120 -10
- pyglet/image/__init__.py +20 -1973
- pyglet/image/animation.py +12 -12
- pyglet/image/base.py +730 -0
- pyglet/image/codecs/__init__.py +9 -0
- pyglet/image/codecs/bmp.py +53 -30
- pyglet/image/codecs/dds.py +53 -31
- pyglet/image/codecs/gdiplus.py +38 -14
- pyglet/image/codecs/gdkpixbuf2.py +0 -2
- pyglet/image/codecs/js_image.py +99 -0
- pyglet/image/codecs/ktx2.py +161 -0
- pyglet/image/codecs/pil.py +1 -1
- pyglet/image/codecs/png.py +1 -1
- pyglet/image/codecs/wic.py +11 -2
- pyglet/info.py +26 -24
- pyglet/input/__init__.py +8 -0
- pyglet/input/base.py +163 -105
- pyglet/input/controller.py +13 -19
- pyglet/input/controller_db.py +39 -24
- pyglet/input/emscripten/__init__.py +18 -0
- pyglet/input/emscripten/gamepad_js.py +397 -0
- pyglet/input/linux/__init__.py +11 -5
- pyglet/input/linux/evdev.py +10 -11
- pyglet/input/linux/x11_xinput.py +2 -2
- pyglet/input/linux/x11_xinput_tablet.py +1 -1
- pyglet/input/macos/__init__.py +7 -2
- pyglet/input/macos/darwin_gc.py +559 -0
- pyglet/input/win32/__init__.py +1 -1
- pyglet/input/win32/directinput.py +34 -29
- pyglet/input/win32/xinput.py +11 -61
- pyglet/lib.py +3 -3
- pyglet/libs/__init__.py +1 -1
- pyglet/{gl → libs/darwin}/agl.py +1 -1
- pyglet/libs/darwin/cocoapy/__init__.py +2 -2
- pyglet/libs/darwin/cocoapy/cocoahelpers.py +181 -0
- pyglet/libs/darwin/cocoapy/cocoalibs.py +31 -0
- pyglet/libs/darwin/cocoapy/cocoatypes.py +27 -0
- pyglet/libs/darwin/cocoapy/runtime.py +81 -45
- pyglet/libs/darwin/coreaudio.py +4 -4
- pyglet/{gl → libs/darwin}/lib_agl.py +9 -8
- pyglet/libs/darwin/quartzkey.py +1 -3
- pyglet/libs/egl/__init__.py +2 -0
- pyglet/libs/egl/egl_lib.py +576 -0
- pyglet/libs/egl/eglext.py +51 -5
- pyglet/libs/linux/__init__.py +0 -0
- pyglet/libs/linux/egl/__init__.py +0 -0
- pyglet/libs/linux/egl/eglext.py +22 -0
- pyglet/libs/linux/glx/__init__.py +0 -0
- pyglet/{gl → libs/linux/glx}/glx.py +13 -14
- pyglet/{gl → libs/linux/glx}/glxext_arb.py +408 -192
- pyglet/{gl → libs/linux/glx}/glxext_mesa.py +1 -1
- pyglet/{gl → libs/linux/glx}/glxext_nv.py +345 -164
- pyglet/{gl → libs/linux/glx}/lib_glx.py +3 -2
- pyglet/libs/linux/wayland/__init__.py +0 -0
- pyglet/libs/linux/wayland/client.py +1068 -0
- pyglet/libs/linux/wayland/lib_wayland.py +207 -0
- pyglet/libs/linux/wayland/wayland_egl.py +38 -0
- pyglet/libs/{wayland → linux/wayland}/xkbcommon.py +26 -0
- pyglet/libs/{x11 → linux/x11}/xf86vmode.py +4 -4
- pyglet/libs/{x11 → linux/x11}/xinerama.py +2 -2
- pyglet/libs/{x11 → linux/x11}/xinput.py +10 -10
- pyglet/libs/linux/x11/xrandr.py +0 -0
- pyglet/libs/{x11 → linux/x11}/xrender.py +1 -1
- pyglet/libs/shared/__init__.py +0 -0
- pyglet/libs/shared/spirv/__init__.py +0 -0
- pyglet/libs/shared/spirv/lib_shaderc.py +85 -0
- pyglet/libs/shared/spirv/lib_spirv_cross.py +126 -0
- pyglet/libs/win32/__init__.py +28 -8
- pyglet/libs/win32/constants.py +59 -48
- pyglet/libs/win32/context_managers.py +20 -3
- pyglet/libs/win32/dinput.py +105 -88
- pyglet/{gl → libs/win32}/lib_wgl.py +52 -26
- pyglet/libs/win32/types.py +58 -23
- pyglet/{gl → libs/win32}/wgl.py +32 -25
- pyglet/{gl → libs/win32}/wglext_arb.py +364 -2
- pyglet/media/__init__.py +9 -10
- pyglet/media/codecs/__init__.py +12 -1
- pyglet/media/codecs/base.py +99 -96
- pyglet/media/codecs/ffmpeg.py +2 -2
- pyglet/media/codecs/ffmpeg_lib/libavformat.py +3 -8
- pyglet/media/codecs/webaudio_pyodide.py +111 -0
- pyglet/media/drivers/__init__.py +9 -4
- pyglet/media/drivers/base.py +4 -4
- pyglet/media/drivers/openal/__init__.py +1 -1
- pyglet/media/drivers/openal/adaptation.py +3 -3
- pyglet/media/drivers/pulse/__init__.py +1 -1
- pyglet/media/drivers/pulse/adaptation.py +3 -3
- pyglet/media/drivers/pyodide_js/__init__.py +8 -0
- pyglet/media/drivers/pyodide_js/adaptation.py +288 -0
- pyglet/media/drivers/xaudio2/adaptation.py +3 -3
- pyglet/media/player.py +276 -193
- pyglet/media/player_worker_thread.py +1 -1
- pyglet/model/__init__.py +39 -29
- pyglet/model/codecs/base.py +4 -4
- pyglet/model/codecs/gltf.py +3 -3
- pyglet/model/codecs/obj.py +71 -43
- pyglet/resource.py +129 -78
- pyglet/shapes.py +154 -194
- pyglet/sprite.py +47 -164
- pyglet/text/__init__.py +44 -54
- pyglet/text/caret.py +12 -7
- pyglet/text/document.py +19 -17
- pyglet/text/formats/html.py +2 -2
- pyglet/text/formats/structured.py +10 -40
- pyglet/text/layout/__init__.py +20 -13
- pyglet/text/layout/base.py +176 -287
- pyglet/text/layout/incremental.py +9 -10
- pyglet/text/layout/scrolling.py +7 -95
- pyglet/window/__init__.py +183 -172
- pyglet/window/cocoa/__init__.py +62 -51
- pyglet/window/cocoa/pyglet_delegate.py +2 -25
- pyglet/window/cocoa/pyglet_view.py +9 -8
- pyglet/window/dialog/__init__.py +184 -0
- pyglet/window/dialog/base.py +99 -0
- pyglet/window/dialog/darwin.py +121 -0
- pyglet/window/dialog/linux.py +72 -0
- pyglet/window/dialog/windows.py +194 -0
- pyglet/window/emscripten/__init__.py +779 -0
- pyglet/window/headless/__init__.py +44 -28
- pyglet/window/key.py +2 -0
- pyglet/window/mouse.py +2 -2
- pyglet/window/wayland/__init__.py +377 -0
- pyglet/window/win32/__init__.py +101 -46
- pyglet/window/xlib/__init__.py +104 -66
- {pyglet-2.1.13.dist-info → pyglet-3.0.dev1.dist-info}/METADATA +2 -3
- pyglet-3.0.dev1.dist-info/RECORD +322 -0
- {pyglet-2.1.13.dist-info → pyglet-3.0.dev1.dist-info}/WHEEL +1 -1
- pyglet/gl/__init__.py +0 -208
- pyglet/gl/base.py +0 -499
- pyglet/gl/cocoa.py +0 -309
- pyglet/gl/gl.py +0 -4625
- pyglet/gl/gl.pyi +0 -2320
- pyglet/gl/gl_compat.pyi +0 -3097
- pyglet/gl/gl_info.py +0 -190
- pyglet/gl/headless.py +0 -166
- pyglet/gl/wgl_info.py +0 -36
- pyglet/gl/wglext_nv.py +0 -1096
- pyglet/gl/win32.py +0 -268
- pyglet/gl/xlib.py +0 -295
- pyglet/image/buffer.py +0 -274
- pyglet/image/codecs/s3tc.py +0 -354
- pyglet/libs/x11/xrandr.py +0 -166
- pyglet-2.1.13.dist-info/RECORD +0 -234
- /pyglet/{libs/wayland → graphics/api/gl/cocoa}/__init__.py +0 -0
- /pyglet/libs/{egl → linux/egl}/egl.py +0 -0
- /pyglet/libs/{egl → linux/egl}/lib.py +0 -0
- /pyglet/libs/{ioctl.py → linux/ioctl.py} +0 -0
- /pyglet/libs/{wayland → linux/wayland}/gbm.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/__init__.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/cursorfont.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/xlib.py +0 -0
- /pyglet/libs/{x11 → linux/x11}/xsync.py +0 -0
- {pyglet-2.1.13.dist-info/licenses → pyglet-3.0.dev1.dist-info}/LICENSE +0 -0
pyglet/font/__init__.py
CHANGED
|
@@ -15,20 +15,187 @@ pyglet will automatically load any system-installed fonts. You can add addition
|
|
|
15
15
|
See the :mod:`pyglet.font.base` module for documentation on the base classes used
|
|
16
16
|
by this package.
|
|
17
17
|
"""
|
|
18
|
+
|
|
18
19
|
from __future__ import annotations
|
|
19
20
|
|
|
21
|
+
import collections
|
|
20
22
|
import os
|
|
21
23
|
import sys
|
|
22
24
|
import weakref
|
|
23
|
-
from
|
|
25
|
+
from dataclasses import dataclass
|
|
26
|
+
from typing import TYPE_CHECKING, BinaryIO, Iterable, Sequence, Any
|
|
24
27
|
|
|
25
28
|
import pyglet
|
|
26
|
-
from pyglet import
|
|
29
|
+
from pyglet.enums import Weight, Style, Stretch
|
|
30
|
+
from pyglet.font.group import FontGroup
|
|
27
31
|
from pyglet.font.user import UserDefinedFontBase
|
|
32
|
+
from pyglet.graphics.api import core
|
|
28
33
|
|
|
29
34
|
if TYPE_CHECKING:
|
|
35
|
+
from pyglet.event import EVENT_HANDLE_STATE
|
|
30
36
|
from pyglet.font.base import Font
|
|
37
|
+
from pyglet.graphics.api.base import SurfaceContext
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
@dataclass
|
|
41
|
+
class _FontContext:
|
|
42
|
+
"""A container for data specific to a graphics context.
|
|
43
|
+
|
|
44
|
+
Glyph textures can only be used in their respective graphics context.
|
|
45
|
+
"""
|
|
46
|
+
context: SurfaceContext
|
|
47
|
+
cache: weakref.WeakValueDictionary[tuple, Font]
|
|
48
|
+
|
|
49
|
+
# Hold onto refs of last three loaded fonts to prevent them being
|
|
50
|
+
# collected if momentarily dropped.
|
|
51
|
+
hold: collections.deque
|
|
52
|
+
|
|
53
|
+
def add(self, descriptor: tuple, font: Font) -> None:
|
|
54
|
+
"""Add a font with the descriptor into the cache."""
|
|
55
|
+
self.cache[descriptor] = font
|
|
56
|
+
self.hold.appendleft(font)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class FontManager(pyglet.event.EventDispatcher):
|
|
61
|
+
"""A manager to keep track of system fonts, font files, and user loaded fonts.
|
|
62
|
+
|
|
63
|
+
This is a global singleton and should not be instantiated by a user.
|
|
64
|
+
|
|
65
|
+
.. versionadded: 3.0
|
|
66
|
+
"""
|
|
67
|
+
default_win32_font = "Segoe UI"
|
|
68
|
+
default_darwin_font = "System Default"
|
|
69
|
+
default_linux_font = "sans" # FC will convert to actual font.
|
|
70
|
+
default_emscripten_font = "Times New Roman"
|
|
71
|
+
|
|
72
|
+
resolved_names: dict[tuple[str, ...], str]
|
|
73
|
+
|
|
74
|
+
_font_groups: dict[str, FontGroup]
|
|
75
|
+
_user_font_names: set[str]
|
|
76
|
+
_font_contexts: weakref.WeakKeyDictionary[SurfaceContext, _FontContext]
|
|
77
|
+
|
|
78
|
+
def __init__(self) -> None:
|
|
79
|
+
self._font_contexts = weakref.WeakKeyDictionary()
|
|
80
|
+
self._hold = collections.deque(maxlen=3)
|
|
81
|
+
self._added_families = set()
|
|
82
|
+
self._added_faces = set()
|
|
83
|
+
self._user_font_names = set()
|
|
84
|
+
self._font_groups = {}
|
|
85
|
+
|
|
86
|
+
# A mapping of sequence to the resulting font name.
|
|
87
|
+
self.resolved_names = {}
|
|
88
|
+
|
|
89
|
+
def _invalidate(self) -> None:
|
|
90
|
+
"""Invalidates all caches.
|
|
91
|
+
|
|
92
|
+
Used for tests.
|
|
93
|
+
"""
|
|
94
|
+
self._font_contexts.clear()
|
|
95
|
+
self._hold.clear()
|
|
96
|
+
self._added_families.clear()
|
|
97
|
+
self._added_faces.clear()
|
|
98
|
+
self._user_font_names.clear()
|
|
99
|
+
self.resolved_names.clear()
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def _get_key_name(name: str | Sequence[str]) -> tuple[str, ...]:
|
|
103
|
+
if isinstance(name, list):
|
|
104
|
+
key_names = tuple(name)
|
|
105
|
+
elif isinstance(name, str):
|
|
106
|
+
key_names = (name,)
|
|
107
|
+
else:
|
|
108
|
+
key_names = name
|
|
109
|
+
|
|
110
|
+
return key_names
|
|
111
|
+
|
|
112
|
+
def get_group(self, name: str) -> FontGroup | None:
|
|
113
|
+
"""Check if the specified name is a font group."""
|
|
114
|
+
return self._font_groups.get(name)
|
|
115
|
+
|
|
116
|
+
def get_resolved_name(self, name: str | Sequence[str]) -> str | None:
|
|
117
|
+
"""Return the name of the first font found for a name or list of names.
|
|
118
|
+
|
|
119
|
+
If a font is not found, a default font will be used depending on the platform.
|
|
120
|
+
|
|
121
|
+
A sequence of font names can be used with layouts, using the first found. Each name is checked to ensure
|
|
122
|
+
it exists everytime it is used or text changes.
|
|
123
|
+
|
|
124
|
+
Platform specific ``have_font`` calls can be slow depending on the platform.
|
|
125
|
+
"""
|
|
126
|
+
key_names = self._get_key_name(name)
|
|
127
|
+
|
|
128
|
+
if key_names in self.resolved_names:
|
|
129
|
+
return self.resolved_names[key_names]
|
|
130
|
+
|
|
131
|
+
for font_name in key_names:
|
|
132
|
+
if font_name in self._user_font_names or font_name in self._font_groups or _system_font_class.have_font(font_name):
|
|
133
|
+
self.resolved_names[key_names] = font_name
|
|
134
|
+
return font_name
|
|
135
|
+
|
|
136
|
+
# If nothing found here, then get a default name.
|
|
137
|
+
self.resolved_names[key_names] = manager.get_platform_default_name()
|
|
138
|
+
return self.resolved_names[key_names]
|
|
139
|
+
|
|
140
|
+
def get_platform_default_name(self) -> str:
|
|
141
|
+
"""Return a font name that should be guaranteed to exist on a particular platform."""
|
|
142
|
+
if pyglet.compat_platform == "win32":
|
|
143
|
+
return self.default_win32_font
|
|
144
|
+
if pyglet.compat_platform == "darwin":
|
|
145
|
+
return self.default_darwin_font
|
|
146
|
+
if pyglet.compat_platform == "linux":
|
|
147
|
+
return self.default_linux_font
|
|
148
|
+
if pyglet.compat_platform == "emscripten":
|
|
149
|
+
return self.default_emscripten_font
|
|
150
|
+
|
|
151
|
+
msg = f"Unsupported platform: {pyglet.compat_platform}"
|
|
152
|
+
raise Exception(msg)
|
|
153
|
+
|
|
154
|
+
def _get_context_data(self, context: SurfaceContext | None = None) -> _FontContext:
|
|
155
|
+
"""Get a font context based on the current graphics context."""
|
|
156
|
+
graphics_ctx = context or core.current_context
|
|
157
|
+
try:
|
|
158
|
+
return self._font_contexts[graphics_ctx]
|
|
159
|
+
except KeyError:
|
|
160
|
+
font_context = _FontContext(graphics_ctx, weakref.WeakValueDictionary(), collections.deque(maxlen=3))
|
|
161
|
+
self._font_contexts[graphics_ctx] = font_context
|
|
162
|
+
return font_context
|
|
163
|
+
|
|
164
|
+
def have_font(self, name: str) -> bool:
|
|
165
|
+
"""Check if specified font name is available in the system database or user font database."""
|
|
166
|
+
return name in self._font_groups or name in self._user_font_names or self._get_key_name(name) in self.resolved_names or _system_font_class.have_font(name)
|
|
167
|
+
|
|
168
|
+
def _add_user_font(self, font: UserDefinedFontBase) -> None:
|
|
169
|
+
self._user_font_names.add(font.name)
|
|
170
|
+
self.dispatch_event("on_font_loaded", font.name, font.weight, font.style, font.stretch)
|
|
31
171
|
|
|
172
|
+
def _add_font_group(self, group: FontGroup) -> None:
|
|
173
|
+
self._font_groups[group.name] = group
|
|
174
|
+
|
|
175
|
+
def _add_loaded_font(self, fonts: set[tuple[str, str, str, str]]) -> None:
|
|
176
|
+
old = self._added_faces
|
|
177
|
+
new_fonts = fonts - old
|
|
178
|
+
self._added_faces.update(fonts)
|
|
179
|
+
|
|
180
|
+
# Clear any resolved names as this affects already loaded fonts.
|
|
181
|
+
self.resolved_names.clear()
|
|
182
|
+
|
|
183
|
+
for new_font in new_fonts:
|
|
184
|
+
self._added_families.add(new_font[0])
|
|
185
|
+
self.dispatch_event("on_font_loaded", *new_font)
|
|
186
|
+
|
|
187
|
+
def on_font_loaded(self, family_name: str, weight: str, style: str, stretch: str) -> EVENT_HANDLE_STATE:
|
|
188
|
+
"""When a font is loaded, this event will be dispatched with the family name and style of the font.
|
|
189
|
+
|
|
190
|
+
On some platforms, a custom added font may not be available immediately after adding the data. In these cases,
|
|
191
|
+
you can set a handler on this event to get notified when it's available.
|
|
192
|
+
|
|
193
|
+
.. note:: Not currently supported by GDI.
|
|
194
|
+
"""
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
manager = FontManager()
|
|
198
|
+
manager.register_event_type("on_font_loaded")
|
|
32
199
|
|
|
33
200
|
def _get_system_font_class() -> type[Font]:
|
|
34
201
|
"""Get the appropriate class for the system being used.
|
|
@@ -37,22 +204,42 @@ def _get_system_font_class() -> type[Font]:
|
|
|
37
204
|
"""
|
|
38
205
|
if pyglet.compat_platform == "darwin":
|
|
39
206
|
from pyglet.font.quartz import QuartzFont
|
|
207
|
+
|
|
40
208
|
_font_class = QuartzFont
|
|
41
209
|
|
|
42
210
|
elif pyglet.compat_platform in ("win32", "cygwin"):
|
|
43
211
|
from pyglet.libs.win32.constants import WINDOWS_7_OR_GREATER
|
|
212
|
+
|
|
44
213
|
if WINDOWS_7_OR_GREATER and not pyglet.options["win32_gdi_font"]:
|
|
45
214
|
from pyglet.font.dwrite import Win32DirectWriteFont
|
|
215
|
+
|
|
46
216
|
_font_class = Win32DirectWriteFont
|
|
47
217
|
else:
|
|
48
218
|
from pyglet.font.win32 import GDIPlusFont
|
|
219
|
+
|
|
49
220
|
_font_class = GDIPlusFont
|
|
50
|
-
|
|
221
|
+
elif pyglet.compat_platform == "linux":
|
|
51
222
|
from pyglet.font.freetype import FreeTypeFont
|
|
223
|
+
|
|
52
224
|
_font_class = FreeTypeFont
|
|
225
|
+
elif pyglet.compat_platform == "emscripten":
|
|
226
|
+
from pyglet.font.pyodide_js import JavascriptPyodideFont
|
|
227
|
+
|
|
228
|
+
_font_class = JavascriptPyodideFont
|
|
229
|
+
else:
|
|
230
|
+
raise Exception("Font Renderer is not available for this Operating System.")
|
|
53
231
|
|
|
54
232
|
return _font_class
|
|
55
233
|
|
|
234
|
+
def add_group(font_group: FontGroup) -> None:
|
|
235
|
+
"""Add a font group to pyglet's list of font groups."""
|
|
236
|
+
assert isinstance(font_group, FontGroup), "Added group must be based on a FontGroup class."
|
|
237
|
+
|
|
238
|
+
if _system_font_class.have_font(font_group.name):
|
|
239
|
+
msg = f"Cannot use FontGroup, name '{font_group.name}' already exists within the system or loaded fonts."
|
|
240
|
+
raise Exception(msg)
|
|
241
|
+
|
|
242
|
+
manager._add_font_group(font_group) # noqa: SLF001
|
|
56
243
|
|
|
57
244
|
def add_user_font(font: UserDefinedFontBase) -> None:
|
|
58
245
|
"""Add a custom font created by the user.
|
|
@@ -72,126 +259,98 @@ def add_user_font(font: UserDefinedFontBase) -> None:
|
|
|
72
259
|
raise Exception(msg)
|
|
73
260
|
|
|
74
261
|
# Locate or create font cache
|
|
75
|
-
|
|
76
|
-
if not hasattr(shared_object_space, "pyglet_font_font_cache"):
|
|
77
|
-
shared_object_space.pyglet_font_font_cache = weakref.WeakValueDictionary()
|
|
78
|
-
shared_object_space.pyglet_font_font_hold = []
|
|
79
|
-
# Match a tuple to specific name to reduce lookups.
|
|
80
|
-
shared_object_space.pyglet_font_font_name_match = {}
|
|
81
|
-
font_cache = shared_object_space.pyglet_font_font_cache
|
|
82
|
-
font_hold = shared_object_space.pyglet_font_font_hold
|
|
262
|
+
font_context = manager._get_context_data(core.current_context) # noqa: SLF001
|
|
83
263
|
|
|
84
264
|
# Look for font name in font cache
|
|
85
|
-
descriptor = (font.name, font.size, font.weight, font.
|
|
86
|
-
if descriptor in
|
|
87
|
-
msg = f"A font with parameters {descriptor} has already been created."
|
|
265
|
+
descriptor = (font.name, font.size, font.weight, font.style, font.stretch, font.dpi)
|
|
266
|
+
if descriptor in font_context.cache:
|
|
267
|
+
msg = f"A font with parameters {descriptor} has already been created. Use a more unique name."
|
|
88
268
|
raise Exception(msg)
|
|
89
269
|
if _system_font_class.have_font(font.name):
|
|
90
|
-
msg = f"Font name '{font.name}' already exists within the system fonts."
|
|
270
|
+
msg = f"Font name '{font.name}' already exists within the system or loaded fonts."
|
|
91
271
|
raise Exception(msg)
|
|
92
272
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
# Cache font in weak-ref dictionary to avoid reloading while still in use
|
|
96
|
-
font_cache[descriptor] = font
|
|
97
|
-
# Hold onto refs of last three loaded fonts to prevent them being
|
|
98
|
-
# collected if momentarily dropped.
|
|
99
|
-
del font_hold[3:]
|
|
100
|
-
font_hold.insert(0, font)
|
|
273
|
+
font_context.add(descriptor, font)
|
|
274
|
+
manager._add_user_font(font) # noqa: SLF001
|
|
101
275
|
|
|
102
276
|
|
|
103
277
|
def have_font(name: str) -> bool:
|
|
104
278
|
"""Check if specified font name is available in the system database or user font database."""
|
|
105
|
-
return
|
|
279
|
+
return manager.have_font(name)
|
|
106
280
|
|
|
107
281
|
|
|
108
|
-
def load(
|
|
109
|
-
|
|
282
|
+
def load(
|
|
283
|
+
name: str | Iterable[str] | None = None,
|
|
284
|
+
size: float | None = None,
|
|
285
|
+
weight: str | None = "normal",
|
|
286
|
+
style: str | None = "normal",
|
|
287
|
+
stretch: str | None = "normal",
|
|
288
|
+
dpi: int | None = None,
|
|
289
|
+
) -> Font:
|
|
110
290
|
"""Load a font for rendering.
|
|
111
291
|
|
|
112
292
|
Args:
|
|
113
293
|
name:
|
|
114
294
|
Font family, for example, "Times New Roman". If a list of names
|
|
115
295
|
is provided, the first one matching a known font is used. If no
|
|
116
|
-
font can be matched to the name(s), a default font is used.
|
|
117
|
-
will be platform dependent.
|
|
296
|
+
font can be matched to the name(s), a default font is used.
|
|
297
|
+
The default font will be platform dependent.
|
|
118
298
|
size:
|
|
119
299
|
Size of the font, in points. The returned font may be an exact
|
|
120
300
|
match or the closest available.
|
|
121
301
|
weight:
|
|
122
302
|
If set, a specific weight variant is returned if one exists for the given font
|
|
123
|
-
family and size.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
303
|
+
family and size. For example, "bold" can be specified. Refer to :py:class:`~pyglet.enums.Weight`
|
|
304
|
+
for valid options.
|
|
305
|
+
style:
|
|
306
|
+
If specified, an italic variant can be returned if one exists for the given family and size. If a font is
|
|
307
|
+
oblique, or italic, either will fallback to choose that variation. Refer to :py:class:`~pyglet.enums.Style`
|
|
308
|
+
for valid options.
|
|
127
309
|
stretch:
|
|
128
|
-
If
|
|
129
|
-
|
|
310
|
+
If specified a stretch variant is returned, if one exists for the given family and size. Refer to
|
|
311
|
+
:py:class:`~pyglet.enums.Stretch` for valid options.
|
|
130
312
|
dpi: int
|
|
131
313
|
The assumed resolution of the display device, for the purposes of
|
|
132
314
|
determining the pixel size of the font. Defaults to 96.
|
|
133
315
|
"""
|
|
134
|
-
#
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
316
|
+
# TextLayouts pass `None` for unused style keys from run _FontStyleRunsRangeIterator.
|
|
317
|
+
size = size or 12 # Arbitrary default size
|
|
318
|
+
dpi = dpi or 96
|
|
319
|
+
weight = weight or Weight.NORMAL
|
|
320
|
+
style = style or Style.NORMAL
|
|
321
|
+
stretch = stretch or Stretch.NORMAL
|
|
139
322
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
if not hasattr(shared_object_space, "pyglet_font_font_cache"):
|
|
143
|
-
shared_object_space.pyglet_font_font_cache = weakref.WeakValueDictionary()
|
|
144
|
-
shared_object_space.pyglet_font_font_hold = []
|
|
145
|
-
# Match a tuple to specific name to reduce lookups.
|
|
146
|
-
shared_object_space.pyglet_font_font_name_match = {}
|
|
147
|
-
font_cache = shared_object_space.pyglet_font_font_cache
|
|
148
|
-
font_hold = shared_object_space.pyglet_font_font_hold
|
|
149
|
-
font_name_match = shared_object_space.pyglet_font_font_name_match
|
|
150
|
-
|
|
151
|
-
if isinstance(name, (tuple, list)):
|
|
152
|
-
if isinstance(name, list):
|
|
153
|
-
name = tuple(name)
|
|
154
|
-
if name in font_name_match:
|
|
155
|
-
name = font_name_match[name]
|
|
156
|
-
else:
|
|
157
|
-
# Find first matching name, cache it.
|
|
158
|
-
found_name = None
|
|
159
|
-
for n in name:
|
|
160
|
-
if n in _user_fonts or _system_font_class.have_font(n):
|
|
161
|
-
found_name = n
|
|
162
|
-
break
|
|
323
|
+
if name is None:
|
|
324
|
+
name = manager.get_platform_default_name()
|
|
163
325
|
|
|
164
|
-
|
|
165
|
-
|
|
326
|
+
font_context = manager._get_context_data(core.current_context) # noqa: SLF001
|
|
327
|
+
name = manager.get_resolved_name(name)
|
|
166
328
|
|
|
167
329
|
# Look for font name in font cache
|
|
168
|
-
descriptor = (name, size, weight,
|
|
169
|
-
if descriptor in
|
|
170
|
-
return
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
330
|
+
descriptor = (name, size, weight, style, stretch, dpi)
|
|
331
|
+
if descriptor in font_context.cache:
|
|
332
|
+
return font_context.cache[descriptor]
|
|
333
|
+
|
|
334
|
+
assert weight is not None
|
|
335
|
+
assert style is not None
|
|
336
|
+
assert stretch is not None
|
|
337
|
+
if font_group := manager.get_group(name):
|
|
338
|
+
font = font_group.get_font(size, weight=weight, style=style, stretch=stretch, dpi=dpi)
|
|
339
|
+
else:
|
|
340
|
+
font = _system_font_class(name, size, weight=weight, style=style, stretch=stretch, dpi=dpi)
|
|
174
341
|
|
|
175
|
-
#
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
font.italic = italic
|
|
180
|
-
font.stretch = stretch
|
|
181
|
-
font.dpi = dpi
|
|
342
|
+
# Font system changed the name. Create two descriptors for it, so both can be used.
|
|
343
|
+
if font.name != name:
|
|
344
|
+
fs_descriptor = (font.name, size, weight, style, stretch, dpi)
|
|
345
|
+
font_context.add(fs_descriptor, font)
|
|
182
346
|
|
|
183
347
|
# Cache font in weak-ref dictionary to avoid reloading while still in use
|
|
184
|
-
|
|
185
|
-
# Hold onto refs of last three loaded fonts to prevent them being
|
|
186
|
-
# collected if momentarily dropped.
|
|
187
|
-
del font_hold[3:]
|
|
188
|
-
font_hold.insert(0, font)
|
|
348
|
+
font_context.add(descriptor, font)
|
|
189
349
|
return font
|
|
190
350
|
|
|
191
351
|
|
|
192
352
|
if not getattr(sys, "is_pyglet_doc_run", False):
|
|
193
353
|
_system_font_class = _get_system_font_class()
|
|
194
|
-
_user_fonts = []
|
|
195
354
|
|
|
196
355
|
|
|
197
356
|
def add_file(font: str | BinaryIO | bytes) -> None:
|
|
@@ -215,7 +374,7 @@ def add_file(font: str | BinaryIO | bytes) -> None:
|
|
|
215
374
|
font = open(font, "rb") # noqa: SIM115
|
|
216
375
|
if hasattr(font, "read"):
|
|
217
376
|
font = font.read()
|
|
218
|
-
_system_font_class.add_font_data(font)
|
|
377
|
+
_system_font_class.add_font_data(font, manager)
|
|
219
378
|
|
|
220
379
|
|
|
221
380
|
def add_directory(directory: str) -> None:
|
|
@@ -233,5 +392,12 @@ def add_directory(directory: str) -> None:
|
|
|
233
392
|
if file[-4:].lower() == ".ttf":
|
|
234
393
|
add_file(os.path.join(directory, file))
|
|
235
394
|
|
|
395
|
+
def get_custom_font_names() -> tuple[str, ...]:
|
|
396
|
+
"""The names of font families added to pyglet via :py:func:`~pyglet.font.add_file`.
|
|
397
|
+
|
|
398
|
+
.. versionadded:: 3.0
|
|
399
|
+
"""
|
|
400
|
+
return tuple(manager._added_families) # noqa: SLF001
|
|
401
|
+
|
|
236
402
|
|
|
237
|
-
__all__ = ("
|
|
403
|
+
__all__ = ("add_directory", "add_file", "add_user_font", "get_custom_font_names", "have_font", "load", "manager")
|