Skip to content

Releases: nicbarker/clay

0.12 - Multi type elements, performance improvements

22 Oct 23:44
Compare
Choose a tag to compare

Clay v0.12 - Multi type elements, performance improvements

Changelog

New Feature: Multi-Type Elements

carbon(91)(1)

Clay's element API has been refactored to allow for significantly better flexibility and modularity. Instead of elements having a single specific type, all elements use the generic CLAY() macro for definition, and then can be configured using any combination of types. The above screenshot demonstrates the significant reduction in boilerplate when defining a multi-type element such as "A scrolling container with a border and background".

New Feature: Clay_Hovered() and Clay_OnHover() functions

Two new functions have been added that can be called during element configuration and layout construction, provided a convenient mechanism for handing hover and click interactions.

See the documentation for Clay_Hovered and Clay_OnHover for details.

void HandleHeaderButtonInteraction(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData) {
    if (pointerData.state == CLAY_POINTER_DATA_PRESSED_THIS_FRAME) {
        // Do some click handling
    }
}

void HeaderButton(Clay_String text) {
    CLAY(CLAY_LAYOUT({ .padding = { 16, 8 } }),
        // When this element is hovered, change the background color from orange to blue
        CLAY_RECTANGLE({ .color = Clay_Hovered() ? COLOR_BLUE : COLOR_ORANGE }),
        // When this element is hovered, call the function HandleHeaderButtonInteraction with the userData = `1`.
        Clay_OnHover(HandleHeaderButtonInteraction, 1)
    ) {
        CLAY_TEXT(text, CLAY_TEXT_CONFIG(headerTextConfig));
    }
}

Improvements: Significantly faster text handling

The internal algorithm for wrapping text and caching text measurements has been rewritten from scratch, resulting in a ballpark 2-4x performance improvement of layout calculation. As a result, reasonably complex layouts now sit in the <100 microseconds range.

Screenshot 2024-10-23 at 11 18 58 AM(1)

New Contributors

Full Changelog: v0.11...v0.12

Migration Guide (C/C++)

This release contains significant breaking changes that are detailed below. For a smooth migration process, please follow the below steps in order.

Step 1. Rename Element Macros -> CLAY()

The following element macros:

  • CLAY_CONTAINER()
  • CLAY_RECTANGLE()
  • CLAY_IMAGE()
  • CLAY_BORDER_CONTAINER()
  • CLAY_SCROLL_CONTAINER()
  • CLAY_FLOATING_CONTAINER()
  • CLAY_CUSTOM_ELEMENT()

Can all be mass renamed to just CLAY(). For example:

- CLAY_RECTANGLE(...) {
+ CLAY(...) {
-     CLAY_CONTAINER(...) {
+     CLAY(...) {
         // ... etc
    }
}

Step 2. Rename CLAY_X_CONFIG() -> CLAY_X()

The following element configuration macros:

  • CLAY_RECTANGLE_CONFIG()
  • CLAY_IMAGE_CONFIG()
  • CLAY_BORDER_CONFIG()
  • CLAY_SCROLL_CONFIG()
  • CLAY_FLOATING_CONFIG()
  • CLAY_CUSTOM_CONFIG()

Can all be mass renamed to remove the _CONFIG. For example:

- CLAY(id, layout, CLAY_RECTANGLE_CONFIG(...)) {
+ CLAY(id, layout, CLAY_RECTANGLE(...)) {
-     CLAY(id, layout, CLAY_BORDER_CONFIG_OUTSIDE(...)) {
+     CLAY(id, layout, CLAY_BORDER_OUTSIDE(...)) {
         // ... etc
    }
}

Step 3. Wrap macro contents in { }

All macros that previously accepted designated initializer syntax in the form of:

CLAY_RECTANGLE(.color = RED)

Now require that their contents are wrapped in braces {}.

CLAY_RECTANGLE({ .color = RED })

This is primarily for C++ syntax compatibility.

- CLAY(id, layout, CLAY_RECTANGLE(.color = RED)) {
+ CLAY(id, layout, CLAY_RECTANGLE({ .color = RED })) {
-     CLAY(id, CLAY_LAYOUT(.layoutDirection = CLAY_TOP_TO_BOTTOM), CLAY_BORDER_OUTSIDE(.width = 2, .color = RED)) {
+     CLAY(id, CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM }), CLAY_BORDER_OUTSIDE({ .width = 2, .color = RED })) {
         // ... etc
    }
}

Step 4. Swap any non layout calls to CLAY_ID for Clay_GetElementId

CLAY_ID is now used exclusively for attaching IDs to elements during layout creation, and does not return a value. If you are using CLAY_ID to retrieve element information at other times (for example, mouse or scroll container handling) it can be swapped for the new public function Clay_GetElementId.

- Clay_ScrollContainerData scrollData = Clay_GetScrollContainerData(CLAY_ID("MainContent"));
+ Clay_ScrollContainerData scrollData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("MainContent")));

Step 5. Remove all IDs from CLAY_TEXT()

CLAY_TEXT() elements no longer accept an ID as the first argument, and instead rely on an auto generated internal ID. The primary reasoning behind this is that various capabilities provided by IDs - such as attaching floating containers to an element - don't make sense when combined with text that can arbitrarily wrap, especially as the result can end up being non rectangular.

If you need to attach a tooltip or similar to CLAY_TEXT, simply wrap the text in a container.

- CLAY_TEXT(CLAY_ID("HFileSecondLine"), CLAY_STRING("~2000 lines of C99."), textConfig);
+ CLAY_TEXT(CLAY_STRING("~2000 lines of C99."), textConfig);

Step 6 (Optional) Remove all empty calls to CLAY_LAYOUT() or references to CLAY_LAYOUT_DEFAULT

Both IDs and calls to CLAY_LAYOUT() are now optional when declaring layouts. As a result, any empty calls to CLAY_LAYOUT or references to &CLAY_LAYOUT_DEFAULT simply to satisfy the compiler can be removed.

- CLAY(CLAY_ID("Button"), CLAY_LAYOUT(), CLAY_RECTANGLE({ .color = RED })) {}
+ CLAY(CLAY_ID("Button"), CLAY_RECTANGLE({ .color = RED })) {}

Migration Guide (Odin)

Step 1. Rename Element Functions -> clay.UI()

The following element functions:

  • clay.Container()
  • clay.Rectangle()
  • clay.Image()
  • clay.Border()
  • clay.Scroll()
  • clay.Floating()
  • clay.Custom()

Should all be renamed to just Clay.UI().

- if (clay.Container(
+ if (clay.UI(
        clay.ID("Button"),
        clay.Layout({ childAlignment = {y = .CENTER}, padding = {x = 50} }),
    ) { // etc
)

Step 2. Rename clay.xConfig() -> clay.x()

The following element config functions:

  • clay.RectangleConfig()
  • clay.ImageConfig()
  • clay.BorderConfig()
  • clay.ScrollConfig()
  • clay.FloatingConfig()
  • clay.CustomConfig()

Should all be renamed to just Clay.__name__().

if (clay.UI(
        clay.ID("Button"),
-      clay.RectangleConfig({ color = COLOR_RED }),
+      clay.Rectangle({ color = COLOR_RED }),
    ) { // etc
)

Step 3. Remove the first ID argument from clay.Text

clay.Text no longer supports IDs, and instead uses an auto generated internal ID.

- clay.Text(clay.ID("HeroBlobText", index), text, clay.TextConfig({fontSize = fontSize, fontId = fontId, textColor = color}))
+ clay.Text(text, clay.TextConfig({fontSize = fontSize, fontId = fontId, textColor = color}))

v0.11

17 Sep 23:55
Compare
Choose a tag to compare

Clay 0.11

Changelog

  • New Feature: Visual Debug Tools. Similar to the inspector in Chrome or Firefox. Browse your layout hierarchy, inspect bounding boxes and config, and view any warnings output during layout. To activate the debug tools, call the new function Clay_SetDebugModeEnabled. See the README for more details.
Screenshot 2024-09-12 at 12 54 03 PM
  • New Feature: Text Wrap Modes. A new feature of TEXT_CONFIG, this allows you to choose between three modes:
  • CLAY_TEXT_WRAP_WORDS - Text will wrap on whitespace characters as container width shrinks.
  • CLAY_TEXT_WRAP_NEWLINES - Text will only wrap when encountering newline characters
  • CLAY_TEXT_WRAP_NONE - Text will never wrap even if its container is compressed beyond the text measured width.

I am considering a wrap mode which will wrap on individual characters in future but haven't decided on an implementation yet.

  • Improved performance of text layout when wrap is disabled or no wrapping needs to occur.
  • Fixed a bug that occurred when multiple nested floating containers were used.
  • Fixed a bug where the text measurement cache would not be used correctly.
  • Fixed a bug in the HTML renderer where text could be measured and cached before custom fonts had loaded.
  • Fixed a bug in the HTML renderer where alpha wasn't correctly respected.

Upgrade Guide

Unfortunately, this release contains some small breaking changes to the public API.

While I do my best to avoid breaking changes, Clay is still in alpha and the API is subject to change.

  • Element's uint32_t id has changed to a struct, Clay_ElementId. CLAY_ID and CLAY_IDI now return this struct, so layout definitions that use macros should not require migration. There are several cases where you might need to change the type of variables.
// Before
uint32_t id = CLAY_ID("Button");
// After
Clay_ElementId id = CLAY_ID("Button");

While functions that previously took uint32_t id as an argument have been updated, the parentId field of CLAY_FLOATING_CONFIG is still uint32_t. You can access the .id field of the Clay_ElementId struct in this case:

CLAY_FLOATING_CONTAINER(CLAY_ID("ScrollBar"), CLAY_LAYOUT(), CLAY_FLOATING_CONFIG(.parentId = CLAY_ID("OuterScrollContainer").id), {
  • Clay_BeginLayout and Clay_EndLayout now take no arguments, and there is a seperate function Clay_SetLayoutDimensions which is used to update the layout dimensions before the current frame. See the README for more details.
  • Clay_Initialize now expects Clay_Dimensions to set the initial layout dimensions. See the README for more details.
  • Clay_SetPointerPosition has been renamed to Clay_SetPointerState, and now expects a second argument isPointerDown representing whether or not the main mouse button / touch is currently held down.

v0.10

23 Aug 04:09
Compare
Choose a tag to compare

First release of clay.h