nicbarker / clay

High performance UI layout library in C.
https://nicbarker.com/clay
zlib License
1.29k stars 31 forks source link

Suggestion: Use for loop for element macro #28

Closed bullno1 closed 1 month ago

bullno1 commented 2 months ago

Instead of making the children code the last argument, the open/close calls can be made into a for loop:

for (int i = (Clay__Open(...), 0), i < 1; ++i, Clay__Close()) {
    // children code
}

CLAY_RECTANGLE for example, can be defined as:

#define CLAY_RECTANGLE(...) for (int i = (Clay__OpenRectangleElement(__VA_ARGS__), 0); i < 1;  ++i, Clay__CloseElementWithChildren())

It can be seen in action here: https://github.com/bullno1/cute-clay/blob/master/src/plugin_main.c#L76-L87 Definition: https://github.com/bullno1/cute-clay/blob/master/src/cute_clay.h#L17-L18

One advantage over the current method is that the children code is not smashed into one line by macro expansion. It can be easily stepped over by a debugger. Syntax highlighting or code completion would also be better since it's not inside a macro.

The disadvantage is that empty containers must end with {} or the next line will get roped into the loop.

nicbarker commented 2 months ago

Hello and thanks for opening the issue, this is super interesting! I will do some local experimentation with this today and get back to you 😁

nicbarker commented 2 months ago

This is genius! I'm a huge fan of the way it just "works" with the debugger, and prevents the macros being turned into one giant expansion. Some issues that need to be thought about:

nicbarker commented 2 months ago

Ah - I see you solved it using a variable postfixed with the __LINE__ of the macro. Seems like it's possible to use just a global latch here, something like this:

Screenshot 2024-09-25 at 11 55 02 AM

Which will avoid having to define a whole bunch of local loop vars during layout creation 👍

nicbarker commented 2 months ago

I think we might be able to solve the second problem too by prepending the macro with a ;, to terminate the previous statement. Something like this:

#define CLAY__ELEMENT_INTERNAL(open, close, ...) \
    ;for (\
        CLAY__ELEMENT_DEFINITION_LATCH = (open(__VA_ARGS__), 0); \
        CLAY__ELEMENT_DEFINITION_LATCH < 1; \
        ++CLAY__ELEMENT_DEFINITION_LATCH, close() \
    )

As a result if you have two consecutive elements in a row and forget the {}, you'll just end up with an empty loop body.

nicbarker commented 2 months ago

This has been addressed in https://github.com/nicbarker/clay/pull/30 - will temporarily leave the issue open while it's confirmed that it solves the original issue adequately 🙂

nicbarker commented 1 month ago

I think this has been adequately, so going to close this one!