Expand the painting/child area of a component

Why not turn this into a feature request? I think a setPaintBounds() or expandPaintBounds() function would be very useful and probably not hard to implement.

3 Likes

Agree, In the GMPI Drawing API each object has both a layout rectangle and a clipping rectangle.
They both default to the same rectangle, but when for example you want to draw a thick border (where some pixels end up outside the layout rect, it is easy to express that without hacks and having to redo the entire layout of the UI.

// bounds for the purpose of layout. May not include all drawn pixels.
virtual GmpiDrawing::Rect getLayoutRect() override { return bounds_; }

// bounds for the purpose of invalidating every single drawn pixel, Including those outside layout boundary.
virtual GmpiDrawing::Rect GetClipRect() override { return bounds_; }
4 Likes

I am not sure if it would be easy to implement free clipping, since it depends on the component hierarchy. From what I have seen it is possible if the clipping is inside the parent component, since the paint function is called from it. The only issue I have found is that if the paint needs to be updated the entire parent component must be called to repaint. So it is more suitable for static drawings.

Another way that I don’t know if it would be possible is to be able to expand the boundaries at any time during the drawing, similar to when reducing with g.reduceClipRegion.

Reviving an old thread as I too think there should be an easier solution to draw shadows and glows. Having the painting region separate from a component’s bounds set by the parent would make drawing tightly packed UI layouts so much easier as you wouldn’t have to deal with overlapping hitboxes and clipped blur effects.

2 Likes

+1

The only way for it to be transparent to the user is if it were integrated into juce. I found a solution that apparently works.

The idea is that the working sizes and positions of the components used by the programmer are different from the internal areas of the components. All components would have a border of the same size, this guarantees that the extra drawing area is the same for all and respect the repainting hierarchy.

Here you can visually see, in black the working boundary of the components, in colors the real boundaries of the components.

paint juce

One way to address this is with an abstract class that acts as an intermediary to convert work dimensions into component dimensions and vice versa.

class Extender {

    juce::Point<int> border;

public:

    Extender(int borderX, int borderY) {
         border.x = borderX, border.y = borderY;
    }

    virtual ~Extender() {}
    virtual juce::Component* getComponent() = 0;


    void adjustTransform(juce::Graphics& g) {
        g.addTransform(juce::AffineTransform().translation(border.x, border.y));
    }

    void setTopLeftPosition(int x, int y) { getComponent()->setTopLeftPosition(x-border.x, y-border.y); }

    juce::Rectangle<int> getBounds() { 
         return getComponent()->getBounds().reduced(border.x, border.y); 
    }
    juce::Rectangle<int> getLocalBounds() { 
         return getComponent()->getLocalBounds().reduced(border.x, border.y); 
    }

    void setBounds(juce::Rectangle<int> rect) { getComponent()->setBounds(rect.expanded(border.x, border.y)); }

    void setBounds(int x, int y, int width, int height) { 
        getComponent()->setBounds(juce::Rectangle<int>(x-border.x, y-border.y, width+border.x*2, height+border.y*2 )); 
    }

    int getX() { return getComponent()->getX()+border.x; }
    int getY() { return getComponent()->getY()+border.y; }

    int getWidth() { return getComponent()->getWidth()-border.x*2; }
    int getHeight() { return getComponent()->getHeight()-border.y*2; }

    // others convert methods....
};

now all those calls are ambiguous and require the Extend:: scope

Additionally, when paint, the coordinates must also move the borders with Extend::adjustTransform(g) , so local -10, -10 coordinates internally will be 0, 0 which guarantees that lower negative values ​​will be drawn within the boundary

but I think that although it may be the best solution, it is not perfect, it may have unforeseen issues

1 Like