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/text/layout/base.py
CHANGED
|
@@ -14,26 +14,14 @@ from typing import (
|
|
|
14
14
|
)
|
|
15
15
|
|
|
16
16
|
import pyglet
|
|
17
|
+
|
|
17
18
|
from pyglet import graphics
|
|
18
|
-
from pyglet.
|
|
19
|
-
from pyglet.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
GL_DEPTH_COMPONENT,
|
|
23
|
-
GL_LINES,
|
|
24
|
-
GL_NEAREST,
|
|
25
|
-
GL_ONE_MINUS_SRC_ALPHA,
|
|
26
|
-
GL_SRC_ALPHA,
|
|
27
|
-
GL_TEXTURE0,
|
|
28
|
-
GL_TRIANGLES,
|
|
29
|
-
glActiveTexture,
|
|
30
|
-
glBindTexture,
|
|
31
|
-
glBlendFunc,
|
|
32
|
-
glDisable,
|
|
33
|
-
glEnable,
|
|
34
|
-
)
|
|
35
|
-
from pyglet.graphics import Group
|
|
19
|
+
from pyglet.enums import BlendFactor
|
|
20
|
+
from pyglet.graphics import GeometryMode, Group, ShaderProgram
|
|
21
|
+
from pyglet.graphics.draw import Group
|
|
22
|
+
from pyglet.graphics.texture import TextureBase
|
|
36
23
|
from pyglet.text import runlist
|
|
24
|
+
from pyglet.font.base import GlyphPosition
|
|
37
25
|
|
|
38
26
|
if TYPE_CHECKING:
|
|
39
27
|
from pyglet.customtypes import AnchorX, AnchorY, ContentVAlign, HorizontalAlign
|
|
@@ -41,161 +29,135 @@ if TYPE_CHECKING:
|
|
|
41
29
|
from pyglet.graphics import Batch
|
|
42
30
|
from pyglet.graphics.shader import ShaderProgram
|
|
43
31
|
from pyglet.graphics.vertexdomain import VertexList
|
|
44
|
-
from pyglet.
|
|
32
|
+
from pyglet.graphics import Texture
|
|
45
33
|
from pyglet.text.document import AbstractDocument, InlineElement
|
|
46
34
|
from pyglet.text.runlist import AbstractRunIterator, RunIterator
|
|
47
35
|
|
|
48
36
|
_is_pyglet_doc_run = hasattr(sys, "is_pyglet_doc_run") and sys.is_pyglet_doc_run
|
|
49
37
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
{
|
|
130
|
-
final_colors = texture(image_texture, texture_coords.xy);
|
|
131
|
-
if (scissor == true) {
|
|
132
|
-
if (vert_position.x < scissor_area[0]) discard; // left
|
|
133
|
-
if (vert_position.y < scissor_area[1]) discard; // bottom
|
|
134
|
-
if (vert_position.x > scissor_area[0] + scissor_area[2]) discard; // right
|
|
135
|
-
if (vert_position.y > scissor_area[1] + scissor_area[3]) discard; // top
|
|
38
|
+
if pyglet.options.backend in ("opengl", "gles3"):
|
|
39
|
+
from pyglet.graphics.api.gl.text import (
|
|
40
|
+
get_default_decoration_shader,
|
|
41
|
+
get_default_image_layout_shader,
|
|
42
|
+
get_default_layout_shader,
|
|
43
|
+
)
|
|
44
|
+
elif pyglet.options.backend in ("gl2", "gles2"):
|
|
45
|
+
from pyglet.graphics.api.gl2.text import (
|
|
46
|
+
get_default_decoration_shader,
|
|
47
|
+
get_default_image_layout_shader,
|
|
48
|
+
get_default_layout_shader,
|
|
49
|
+
)
|
|
50
|
+
elif pyglet.options.backend == "webgl":
|
|
51
|
+
from pyglet.graphics.api.webgl.text import (
|
|
52
|
+
get_default_decoration_shader,
|
|
53
|
+
get_default_image_layout_shader, # noqa: F401
|
|
54
|
+
get_default_layout_shader,
|
|
55
|
+
)
|
|
56
|
+
elif pyglet.options.backend == "vulkan":
|
|
57
|
+
from pyglet.graphics.api.vulkan.text import (
|
|
58
|
+
get_default_decoration_shader,
|
|
59
|
+
get_default_layout_shader,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class TextLayoutGroup(Group):
|
|
64
|
+
"""Create a text layout rendering group.
|
|
65
|
+
|
|
66
|
+
The group is created internally when a :py:class:`~pyglet.text.Label`
|
|
67
|
+
is created; applications usually do not need to explicitly create it.
|
|
68
|
+
"""
|
|
69
|
+
|
|
70
|
+
def __init__(self, texture: TextureBase, program: ShaderProgram, order: int = 1, # noqa: D107
|
|
71
|
+
parent: Group | None = None) -> None:
|
|
72
|
+
super().__init__(order=order, parent=parent)
|
|
73
|
+
self.uniforms = {"scissor": False}
|
|
74
|
+
self.texture = texture
|
|
75
|
+
self.set_shader_program(program)
|
|
76
|
+
self.set_blend(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA)
|
|
77
|
+
self.set_texture(texture, 0)
|
|
78
|
+
self.set_shader_uniforms(program, self.uniforms)
|
|
79
|
+
|
|
80
|
+
def __repr__(self) -> str:
|
|
81
|
+
return f"{self.__class__.__name__}({self.texture})"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class TextDecorationGroup(Group):
|
|
85
|
+
"""Create a text decoration rendering group.
|
|
86
|
+
|
|
87
|
+
The group is created internally when a :py:class:`~pyglet.text.Label`
|
|
88
|
+
is created; applications usually do not need to explicitly create it.
|
|
89
|
+
"""
|
|
90
|
+
|
|
91
|
+
def __init__(self, program: ShaderProgram, order: int = 0, # noqa: D107
|
|
92
|
+
parent: Group | None = None) -> None:
|
|
93
|
+
super().__init__(order=order, parent=parent)
|
|
94
|
+
self.uniforms = {"scissor": False}
|
|
95
|
+
self.set_shader_program(program)
|
|
96
|
+
self.set_blend(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA)
|
|
97
|
+
self.set_shader_uniforms(program, self.uniforms)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
class ScrollableTextLayoutGroup(Group):
|
|
101
|
+
"""Default rendering group for :py:class:`~pyglet.text.layout.ScrollableTextLayout`.
|
|
102
|
+
|
|
103
|
+
The group maintains internal state for specifying the viewable
|
|
104
|
+
area, and for scrolling. Because the group has internal state
|
|
105
|
+
specific to the text layout, the group is never shared.
|
|
106
|
+
"""
|
|
107
|
+
scissor_area: ClassVar[tuple[int, int, int, int]] = 0, 0, 0, 0
|
|
108
|
+
|
|
109
|
+
def __init__(self, texture: TextureBase, program: ShaderProgram, order: int = 1, # noqa: D107
|
|
110
|
+
parent: Group | None = None) -> None:
|
|
111
|
+
|
|
112
|
+
super().__init__(order=order, parent=parent)
|
|
113
|
+
self.texture = texture
|
|
114
|
+
self.uniforms = {
|
|
115
|
+
"scissor": True,
|
|
116
|
+
"scissor_area": self.scissor_area,
|
|
136
117
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
m_rotation[0][1] = sin(-radians(rotation));
|
|
170
|
-
m_rotation[1][0] = -sin(-radians(rotation));
|
|
171
|
-
m_rotation[1][1] = cos(-radians(rotation));
|
|
172
|
-
|
|
173
|
-
gl_Position = window.projection * window.view * m_translate * m_anchor * m_rotation * vec4(position + view_translation + v_anchor, 1.0) * visible;
|
|
174
|
-
|
|
175
|
-
vert_position = vec4(position + translation + view_translation + v_anchor, 1.0);
|
|
176
|
-
vert_colors = colors;
|
|
177
|
-
}
|
|
178
|
-
""" # noqa: E501
|
|
179
|
-
decoration_fragment_source = """#version 330 core
|
|
180
|
-
in vec4 vert_colors;
|
|
181
|
-
in vec4 vert_position;
|
|
182
|
-
|
|
183
|
-
out vec4 final_colors;
|
|
184
|
-
|
|
185
|
-
uniform bool scissor;
|
|
186
|
-
uniform vec4 scissor_area;
|
|
187
|
-
|
|
188
|
-
void main()
|
|
189
|
-
{
|
|
190
|
-
final_colors = vert_colors;
|
|
191
|
-
if (scissor == true) {
|
|
192
|
-
if (vert_position.x < scissor_area[0]) discard; // left
|
|
193
|
-
if (vert_position.y < scissor_area[1]) discard; // bottom
|
|
194
|
-
if (vert_position.x > scissor_area[0] + scissor_area[2]) discard; // right
|
|
195
|
-
if (vert_position.y > scissor_area[1] + scissor_area[3]) discard; // top
|
|
118
|
+
self.set_shader_program(program)
|
|
119
|
+
self.set_blend(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA)
|
|
120
|
+
self.set_texture(texture, 0)
|
|
121
|
+
self.set_shader_uniforms(program, self.uniforms)
|
|
122
|
+
|
|
123
|
+
def __repr__(self) -> str:
|
|
124
|
+
return f"{self.__class__.__name__}({self.texture})"
|
|
125
|
+
|
|
126
|
+
def __eq__(self, other: object) -> bool:
|
|
127
|
+
return self is other
|
|
128
|
+
|
|
129
|
+
def __hash__(self) -> int:
|
|
130
|
+
return id(self)
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class ScrollableTextDecorationGroup(Group):
|
|
134
|
+
"""Create a text decoration rendering group.
|
|
135
|
+
|
|
136
|
+
The group is created internally when a :py:class:`~pyglet.text.Label`
|
|
137
|
+
is created; applications usually do not need to explicitly create it.
|
|
138
|
+
"""
|
|
139
|
+
|
|
140
|
+
scissor_area: ClassVar[tuple[int, int, int, int]] = 0, 0, 0, 0
|
|
141
|
+
|
|
142
|
+
def __init__(self, program: ShaderProgram, order: int = 0, parent: Group | None = None) -> None: # noqa: D107
|
|
143
|
+
super().__init__(order=order, parent=parent)
|
|
144
|
+
self.program = program
|
|
145
|
+
self.set_shader_program(program)
|
|
146
|
+
self.set_blend(BlendFactor.SRC_ALPHA, BlendFactor.ONE_MINUS_SRC_ALPHA)
|
|
147
|
+
self.uniforms = {
|
|
148
|
+
"scissor": True,
|
|
149
|
+
"scissor_area": self.scissor_area,
|
|
196
150
|
}
|
|
197
|
-
|
|
198
|
-
|
|
151
|
+
self.set_shader_uniforms(program, self.uniforms)
|
|
152
|
+
|
|
153
|
+
def __repr__(self) -> str:
|
|
154
|
+
return f"{self.__class__.__name__}(scissor={self.scissor_area})"
|
|
155
|
+
|
|
156
|
+
def __eq__(self, other: object) -> bool:
|
|
157
|
+
return self is other
|
|
158
|
+
|
|
159
|
+
def __hash__(self) -> int:
|
|
160
|
+
return id(self)
|
|
199
161
|
|
|
200
162
|
|
|
201
163
|
class _LayoutVertexList(Protocol):
|
|
@@ -212,24 +174,6 @@ class _LayoutVertexList(Protocol):
|
|
|
212
174
|
def delete(self) -> None: ...
|
|
213
175
|
|
|
214
176
|
|
|
215
|
-
def get_default_layout_shader() -> ShaderProgram:
|
|
216
|
-
"""The default shader used for all glyphs in the layout."""
|
|
217
|
-
return pyglet.gl.current_context.create_program((layout_vertex_source, "vertex"),
|
|
218
|
-
(layout_fragment_source, "fragment"))
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
def get_default_image_layout_shader() -> ShaderProgram:
|
|
222
|
-
"""The default shader used for an InlineElement image. Used for HTML Labels that insert images via <img> tag."""
|
|
223
|
-
return pyglet.gl.current_context.create_program((layout_vertex_source, "vertex"),
|
|
224
|
-
(layout_fragment_image_source, "fragment"))
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
def get_default_decoration_shader() -> ShaderProgram:
|
|
228
|
-
"""The default shader for underline and background decoration effects in the layout."""
|
|
229
|
-
return pyglet.gl.current_context.create_program((decoration_vertex_source, "vertex"),
|
|
230
|
-
(decoration_fragment_source, "fragment"))
|
|
231
|
-
|
|
232
|
-
|
|
233
177
|
_distance_re: Pattern[str] = re.compile(r"([-0-9.]+)([a-zA-Z]+)")
|
|
234
178
|
|
|
235
179
|
|
|
@@ -496,10 +440,12 @@ class _GlyphBox(_AbstractBox):
|
|
|
496
440
|
|
|
497
441
|
t_position = (x, y, z)
|
|
498
442
|
|
|
499
|
-
vertex_list = layout.program.vertex_list_indexed(n_glyphs * 4,
|
|
443
|
+
vertex_list = layout.program.vertex_list_indexed(n_glyphs * 4, GeometryMode.TRIANGLES, indices, layout.batch,
|
|
444
|
+
group,
|
|
500
445
|
position=("f", vertices),
|
|
501
446
|
translation=("f", t_position * 4 * n_glyphs),
|
|
502
447
|
colors=("Bn", colors),
|
|
448
|
+
view_translation=('f', ((0, 0, 0) * 4 * n_glyphs)),
|
|
503
449
|
tex_coords=("f", tex_coords),
|
|
504
450
|
rotation=("f", ((rotation,) * 4) * n_glyphs),
|
|
505
451
|
visible=("f", ((visible,) * 4) * n_glyphs),
|
|
@@ -548,10 +494,12 @@ class _GlyphBox(_AbstractBox):
|
|
|
548
494
|
bg_count = len(background_vertices) // 3
|
|
549
495
|
background_indices = [(0, 1, 2, 0, 2, 3)[i % 6] for i in range(bg_count * 3)]
|
|
550
496
|
decoration_program = get_default_decoration_shader()
|
|
551
|
-
background_list = decoration_program.vertex_list_indexed(bg_count,
|
|
497
|
+
background_list = decoration_program.vertex_list_indexed(bg_count, GeometryMode.TRIANGLES,
|
|
498
|
+
background_indices,
|
|
552
499
|
layout.batch, layout.background_decoration_group,
|
|
553
500
|
position=("f", background_vertices),
|
|
554
501
|
translation=("f", t_position * bg_count),
|
|
502
|
+
view_translation=('f', (0, 0, 0) * bg_count),
|
|
555
503
|
colors=("Bn", background_colors),
|
|
556
504
|
rotation=("f", (rotation,) * bg_count),
|
|
557
505
|
visible=("f", (visible,) * bg_count),
|
|
@@ -561,10 +509,11 @@ class _GlyphBox(_AbstractBox):
|
|
|
561
509
|
if underline_vertices:
|
|
562
510
|
ul_count = len(underline_vertices) // 3
|
|
563
511
|
decoration_program = get_default_decoration_shader()
|
|
564
|
-
underline_list = decoration_program.vertex_list(ul_count,
|
|
512
|
+
underline_list = decoration_program.vertex_list(ul_count, GeometryMode.LINES,
|
|
565
513
|
layout.batch, layout.foreground_decoration_group,
|
|
566
514
|
position=("f", underline_vertices),
|
|
567
515
|
translation=("f", t_position * ul_count),
|
|
516
|
+
view_translation=('f', (0, 0, 0) * ul_count),
|
|
568
517
|
colors=("Bn", underline_colors),
|
|
569
518
|
rotation=("f", (rotation,) * ul_count),
|
|
570
519
|
visible=("f", (visible,) * ul_count),
|
|
@@ -603,7 +552,7 @@ class _GlyphBox(_AbstractBox):
|
|
|
603
552
|
def update_rotation(self, rotation: float) -> None:
|
|
604
553
|
rot = (rotation,)
|
|
605
554
|
for _vertex_list in self.vertex_lists:
|
|
606
|
-
_vertex_list.rotation[:] = rot * _vertex_list.count
|
|
555
|
+
_vertex_list.rotation[:] = (rot * _vertex_list.count)
|
|
607
556
|
|
|
608
557
|
def update_visibility(self, visible: bool) -> None:
|
|
609
558
|
visible_tuple = (visible,)
|
|
@@ -657,7 +606,7 @@ class _InlineElementBox(_AbstractBox):
|
|
|
657
606
|
# Determines if the box is visible.
|
|
658
607
|
self.placed = False
|
|
659
608
|
|
|
660
|
-
def place(self, layout: TextLayout, i: int, x: float, y: float, z: float, line_x: float, line_y: float,
|
|
609
|
+
def place(self, layout: TextLayout, i: int, x: float, y: float, z: float, line_x: float, line_y: float,
|
|
661
610
|
rotation: float, visible: bool, anchor_x: float, anchor_y: float,
|
|
662
611
|
context: _LayoutContext) -> None: # noqa: ARG002
|
|
663
612
|
self.element.place(layout, x, y, z, line_x, line_y, rotation, visible, anchor_x, anchor_y)
|
|
@@ -751,75 +700,11 @@ class _InvalidRange:
|
|
|
751
700
|
return self.end > self.start
|
|
752
701
|
|
|
753
702
|
|
|
754
|
-
class TextLayoutGroup(graphics.Group):
|
|
755
|
-
"""Create a text layout rendering group.
|
|
756
|
-
|
|
757
|
-
The group is created internally when a :py:class:`~pyglet.text.Label`
|
|
758
|
-
is created; applications usually do not need to explicitly create it.
|
|
759
|
-
"""
|
|
760
|
-
|
|
761
|
-
def __init__(self, texture: Texture, program: ShaderProgram, order: int = 1, # noqa: D107
|
|
762
|
-
parent: graphics.Group | None = None) -> None:
|
|
763
|
-
super().__init__(order=order, parent=parent)
|
|
764
|
-
self.texture = texture
|
|
765
|
-
self.program = program
|
|
766
|
-
|
|
767
|
-
def set_state(self) -> None:
|
|
768
|
-
self.program.use()
|
|
769
|
-
self.program["scissor"] = False
|
|
770
|
-
|
|
771
|
-
glActiveTexture(GL_TEXTURE0)
|
|
772
|
-
glBindTexture(self.texture.target, self.texture.id)
|
|
773
|
-
|
|
774
|
-
glEnable(GL_BLEND)
|
|
775
|
-
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
|
776
|
-
|
|
777
|
-
def unset_state(self) -> None:
|
|
778
|
-
glDisable(GL_BLEND)
|
|
779
|
-
self.program.stop()
|
|
780
|
-
|
|
781
|
-
def __repr__(self) -> str:
|
|
782
|
-
return f"{self.__class__.__name__}({self.texture})"
|
|
783
|
-
|
|
784
|
-
def __eq__(self, other: object) -> bool:
|
|
785
|
-
return (other.__class__ is self.__class__ and
|
|
786
|
-
self.parent is other.parent and
|
|
787
|
-
self.program.id is other.program.id and
|
|
788
|
-
self.order == other.order and
|
|
789
|
-
self.texture.target == other.texture.target and
|
|
790
|
-
self.texture.id == other.texture.id)
|
|
791
|
-
|
|
792
|
-
def __hash__(self) -> int:
|
|
793
|
-
return hash((id(self.parent), self.program.id, self.order, self.texture.target, self.texture.id))
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
class TextDecorationGroup(Group):
|
|
797
|
-
"""Create a text decoration rendering group.
|
|
798
|
-
|
|
799
|
-
The group is created internally when a :py:class:`~pyglet.text.Label`
|
|
800
|
-
is created; applications usually do not need to explicitly create it.
|
|
801
|
-
"""
|
|
802
|
-
|
|
803
|
-
def __init__(self, program: ShaderProgram, order: int = 0, # noqa: D107
|
|
804
|
-
parent: graphics.Group | None = None) -> None:
|
|
805
|
-
super().__init__(order=order, parent=parent)
|
|
806
|
-
self.program = program
|
|
807
|
-
|
|
808
|
-
def set_state(self) -> None:
|
|
809
|
-
self.program.use()
|
|
810
|
-
self.program["scissor"] = False
|
|
811
|
-
|
|
812
|
-
glEnable(GL_BLEND)
|
|
813
|
-
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
|
|
814
|
-
|
|
815
|
-
def unset_state(self) -> None:
|
|
816
|
-
glDisable(GL_BLEND)
|
|
817
|
-
self.program.stop()
|
|
818
|
-
|
|
819
703
|
|
|
820
704
|
# Just have one object for empty positions in layout. It won't be modified.
|
|
821
705
|
_empty_pos = GlyphPosition(0, 0, 0, 0)
|
|
822
706
|
|
|
707
|
+
|
|
823
708
|
class TextLayout:
|
|
824
709
|
"""Lay out and display documents.
|
|
825
710
|
|
|
@@ -873,7 +758,7 @@ class TextLayout:
|
|
|
873
758
|
anchor_x: AnchorX = 'left', anchor_y: AnchorY = 'bottom', rotation: float = 0,
|
|
874
759
|
multiline: bool = False, dpi: float | None = None, batch: Batch | None = None,
|
|
875
760
|
group: graphics.Group | None = None, program: ShaderProgram | None = None,
|
|
876
|
-
wrap_lines: bool = True, init_document: bool = True) -> None:
|
|
761
|
+
wrap_lines: bool = True, shaping: bool = True, init_document: bool = True) -> None:
|
|
877
762
|
"""Create a text layout.
|
|
878
763
|
|
|
879
764
|
Args:
|
|
@@ -913,6 +798,9 @@ class TextLayout:
|
|
|
913
798
|
Optional graphics shader to use. Will affect all glyphs in the layout.
|
|
914
799
|
wrap_lines:
|
|
915
800
|
If True and `multiline` is True, the text is word-wrapped using the specified width.
|
|
801
|
+
shaping:
|
|
802
|
+
If the text should use proper positioning and typography according to the font and global
|
|
803
|
+
``pyglet.options.text_shaping`` option. If ``False``, metrics will instead be tied to the glyph sizes.
|
|
916
804
|
init_document:
|
|
917
805
|
If True the document will be initialized. If subclassing then
|
|
918
806
|
you may want to avoid duplicate initializations by changing to False.
|
|
@@ -927,6 +815,7 @@ class TextLayout:
|
|
|
927
815
|
self._rotation = rotation
|
|
928
816
|
self._multiline = multiline
|
|
929
817
|
self._dpi = dpi or 96
|
|
818
|
+
self._shaping = shaping
|
|
930
819
|
|
|
931
820
|
self._content_width = 0
|
|
932
821
|
self._content_height = 0
|
|
@@ -939,7 +828,6 @@ class TextLayout:
|
|
|
939
828
|
# Boxes are all existing _AbstractBoxes, these are used to gather line information.
|
|
940
829
|
# Note that this is only relevant to layouts that do not store directly on lines.
|
|
941
830
|
self._boxes = []
|
|
942
|
-
self._lines = []
|
|
943
831
|
|
|
944
832
|
#: :meta private:
|
|
945
833
|
self.group_cache = {}
|
|
@@ -947,7 +835,8 @@ class TextLayout:
|
|
|
947
835
|
self._initialize_groups()
|
|
948
836
|
|
|
949
837
|
if batch is None:
|
|
950
|
-
batch = graphics.Batch()
|
|
838
|
+
batch = pyglet.graphics.Batch()
|
|
839
|
+
# Create a batch as some text elements may require being drawn together.
|
|
951
840
|
self._own_batch = True
|
|
952
841
|
self._batch = batch
|
|
953
842
|
|
|
@@ -1022,7 +911,7 @@ class TextLayout:
|
|
|
1022
911
|
return
|
|
1023
912
|
|
|
1024
913
|
if batch is None:
|
|
1025
|
-
self._batch = graphics.Batch()
|
|
914
|
+
self._batch = pyglet.graphics.Batch()
|
|
1026
915
|
self._own_batch = True
|
|
1027
916
|
self._update()
|
|
1028
917
|
elif batch is not None:
|
|
@@ -1140,11 +1029,10 @@ class TextLayout:
|
|
|
1140
1029
|
|
|
1141
1030
|
anchor_y = self._get_top_anchor()
|
|
1142
1031
|
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
acc_anchor_x += box.advance
|
|
1032
|
+
acc_anchor_x = self._anchor_left
|
|
1033
|
+
for box in self._boxes:
|
|
1034
|
+
box.update_anchor(acc_anchor_x, anchor_y)
|
|
1035
|
+
acc_anchor_x += box.advance
|
|
1148
1036
|
|
|
1149
1037
|
@property
|
|
1150
1038
|
def visible(self) -> bool:
|
|
@@ -1391,7 +1279,7 @@ class TextLayout:
|
|
|
1391
1279
|
self._vertex_lists.clear()
|
|
1392
1280
|
self._boxes.clear()
|
|
1393
1281
|
|
|
1394
|
-
def get_as_texture(self
|
|
1282
|
+
def get_as_texture(self) -> Texture:
|
|
1395
1283
|
"""Utilizes a :py:class:`~pyglet.image.framebuffer.Framebuffer` to draw the current layout into a texture.
|
|
1396
1284
|
|
|
1397
1285
|
.. warning:: Usage is recommended only if you understand how texture generation affects your application.
|
|
@@ -1404,22 +1292,23 @@ class TextLayout:
|
|
|
1404
1292
|
|
|
1405
1293
|
.. versionadded:: 2.0.11
|
|
1406
1294
|
"""
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
framebuffer.
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1295
|
+
raise NotImplementedError
|
|
1296
|
+
# framebuffer = pyglet.image.Framebuffer()
|
|
1297
|
+
# temp_pos = self.position
|
|
1298
|
+
# width = int(round(self._content_width))
|
|
1299
|
+
# height = int(round(self._content_height))
|
|
1300
|
+
# texture = pyglet.graphics.Texture.create(width, height, texture_desc)
|
|
1301
|
+
# depth_buffer = pyglet.image.buffer.Renderbuffer(width, height, GL_DEPTH_COMPONENT)
|
|
1302
|
+
# framebuffer.attach_texture(texture)
|
|
1303
|
+
# framebuffer.attach_renderbuffer(depth_buffer, attachment=GL_DEPTH_ATTACHMENT)
|
|
1304
|
+
#
|
|
1305
|
+
# self.position = (0 - self._anchor_left, 0 - self._anchor_bottom, 0)
|
|
1306
|
+
# framebuffer.bind()
|
|
1307
|
+
# self.draw()
|
|
1308
|
+
# framebuffer.unbind()
|
|
1309
|
+
#
|
|
1310
|
+
# self.position = temp_pos
|
|
1311
|
+
# return texture
|
|
1423
1312
|
|
|
1424
1313
|
def draw(self) -> None:
|
|
1425
1314
|
"""Draw this text layout.
|
|
@@ -1455,8 +1344,7 @@ class TextLayout:
|
|
|
1455
1344
|
|
|
1456
1345
|
self._vertex_lists.clear()
|
|
1457
1346
|
self._boxes.clear()
|
|
1458
|
-
self.
|
|
1459
|
-
self.group_cache.clear()
|
|
1347
|
+
#self.group_cache.clear()
|
|
1460
1348
|
|
|
1461
1349
|
if not self._document or not self._document.text:
|
|
1462
1350
|
self._ascent = 0
|
|
@@ -1465,9 +1353,9 @@ class TextLayout:
|
|
|
1465
1353
|
self._anchor_bottom = 0
|
|
1466
1354
|
return
|
|
1467
1355
|
|
|
1468
|
-
|
|
1469
|
-
self._ascent =
|
|
1470
|
-
self._descent =
|
|
1356
|
+
lines = self._get_lines()
|
|
1357
|
+
self._ascent = lines[0].ascent
|
|
1358
|
+
self._descent = lines[0].descent
|
|
1471
1359
|
|
|
1472
1360
|
colors_iter = self._document.get_style_runs("color")
|
|
1473
1361
|
|
|
@@ -1479,7 +1367,7 @@ class TextLayout:
|
|
|
1479
1367
|
|
|
1480
1368
|
context = _StaticLayoutContext(self, self._document, colors_iter, background_iter)
|
|
1481
1369
|
|
|
1482
|
-
for line in
|
|
1370
|
+
for line in lines:
|
|
1483
1371
|
self._boxes.extend(line.boxes)
|
|
1484
1372
|
self._create_vertex_lists(line.x, line.y, self._anchor_left, anchor_top, line.start, line.boxes, context)
|
|
1485
1373
|
|
|
@@ -1633,7 +1521,7 @@ class TextLayout:
|
|
|
1633
1521
|
glyphs.append(_InlineElementBox(element))
|
|
1634
1522
|
offsets.append(_empty_pos)
|
|
1635
1523
|
else:
|
|
1636
|
-
char_glyphs, char_offsets = font.get_glyphs(text[start:end])
|
|
1524
|
+
char_glyphs, char_offsets = font.get_glyphs(text[start:end], self._shaping)
|
|
1637
1525
|
glyphs.extend(char_glyphs)
|
|
1638
1526
|
offsets.extend(char_offsets)
|
|
1639
1527
|
|
|
@@ -2009,3 +1897,4 @@ class TextLayout:
|
|
|
2009
1897
|
def get_line_count(self) -> int:
|
|
2010
1898
|
"""Get the number of lines in the text layout."""
|
|
2011
1899
|
return self._line_count
|
|
1900
|
+
|