Skip to content

Commit

Permalink
Gui/blend text (#2459)
Browse files Browse the repository at this point in the history
* Small cleanup
* Check transparency to determine if background clears the widgets area or use rect draw.
  This can be overwritten by setting UIWidget._strong_background for now.
* override pyglet text blending
  • Loading branch information
eruvanos authored Dec 23, 2024
1 parent 7aa25be commit 4d65b60
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 7 deletions.
21 changes: 15 additions & 6 deletions arcade/gui/widgets/__init__.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
from __future__ import annotations

from abc import ABC
from typing import NamedTuple, Iterable, Optional, Union, TYPE_CHECKING, TypeVar, Tuple, List, Dict
from typing import Dict, Iterable, List, NamedTuple, Optional, TYPE_CHECKING, Tuple, TypeVar, Union

from pyglet.event import EventDispatcher, EVENT_HANDLED, EVENT_UNHANDLED
from pyglet.event import EVENT_HANDLED, EVENT_UNHANDLED, EventDispatcher
from pyglet.math import Vec2
from typing_extensions import Self

import arcade
from arcade import Sprite, Texture, LBWH, Rect
from arcade import LBWH, Rect, Sprite, Texture
from arcade.color import TRANSPARENT_BLACK
from arcade.gui.events import (
UIEvent,
Expand All @@ -19,9 +19,9 @@
UIOnUpdateEvent,
)
from arcade.gui.nine_patch import NinePatchTexture
from arcade.gui.property import Property, bind, ListProperty
from arcade.gui.property import ListProperty, Property, bind
from arcade.gui.surface import Surface
from arcade.types import Color, AnchorPoint, AsFloat
from arcade.types import AnchorPoint, AsFloat, Color
from arcade.utils import copy_dunders_unimplemented

if TYPE_CHECKING:
Expand Down Expand Up @@ -73,6 +73,11 @@ class UIWidget(EventDispatcher, ABC):
_padding_right = Property(0)
_padding_bottom = Property(0)
_padding_left = Property(0)
_strong_background = Property(False)
"""If True, the background will clear the surface, even if it is not fully opaque.
This is not part of the public API and subject to change.
UILabel have a strong background if set.
"""

def __init__(
self,
Expand Down Expand Up @@ -116,6 +121,7 @@ def __init__(
bind(self, "_padding_right", self.trigger_render)
bind(self, "_padding_bottom", self.trigger_render)
bind(self, "_padding_left", self.trigger_render)
bind(self, "_strong_background", self.trigger_render)

def add(self, child: W, **kwargs) -> W:
"""Add a widget as a child.
Expand Down Expand Up @@ -253,7 +259,10 @@ def do_render_base(self, surface: Surface):

# draw background
if self._bg_color:
surface.clear(self._bg_color)
if self._bg_color.a == 255 or self._strong_background:
surface.clear(self._bg_color)
else:
arcade.draw_rect_filled(LBWH(0, 0, self.width, self.height), color=self._bg_color)
# draw background texture
if self._bg_tex:
surface.draw_texture(x=0, y=0, width=self.width, height=self.height, tex=self._bg_tex)
Expand Down
2 changes: 2 additions & 0 deletions arcade/gui/widgets/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ def __init__(
multiline=multiline,
**kwargs,
)
self._strong_background = True

if adaptive_multiline:
# +1 is required to prevent line wrap
width = self._label.content_width + 1
Expand Down
60 changes: 59 additions & 1 deletion arcade/text.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

from __future__ import annotations

from ctypes import c_int, c_ubyte
from pathlib import Path
from typing import Any, Union

Expand All @@ -18,6 +19,62 @@
__all__ = ["load_font", "Text", "create_text_sprite", "draw_text"]


class _ArcadeTextLayoutGroup(pyglet.text.layout.TextLayoutGroup):
"""Create a text layout rendering group.
Overrides pyglet blending handling to allow for additive blending.
Furthermore, it resets the blend function to the previous state.
"""

_prev_blend: bool
_prev_blend_func: tuple[int, int, int, int]

def set_state(self) -> None:
self.program.use()
self.program["scissor"] = False

pyglet.gl.glActiveTexture(pyglet.gl.GL_TEXTURE0)
pyglet.gl.glBindTexture(self.texture.target, self.texture.id)

blend = c_ubyte()
pyglet.gl.glGetBooleanv(pyglet.gl.GL_BLEND, blend)
self._prev_blend = bool(blend.value)

src_rgb = c_int()
dst_rgb = c_int()
src_alpha = c_int()
dst_alpha = c_int()
pyglet.gl.glGetIntegerv(pyglet.gl.GL_BLEND_SRC_RGB, src_rgb)
pyglet.gl.glGetIntegerv(pyglet.gl.GL_BLEND_DST_RGB, dst_rgb)
pyglet.gl.glGetIntegerv(pyglet.gl.GL_BLEND_SRC_ALPHA, src_alpha)
pyglet.gl.glGetIntegerv(pyglet.gl.GL_BLEND_DST_ALPHA, dst_alpha)

self._prev_blend_func = (src_rgb.value, dst_rgb.value, src_alpha.value, dst_alpha.value)

pyglet.gl.glEnable(pyglet.gl.GL_BLEND)
pyglet.gl.glBlendFuncSeparate(
pyglet.gl.GL_SRC_ALPHA,
pyglet.gl.GL_ONE_MINUS_SRC_ALPHA,
pyglet.gl.GL_ONE,
pyglet.gl.GL_ONE,
)

def unset_state(self) -> None:
if not self._prev_blend:
pyglet.gl.glDisable(pyglet.gl.GL_BLEND)

pyglet.gl.glBlendFuncSeparate(
self._prev_blend_func[0],
self._prev_blend_func[1],
self._prev_blend_func[2],
self._prev_blend_func[3],
)
self.program.stop()


pyglet.text.layout.TextLayout.group_class = _ArcadeTextLayoutGroup


def load_font(path: str | Path) -> None:
"""
Load fonts in a file (usually .ttf) adding them to a global font registry.
Expand Down Expand Up @@ -253,7 +310,8 @@ def __init__(
bold=bold,
italic=italic,
multiline=multiline,
rotation=rotation, # type: ignore # pending https://github.com/pyglet/pyglet/issues/843
rotation=rotation,
# type: ignore # pending https://github.com/pyglet/pyglet/issues/843
batch=batch,
group=group,
**kwargs,
Expand Down

0 comments on commit 4d65b60

Please sign in to comment.