kxgames / glooey

An object-oriented GUI library for pyglet.
MIT License
91 stars 6 forks source link

Transparent Primative Widgets? #58

Closed Rahuum closed 2 years ago

Rahuum commented 2 years ago

I'm trying to create a transparent/overlay widget that is a primitive gradient. The idea is that it can be used with Stack() and Background() to create an adjustable size background with a gradient effect overlayed on it, that replaces Background().

An example of what a UI might look like with/without: image image

It's a tiny thing, but there's no way to 'pre build' it with arbitrary size frames/dialogs/buttons/etc.

Right now I'm focusing on making the class Gradient, and then later I'll make GradientBackground() that stacks a Gradient() on top of a Background()

Right now, the gradient is being properly made/applied, but there's no transparency at all, let alone an opportunity to do an overlay-style operation.

Right now the transparency is hardcoded to 50%

@autoprop
class Gradient(glooey.Widget):
    custom_alignment = 'fill'

    def __init__(self, min_width=0, min_height=0, color1='#000000', color2='#FFFFFF', align=None):
        super().__init__()
        self._min_height = min_height
        self._min_width = min_width
        self._color1 = glooey.drawing.Color.from_anything(color1)
        self._color1.a = self._color1.a // 2
        self._color2 = glooey.drawing.Color.from_anything(color2)
        self._color2.a = self._color2.a // 2
        self._mid_color = glooey.drawing.Color((self._color1.r + self._color2.r) // 2,
                                               (self._color1.g + self._color2.g) // 2,
                                               (self._color1.b + self._color2.b) // 2,
                                               (self._color1.a + self._color2.a) // 2)
        self.vertex_list = None
        self.alignment = align or self.custom_alignment

    def do_claim(self):
        return self._min_width, self._min_height

    def do_regroup(self):
        if self.vertex_list is not None:
            self.batch.migrate(self.vertex_list, pyglet.gl.GL_TRIANGLE_STRIP, self.group, self.batch)

    def do_draw(self):
        if self.vertex_list is None:
            self.vertex_list = self.batch.add(5, pyglet.gl.GL_TRIANGLE_STRIP, self.group, 'v2f/static', 
                                              'c4B/static')

        rect = self.rect.get_shrunk(0.5)
        self.vertex_list.vertices = (
            rect.bottom_left.tuple +
            (rect.bottom_right + (1,0)).tuple +
            rect.top_right.tuple +
            rect.top_left.tuple +
            rect.bottom_left.tuple
        )
        self.vertex_list.colors = (self._color1.tuple + self._mid_color.tuple + self._color2.tuple 
                                   + self._mid_color.tuple + self._color1.tuple)

    def set_state(self):
        pyglet.gl.glEnable(pyglet.gl.GL_BLEND)
        pyglet.gl.glBlendFunc(pyglet.gl.GL_SRC_ALPHA, pyglet.gl.GL_ONE_MINUS_SRC_ALPHA)

    def unset_state(self):
        pyglet.gl.glDisable(pyglet.gl.GL_BLEND)

    def do_undraw(self):
        if self.vertex_list is not None:
            self.vertex_list.delete()
            self.vertex_list = None

    def get_min_width(self):
        return self._min_width

    def set_min_width(self, new_width):
        self._min_width = new_width
        self._repack()

    def get_min_height(self):
        self._min_height = new_height
        self._repack()

Right now it's rendering the gradient just fine: image It's just not seeming to respect the blend mode.

Are there any immediately obvious mistakes, or gotchas you can think of in glooey, that would prevent a transparent/blend mode primitive widget from being rendered properly?

Thanks!

Rahuum commented 2 years ago

The issue was the set_state and unset_state are only or pyglet groups, not Widgets.

kalekundert commented 2 years ago

Glad you found the mistake. This seems like a generally useful primitive, so if you're interested in making a PR, I'd be happy to merge it.