Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a UI element which able to render raw pygame surface #662

Open
TheKruger opened this issue Dec 30, 2024 · 8 comments
Open

Add a UI element which able to render raw pygame surface #662

TheKruger opened this issue Dec 30, 2024 · 8 comments
Labels
enhancement New feature or request

Comments

@TheKruger
Copy link

Is your feature request related to a problem? Please describe.
Currently pygame_gui doesn't have plots, so I made a simple class which draws a plot surface, but I couldn't find a way to add it to the base UIElement class. I would simply use the rendered plot surface, inside the UIElement to render the plot, but as far as I know I can't.

Describe the solution you'd like
A simple UISurfaceElement which can render raw pygame surface would be cool. I didn't dig into the code too much, so I don't know if this is even possible.

Describe alternatives you've considered
None

Additional context
A simple code example that I came up with:

import pygame
import pygame_gui

class UIPlot(pygame.elements.UISurfaceElement):
    def __init__(self, rect, manager, container):
        super().__init__(rect, manager, container)

        # My own surface
        self.plot_surface = pygame.Surface((self.rect.width, self.rect.height))

    def draw(self):
        # An internal surface inside the UISurfaceElement
        self.surface.blit(self.plot_surface, (0, 0))
@TheKruger TheKruger added the enhancement New feature or request label Dec 30, 2024
@MyreMylar
Copy link
Owner

I believe what you want is UIImage :

https://github.com/MyreMylar/pygame_gui/blob/main/pygame_gui/elements/ui_image.py

https://pygame-gui.readthedocs.io/en/latest/pygame_gui.elements.html#module-pygame_gui.elements.ui_image

Just draw your surface however you like and then pass it into UIImage constructor - or set the image later with set_image() if it is dynamic.

Let me know if this is not what you were thinking of.

@TheKruger
Copy link
Author

Thanks for the fast reply.

Now I'm trying to make work with the UIImage, but I will have to figure it out how hovering and clicking events will work.

The plot has a few features like when you hover one of the point, it's display the number and also a range can be selected. Like what google plots have.

So like this:
image

I will write here if I found a solution for this.

@TheKruger
Copy link
Author

I've found out if I use my plot inside the class it will draws enierly different. New values always renders at the top of the surface and the plot animation didn't even play.

It doesn't matter where is the plot surface which has to be updated, because while the plot manager is in the UI class it will not draws the plot in the way it has to.

Updating the plot surface requires to call a draw function. I tried to overwrite the UI update function and writing the update in the main loop. Both case works if my plot is not defined inside the UI class.

It's kinda wierd why it's not working inside a UI class, but this would do for a while. I will only use a plot in one UI in my game, so that's not a big deal.

The hovering event works by calculating the mouse cursor relative to the UIImage within the UIWindow. So it's just simply subtract the absolute x and y position of the UIImage from the mouse x and y position.

@MyreMylar
Copy link
Owner

MyreMylar commented Dec 31, 2024

Here is an example program of a custom, animated, surface being updated on a UIImage:

import pygame
import pygame_gui
import random

pygame.init()

pygame.display.set_caption("Quick Start")
window_surface = pygame.display.set_mode((800, 600))

background = pygame.Surface((800, 600))
background.fill(pygame.Color("#000000"))

plot_surface = pygame.Surface((100, 100))
plot_surface.fill(pygame.Color("#909060"))

manager = pygame_gui.UIManager((800, 600))

test_window = pygame_gui.elements.UIWindow((50, 50, 300, 300), manager, "Test Window")

plot_ui_image = pygame_gui.elements.UIImage(
    relative_rect=pygame.Rect((50, 50), (100, 100)),
    image_surface=plot_surface,
    manager=manager,
    container=test_window,
)

colour_change_timer = 0.0

clock = pygame.time.Clock()
is_running = True

while is_running:
    time_delta = clock.tick(60) / 1000.0
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            is_running = False

        manager.process_events(event)

    colour_change_timer += time_delta
    if colour_change_timer >= 1.0:
        colour_change_timer = 0.0
        plot_surface.fill(
            (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
        )
        plot_ui_image.set_image(plot_surface)

    manager.update(time_delta)

    window_surface.blit(background, (0, 0))
    manager.draw_ui(window_surface)

    pygame.display.update()

image

@TheKruger
Copy link
Author

Thanks for the code, but I want to create a custom UIPlot which has my plot class inside it.

Here is two code. (The code is not yet optimized)
This code works well, but the Plot class draw function must be called in the main game loop:
1.txt

This is code contains what I want to achive. I want to implement the draw function inside the UI element, so I will don't have to care about the drawing if I want to use more plots:
2.txt

Github didn't allowed me to upload python files, so I uploaded as txt files.

@MyreMylar
Copy link
Owner

MyreMylar commented Dec 31, 2024

Are you still having any issues? I've run the code in your 2.txt and it seems reasonable:

image

This is how it looks at the end of the animation. Here it is with a second window added:

image

@TheKruger
Copy link
Author

TheKruger commented Dec 31, 2024

Yeah I still have this issue. For some reason it always adds 25 no matter what value I add, even if I add a constant 5 it still adds 25 instead.

Also new values didn't got added to the plot.

@TheKruger
Copy link
Author

TheKruger commented Dec 31, 2024

I've found out the elapsed in the _animate_data function was wrong somehow.

If I replace the elapsed = self.delta_time with elapsed = time.time() - self.animation_start, then it's works.

Anyway, thanks for the help, the suffering now ends for a while I hope.

By the way, happy new year 🥳🎉.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants