Skip to content

move NanoVG::restore() down#521

Open
dromer wants to merge 3 commits intoDISTRHO:developfrom
Wasted-Audio:bug/nanovg-childrender
Open

move NanoVG::restore() down#521
dromer wants to merge 3 commits intoDISTRHO:developfrom
Wasted-Audio:bug/nanovg-childrender

Conversation

@dromer
Copy link
Contributor

@dromer dromer commented Feb 21, 2026

This was needed to have correct order of operations on child widgets (like intersectScissor()).

Also added an optional method to be able to draw on top.

@dromer dromer changed the base branch from main to develop February 21, 2026 11:20
@falkTX
Copy link
Contributor

falkTX commented Feb 21, 2026

the onNanoDisplayAfter sounds to me like the wrong approach, and breaks the typical approach to drawing.
if you need to draw something on top of any children of a widget, cant you draw that with a different widget altogether too?

if we need to draw on top of other elements, we can use the Rack way and provide a layer number instead.
so the old onNanoDisplay() becomes layer 0, the bottom one, which is called by some new onNanoDisplayLayer(uint8_t layer) for layer 0 automatically. then we can keep adding more layers as needed, could be a constructor argument or runtime variable

@dromer
Copy link
Contributor Author

dromer commented Feb 21, 2026

Sure, I was hoping to be able to use my Subpatch widget in one go instead of having to create two separate widgets for the same thing.

Having layers would be a neat way to solve this!

@dromer dromer changed the title move NanoVG::restore() down; add optional onNanoDisplayAfter() move NanoVG::restore() down Feb 21, 2026
@falkTX
Copy link
Contributor

falkTX commented Feb 22, 2026

I dont think the save/restore change works here, it will save recursively when painting children, but there is no need for it as the onDisplay always starts with

        translate(SubWidget::getAbsoluteX(), SubWidget::getAbsoluteY());

so the save/restore will do nothing in regards to positioning.

it could be useful if you need to keep other properties though, like alpha or "tint" levels. is that the case?

@dromer
Copy link
Contributor Author

dromer commented Feb 22, 2026

As I said my issue was with intersectScissor() on the parent that was not propagating to the children. Which afaict it should. Moving these around fixes that behavior.

Maybe there is another/better place where it should be fixed? But to me it kind of makes sense like this, no?

@falkTX
Copy link
Contributor

falkTX commented Feb 22, 2026

oh right, I should have re-read the initial message and not just the last one.
so yes your solution makes sense, but it introduces a side effect as now the position/translation offset gets combined with every child element, which will end up being wrong.

e.g.
child 1 is at 20x20 position, which contains children at 60x60 pos.
the current code will place the first 20x20 correctly, but then 2nd children will have 20x20 + 60x60 which is not correct.

at least from what I recall of how nanovg works, that translation calls are additive.

@dromer
Copy link
Contributor Author

dromer commented Feb 22, 2026

Indeed children positions are relative to the parent. Which for me works out because the data that I use with this code also has all children positioned relative to the parent.

To me conceptually this does make sense. Children are enclosed by a parent and their positions only make sense with the parent as reference.

But I can see how this would break things (that maybe were incorrect in the first place?)

@falkTX
Copy link
Contributor

falkTX commented Feb 22, 2026

positions in dpf subwidgets dont have the concept of relative to parent though, they are always specified as absolute.

@dromer
Copy link
Contributor Author

dromer commented Feb 22, 2026

So moving or intersecting on a parent has no affect on the child widgets, which to me is .. odd.
Whats the point of having the parent<->child relation then?

I did need to overload the contains() method for detecting mouse events and propagating those down.

See: https://github.com/Wasted-Audio/PDVG/compare/feat/subpatches

But this was a minor inconvenience over having to position and intersect every single object on all possible nested levels. Which is a total accounting nightmare.

So do I have to maintain a patch with this one line fix, or can we make this behavior configurable somehow?

@falkTX
Copy link
Contributor

falkTX commented Feb 22, 2026

this has nothing to do with intersecting, but positioning.

the child widgets are used as a way to do drawing and event handling. drawing starts from parent to children; event handling is handled in reverse.

the events received by subwidgets are already in relative coordinates.

the only odd part is about positioning things, we can for sure have relative positioning. it is just the initial API deals with position of elements always in absolute coordinates, and there was not a need for more yet.
I agree that relative position makes sense for subwidgets in general, though its a bit more complex to handle.

@dromer
Copy link
Contributor Author

dromer commented Feb 22, 2026

Ok but the intersection operation does not propagate to children, which is the thing I was trying to solve :)

The relative positioning was just a "happy accident" that makes much of the rest of my code a lot easier.

@falkTX
Copy link
Contributor

falkTX commented Feb 22, 2026

sure I am agreeing with you here.

we need to find a way to clear the nanovg translation and set another one.

@dromer
Copy link
Contributor Author

dromer commented Feb 22, 2026

Just to show, left is without the fix and right is with:

2026-02-22_12-09

(this is two levels of child-widgets. one parent with only blue square and toggle box, then another containing this parent + green and red square)

@dromer
Copy link
Contributor Author

dromer commented Feb 22, 2026

Wait I think I get what you're saying: the intersection on the children moves to a relative position inside of the parent which is why we don't see its effect in the original code?

@dromer
Copy link
Contributor Author

dromer commented Feb 22, 2026

Wait I think I get what you're saying: the intersection on the children moves to a relative position inside of the parent which is why we don't see its effect in the original code?

Actually that wouldn't make sense since then these objects wouldn't be visible at all and completely "cut out" from view.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants