TGUI icon indicating copy to clipboard operation
TGUI copied to clipboard

Borders for `tgui::Picture`

Open Ma5t3rful opened this issue 7 months ago • 3 comments

Hello, Could you please add the ability to set and customize borders(Radius thickness and color) for tgui::Photo?

Thanks.

Ma5t3rful avatar Jul 10 '25 18:07 Ma5t3rful

I don't think adding borders to the Picture widget is needed. You can probably just put the Picture inside a Panel and use picture->setSize({"100%", "100%"}); to fill the entire panel. Then you can use the borders of the panel.

Unfortunately I have no way do perform clipping on the rounded borders (no matter whether the borders would be in Picture or Panel). So if the image is a rectangle then it would be drawn outside the borders. So you would have to make certain that the texture itself has transparent rounded corners with the right radius.

texus avatar Jul 10 '25 20:07 texus

Unfortunately I have no way do perform clipping on the rounded borders (no matter whether the borders would be in Picture or Panel). So if the image is a rectangle then it would be drawn outside the borders. So you would have to make certain that the texture itself has transparent rounded corners with the right radius.

Yeah. Unfortunately, that was the issue. I wanted to add some rounded corners around the thumbnails in my app. But it didn't work.

#pragma once
#include "TGUI/Texture.hpp"
#include "TGUI/Widgets/Panel.hpp"
#include "TGUI/Widgets/Picture.hpp"
#include <memory>

class RoundedPicture
: public tgui::Panel
{
    public:
    RoundedPicture(const tgui::Texture &texture);
    void replace_texture ();
    private:
    std::shared_ptr<tgui::Picture> m_picture;
};
#include "rounded_picture.hpp"
#include "TGUI/Texture.hpp"
#include "TGUI/Widgets/Picture.hpp"

RoundedPicture::RoundedPicture(const tgui::Texture& texture):
tgui::Panel(),
m_picture(tgui::Picture::create(texture))
{
    m_picture->setSize("100%","100%");
    const auto renderer = getRenderer();
    renderer->setPadding(0);
    renderer->setBackgroundColor("transparent");
    renderer->setBorderColor("white");
    renderer->setRoundedBorderRadius(10);
    add(m_picture);
}

I pull pictures from user's files there is no way for me to make sure they are rounded.

Ma5t3rful avatar Jul 10 '25 21:07 Ma5t3rful

There is no easy solution, you will have to somehow make the corners of the image transparent. Since they are user files that you don't control and don't want to modify, this will have to be done in memory.

There is probably some way to make the corners transparent during rendering by using a shader. (You could experiment with rendering an sf::Sprite with an sf::Shader until you have a working shader, and then use that shader in combination with the tgui::Texture::setShader function).

Something that might be simpler than writing a shader is to alter the pixel data itself when loading the image. I don't have the time to come up with a full solution or to test the code that I'm writing below, but the process would look like the following:

// Load the image into memory
sf::Image image("test.png");
const unsigned imageWidth = image.getSize().x;
const unsigned imageHeight = image.getSize().y;
const std::uint8_t* originalPixels = image.getPixelsPtr();

// Create a copy of the image, where you set the alpha component of the pixels in the corners to 0 to make them transparent
std::unique_ptr<std::uint8_t[]> newPixels = tgui::MakeUniqueForOverwrite<std::uint8_t[]>(imageWidth * imageHeight * 4);
for (unsigned y = 0; y < imageHeight; ++y)
{
    for (unsigned x = 0; x < imageWidth; ++x)
    {
        const unsigned pixelIndex = (y * imageWidth + x) * 4;
        newPixels[pixelIndex] = originalPixels[pixelIndex]; // Copy red component
        newPixels[pixelIndex+1] = originalPixels[pixelIndex+1]; // Copy green component
        newPixels[pixelIndex+2] = originalPixels[pixelIndex+2]; // Copy blue component

        if (true) // TODO: Determine if this pixel is part of the corner
            newPixels[pixelIndex+3] = originalPixels[pixelIndex+3]; // Copy alpha component
        else
            newPixels[pixelIndex+3] = 0; // Make the pixel transparent
    }
}

// Load the modified pixel data into a texture object that can be passed to the tgui::Picture
tgui::Texture texture;
texture.loadFromPixelData({imageWidth, imageHeight}, newPixels.get());

texus avatar Jul 11 '25 21:07 texus