Compare commits

...

58 Commits

Author SHA1 Message Date
Nic Barker
7cd48bd336 Convert internal memcmp to simd version 2025-01-30 12:11:43 +13:00
Nic Barker
dfc9db43bc initial attempt 2025-01-30 12:11:43 +13:00
Nic Barker
cc6dfccc7e update odin bindings and revert some accidental change
s
2025-01-30 12:11:42 +13:00
Nic Barker
3effdbbfd4 update generated wasm 2025-01-30 12:11:26 +13:00
Nic Barker
16ed00b184 Expose getter for max element counts 2025-01-30 12:11:06 +13:00
Nic Barker
7af2d128c9 Update for c99 compat 2025-01-30 12:11:06 +13:00
Harrison Lambeth
9d81c808f9 seems like this fully works 2025-01-30 12:11:06 +13:00
Harrison Lambeth
efad3deef8
Copy elementId in Clay__AddHashMapItem() in case underlying stringId has changed (#239)
Some checks are pending
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Waiting to run
2025-01-30 10:20:14 +13:00
Nic Barker
a1e692b72a
[Core] Add option to hash text contents to text config (#238) 2025-01-30 09:59:42 +13:00
Nic Barker
5fae7a6249 [Core] Compensate for OSes that don't return 64b aligned memory from malloc
Some checks are pending
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Waiting to run
2025-01-29 21:16:24 +13:00
Nic Barker
1bcf256e4d
[Core] Replace generated arrays with macro declarations, align cache lines to 64 bytes (#235)
Some checks are pending
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Waiting to run
2025-01-29 17:14:01 +13:00
Martin Evald
e9f2e6c4f1
[Renderers/SDL2] Don't take addresses of temporaries. (#232) 2025-01-29 13:09:41 +13:00
noflashbang
34f2dab9e8
Normalized usage of Clay__defaultMaxElementCount and Clay__defaultMaxMeasureTextWordCacheCount (#233) 2025-01-29 13:09:07 +13:00
Nic Barker
951d785deb [Documentation] Fix incorrect type information in README for CLAY_IDI
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Has been cancelled
2025-01-26 15:43:55 +13:00
Nic Barker
4612481d25 [Documentation] Fix some typos in the README example code 2025-01-26 15:35:30 +13:00
Nic Barker
0a703de69a
[Core] Add z-index and string base to Render Commands (#227) 2025-01-26 15:28:35 +13:00
Nic Barker
cb62db77e3 [Documentation] Combine quick start steps into a single code block in main README 2025-01-26 15:22:46 +13:00
Cory
ea6109bd0b
[CMake] Make Examples Optional in CMAKE (#216) 2025-01-26 15:05:45 +13:00
arnauNau
c0dac38c87
[Renderers/SDL3] Add borders and rounded borders functionality. (#220) 2025-01-26 14:39:34 +13:00
Timothy Hoyt
c3fcf6ce12
[Bindings/C++] Link and information for ClayMan, a C++ wrapper library for clay (#218)
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Has been cancelled
2025-01-24 20:51:00 +13:00
arnauNau
aba846a446
[Renderers/SDL3] Add rounded corners rectangle functionality (#219)
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Has been cancelled
2025-01-23 09:30:24 +13:00
Nic Barker
9d659e8abd [Examples/Raylib] Restore deleted font
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Has been cancelled
2025-01-21 21:28:38 +13:00
Nic Barker
ec2b3b35ff [Renderers/Raylib] Early return 0 rather than segfault when Raylib fonts fail to load 2025-01-21 21:26:57 +13:00
Nic Barker
5f7176cdcc Fix quick start in README to include error handler 2025-01-21 21:17:24 +13:00
Nic Barker
ebeef93c34 [Documentation] Include CLAY_ID_LOCAL in README.md 2025-01-21 21:11:49 +13:00
Nic Barker
9b2d585499 Update odin and wasm bindings 2025-01-21 19:14:22 +13:00
Nic Barker
81589ad29b [Core] Fix layout bug in SIZING_PERCENT 2025-01-21 19:11:33 +13:00
Nic Barker
16f894bb4d Fix incorrect use of corner radius 2025-01-21 18:32:33 +13:00
Timothy Hoyt
9f07f5aac8
fixed video demo padding (#205) 2025-01-21 18:31:48 +13:00
Nic Barker
01d3ab127f Update odin bindings for new text measurement API
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Has been cancelled
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Has been cancelled
2025-01-20 11:39:59 +13:00
Nic Barker
326325ffaf
[Core] Convert measureText pointer to value string slice (#214) 2025-01-20 11:27:22 +13:00
Daniel Collin
e8025cc254
SetMesureText and SetQueryScrollOffset takes userData (#212) 2025-01-20 10:59:02 +13:00
Linus Probert
8e7e30dda6
[Renderers/SDL3] Adds an example using SDL3 as a renderer (#107)
Some checks are pending
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Waiting to run
Co-authored-by: Nic Barker <contact+github@nicbarker.com>
2025-01-19 14:35:41 +13:00
William Inal Zettergren
9d3fba39be
Add external link to zig bindings (#210)
Some checks are pending
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Waiting to run
2025-01-18 21:43:23 +13:00
ppeb
4961f2153e
Extend SDL2 Renderer and SDL2-video-demo (#208) 2025-01-18 21:42:18 +13:00
Nic Barker
a093730da2 [Core] Fix a segfault if debug tools were enabled without a measure text function
Some checks failed
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Failing after 13s
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Failing after 12s
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Has been cancelled
2025-01-16 09:14:57 +13:00
Michael Savage
cd82ce6fcf
[Core] Don't divide zero by zero (#200)
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Failing after 14s
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Failing after 12s
Co-authored-by: Nic Barker <contact+github@nicbarker.com>
2025-01-15 10:06:22 +13:00
Nic Barker
814c9392c6
[Core] Add API to query element bounding boxes (#199)
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Failing after 12s
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Failing after 13s
Co-authored-by: hexmaster111 <hailey@not-an-email-address.fake>
2025-01-14 22:09:06 +13:00
Nic Barker
338852b3ce Fix a bug with the new padding
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Failing after 12s
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Failing after 13s
2025-01-14 14:26:30 +13:00
Nic Barker
f1d8a53a32
[Core] [Breaking] Split padding values into left, right, top, bottom (#195) 2025-01-14 10:38:02 +13:00
Harrison Lambeth
afba9f0de6
Add a function to reset text measurement cache (#181)
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Failing after 14s
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Failing after 14s
2025-01-13 19:26:46 +13:00
Nic Barker
3a4455aa83
Fix text wrapping handling with explicit newline characters (#192)
Co-authored-by: Ryzee119 <wendland@live.com.au>
2025-01-13 19:23:28 +13:00
Nic Barker
208c7cb3a0 Fix incorrect border between children after 2nd element
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Failing after 12s
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Failing after 11s
2025-01-12 19:16:09 +13:00
Nic Barker
c2c445e455 Fix broken ifdef on MSVC
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Failing after 12s
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Failing after 13s
2025-01-12 10:49:00 +13:00
Nic Barker
9e7595b873 Fixed a bug where minMemorySize could cause a memory overwrite
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Failing after 12s
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Failing after 11s
2025-01-11 21:37:21 +13:00
Nic Barker
32d1a31dfe Fix uint64 usage for wasm 2025-01-11 21:35:45 +13:00
Nic Barker
b2b50724e2 Fix bug in html renderer debug tools 2025-01-11 20:45:20 +13:00
Nic Barker
12b3280dab update odin bindings
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Failing after 15s
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Failing after 11s
2025-01-11 14:22:52 +13:00
Nic Barker
d81c9e1de5 fix C++ compile issues 2025-01-11 14:21:47 +13:00
Nic Barker
7142a427bb Update odin bindings 2025-01-11 14:19:31 +13:00
Nic Barker
d7ee448ed5 Add EXTEND_CONFIG_BORDER 2025-01-11 14:15:24 +13:00
Nic Barker
7ecd5adbce Update debug view to have correct z indexing 2025-01-11 14:15:02 +13:00
Nic Barker
2fcb4cc76e Fix z index sorting of tree roots 2025-01-11 14:08:02 +13:00
Nic Barker
44fb89c8b6 Add an epsilon to compression comparison to prevent degenerate loop
Some checks failed
CMake on multiple platforms / build (Release, cl, cl, windows-latest) (push) Waiting to run
CMake on multiple platforms / build (Release, clang, clang++, ubuntu-latest) (push) Failing after 13s
CMake on multiple platforms / build (Release, gcc, g++, ubuntu-latest) (push) Failing after 12s
2025-01-10 21:54:13 +13:00
Nic Barker
bc9ef8b02d
Update README.md 2025-01-10 21:05:12 +13:00
Mathys Gasnier
0989aeee06
[Documentation] Summary & Readability improvement (#125) 2025-01-10 21:03:32 +13:00
Funto
e11a394c25
[Compilers] Fix MSVC compilation with CMake (#178)
Co-authored-by: Nic Barker <contact+github@nicbarker.com>
2025-01-10 20:59:13 +13:00
FintasticMan
670f707997
[Core] Remove ##__VA_ARGS__ (#150) 2025-01-10 20:47:00 +13:00
58 changed files with 2813 additions and 2165 deletions

1
.gitignore vendored
View File

@ -4,3 +4,4 @@ cmake-build-release/
.idea/
node_modules/
*.dSYM
.vs/

View File

@ -3,14 +3,38 @@ project(clay)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
add_subdirectory("examples/cpp-project-example")
option(CLAY_INCLUDE_ALL_EXAMPLES "Build all examples" ON)
option(CLAY_INCLUDE_DEMOS "Build video demo and website" OFF)
option(CLAY_INCLUDE_CPP_EXAMPLE "Build C++ example" OFF)
option(CLAY_INCLUDE_RAYLIB_EXAMPLES "Build raylib examples" OFF)
option(CLAY_INCLUDE_SDL2_EXAMPLES "Build SDL 2 examples" OFF)
option(CLAY_INCLUDE_SDL3_EXAMPLES "Build SDL 3 examples" OFF)
# Don't try to compile C99 projects using MSVC
if(NOT MSVC)
add_subdirectory("examples/raylib-sidebar-scrolling-container")
add_subdirectory("examples/raylib-multi-context")
# add_subdirectory("examples/cairo-pdf-rendering") Some issue with github actions populating cairo, disable for now
add_subdirectory("examples/clay-official-website")
add_subdirectory("examples/introducing-clay-video-demo")
add_subdirectory("examples/SDL2-video-demo")
message(STATUS "CLAY_INCLUDE_DEMOS: ${CLAY_INCLUDE_DEMOS}")
if(APPLE)
enable_language(OBJC)
endif()
if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_CPP_EXAMPLE)
add_subdirectory("examples/cpp-project-example")
endif()
if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_DEMOS)
if(NOT MSVC)
add_subdirectory("examples/clay-official-website")
endif()
add_subdirectory("examples/introducing-clay-video-demo")
endif ()
if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_RAYLIB_EXAMPLES)
add_subdirectory("examples/raylib-multi-context")
add_subdirectory("examples/raylib-sidebar-scrolling-container")
endif ()
if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_SDL2_EXAMPLES)
add_subdirectory("examples/SDL2-video-demo")
endif ()
if(NOT MSVC AND (CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_SDL3_EXAMPLES))
add_subdirectory("examples/SDL3-simple-demo")
endif()
# add_subdirectory("examples/cairo-pdf-rendering") Some issue with github actions populating cairo, disable for now

386
README.md
View File

@ -20,68 +20,38 @@ _An example GUI application built with clay_
## Quick Start
1. Download or clone clay.h and include it after defining `CLAY_IMPLEMENTATION` in one file.
Download or clone clay.h and include it after defining `CLAY_IMPLEMENTATION` in one file.
```C
// Must be defined in one file, _before_ #include "clay.h"
#define CLAY_IMPLEMENTATION
#include "clay.h"
```
#include "../../clay.h"
2. Ask clay for how much static memory it needs using [Clay_MinMemorySize()](#clay_minmemorysize), create an Arena for it to use with [Clay_CreateArenaWithCapacityAndMemory(size, void *memory)](#clay_createarenawithcapacityandmemory), and initialize it with [Clay_Initialize(arena, dimensions)](#clay_initialize).
```C
// Note: malloc is only used here as an example, any allocator that provides
// a pointer to addressable memory of at least totalMemorySize will work
uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena arena = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
Clay_Initialize(arena, (Clay_Dimensions) { screenWidth, screenHeight });
```
3. Provide a `MeasureText(text, config)` function pointer with [Clay_SetMeasureTextFunction(function)](#clay_setmeasuretextfunction) so that clay can measure and wrap text.
```C
// Example measure text function
static inline Clay_Dimensions MeasureText(Clay_String *text, Clay_TextElementConfig *config) {
// Clay_TextElementConfig contains members such as fontId, fontSize, letterSpacing etc
// Note: Clay_String->chars is not guaranteed to be null terminated
}
// Tell clay how to measure text
Clay_SetMeasureTextFunction(MeasureText);
```
4. **Optional** - Call [Clay_SetLayoutDimensions(dimensions)](#clay_setlayoutdimensions) if the window size of your application has changed.
```C
// Update internal layout dimensions
Clay_SetLayoutDimensions((Clay_Dimensions) { screenWidth, screenHeight });
```
5. **Optional** - Call [Clay_SetPointerState(pointerPosition, isPointerDown)](#clay_setpointerstate) if you want to use mouse interactions.
```C
// Update internal pointer position for handling mouseover / click / touch events
Clay_SetPointerState((Clay_Vector2) { mousePositionX, mousePositionY }, isMouseDown);
```
6. **Optional** - Call [Clay_UpdateScrollContainers(enableDragScrolling, scrollDelta, deltaTime)](#clay_updatescrollcontainers) if you want to use clay's built in scrolling containers.
```C
// Update internal pointer position for handling mouseover / click / touch events
Clay_UpdateScrollContainers(true, (Clay_Vector2) { mouseWheelX, mouseWheelY }, deltaTime);
```
7. Call [Clay_BeginLayout()](#clay_beginlayout) and declare your layout using the provided macros.
```C
const Clay_Color COLOR_LIGHT = (Clay_Color) {224, 215, 210, 255};
const Clay_Color COLOR_RED = (Clay_Color) {168, 66, 28, 255};
const Clay_Color COLOR_ORANGE = (Clay_Color) {225, 138, 50, 255};
void HandleClayErrors(Clay_ErrorData errorData) {
// See the Clay_ErrorData struct for more information
printf("%s", errorData.errorText.chars);
switch(errorData.errorType) {
// etc
}
}
// Example measure text function
static inline Clay_Dimensions MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData) {
// Clay_TextElementConfig contains members such as fontId, fontSize, letterSpacing etc
// Note: Clay_String->chars is not guaranteed to be null terminated
return (Clay_Dimensions) {
.width = text.length * config->fontSize, // <- this will only work for monospace fonts, see the renderers/ directory for more advanced text measurement
.height = config->fontSize
};
}
// Layout config is just a struct that can be declared statically, or inline
Clay_LayoutConfig sidebarItemLayout = (Clay_LayoutConfig) {
.sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(50) },
.sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(50) },
};
// Re-useable components are just normal functions
@ -89,52 +59,65 @@ void SidebarItemComponent() {
CLAY(CLAY_LAYOUT(sidebarItemLayout), CLAY_RECTANGLE({ .color = COLOR_ORANGE })) {}
}
// An example function to begin the "root" of your layout tree
Clay_RenderCommandArray CreateLayout() {
Clay_BeginLayout();
int main() {
// Note: malloc is only used here as an example, any allocator that provides
// a pointer to addressable memory of at least totalMemorySize will work
uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena arena = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
// An example of laying out a UI with a fixed width sidebar and flexible width main content
CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(), CLAY_SIZING_GROW()}, .padding = {16, 16}, .childGap = 16 }), CLAY_RECTANGLE({ .color = {250,250,255,255} })) {
CLAY(CLAY_ID("SideBar"),
CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_FIXED(300), .height = CLAY_SIZING_GROW() }, .padding = {16, 16}, .childGap = 16 }),
CLAY_RECTANGLE({ .color = COLOR_LIGHT })
) {
CLAY(CLAY_ID("ProfilePictureOuter"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW() }, .padding = {16, 16}, .childGap = 16, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY(CLAY_ID("ProfilePicture"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60) }}), CLAY_IMAGE({ .imageData = &profilePicture, .sourceDimensions = {60, 60} })) {}
CLAY_TEXT(CLAY_STRING("Clay - UI Library"), CLAY_TEXT_CONFIG({ .fontSize = 24, .textColor = {255, 255, 255, 255} }));
Clay_Initialize(arena, (Clay_Dimensions) { screenWidth, screenHeight }, (Clay_ErrorHandler) { HandleClayErrors });
while(renderLoop()) { // Will be different for each renderer / environment
// Optional: Update internal layout dimensions to support resizing
Clay_SetLayoutDimensions((Clay_Dimensions) { screenWidth, screenHeight });
// Optional: Update internal pointer position for handling mouseover / click / touch events - needed for scrolling & debug tools
Clay_SetPointerState((Clay_Vector2) { mousePositionX, mousePositionY }, isMouseDown);
// Optional: Update internal pointer position for handling mouseover / click / touch events - needed for scrolling and debug tools
Clay_UpdateScrollContainers(true, (Clay_Vector2) { mouseWheelX, mouseWheelY }, deltaTime);
// All clay layouts are declared between Clay_BeginLayout and Clay_EndLayout
Clay_BeginLayout();
// An example of laying out a UI with a fixed width sidebar and flexible width main content
CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT({ .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)}, .padding = CLAY_PADDING_ALL(16), .childGap = 16 }), CLAY_RECTANGLE({ .color = {250,250,255,255} })) {
CLAY(CLAY_ID("SideBar"),
CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_FIXED(300), .height = CLAY_SIZING_GROW(0) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16 }),
CLAY_RECTANGLE({ .color = COLOR_LIGHT })
) {
CLAY(CLAY_ID("ProfilePictureOuter"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY(CLAY_ID("ProfilePicture"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60) }}), CLAY_IMAGE({ .imageData = &profilePicture, .sourceDimensions = {60, 60} })) {}
CLAY_TEXT(CLAY_STRING("Clay - UI Library"), CLAY_TEXT_CONFIG({ .fontSize = 24, .textColor = {255, 255, 255, 255} }));
}
// Standard C code like loops etc work inside components
for (int i = 0; i < 5; i++) {
SidebarItemComponent();
}
CLAY(CLAY_ID("MainContent"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) }}), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) {}
}
// Standard C code like loops etc work inside components
for (int i = 0; i < 5; i++) {
SidebarItemComponent();
// All clay layouts are declared between Clay_BeginLayout and Clay_EndLayout
Clay_RenderCommandArray renderCommands = Clay_EndLayout();
// More comprehensive rendering examples can be found in the renderers/ directory
for (int i = 0; i < renderCommands.length; i++) {
Clay_RenderCommand *renderCommand = &renderCommands.internalArray[i];
switch (renderCommand->commandType) {
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
DrawRectangle(
renderCommand->boundingBox,
renderCommand->config.rectangleElementConfig->color);
}
// ... Implement handling of other command types
}
}
}
CLAY(CLAY_ID("MainContent"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_GROW() }}), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) {}
}
// ...
});
```
8. Call [Clay_EndLayout()](#clay_endlayout) and process the resulting [Clay_RenderCommandArray](#clay_rendercommandarray) in your choice of renderer.
```C
Clay_RenderCommandArray renderCommands = Clay_EndLayout();
for (int i = 0; i < renderCommands.length; i++) {
Clay_RenderCommand *renderCommand = &renderCommands.internalArray[i];
switch (renderCommand->commandType) {
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
DrawRectangle(
renderCommand->boundingBox,
renderCommand->config.rectangleElementConfig->color);
}
// ... Implement handling of other command types
}
}
```
The above example, rendered correctly will look something like the following:
![Clay Example](https://github.com/user-attachments/assets/1928c6d4-ada9-4a4c-a3d1-44fe9b23b3bd)
@ -151,6 +134,65 @@ In summary, the general order of steps is:
For help starting out or to discuss clay, considering joining [the discord server.](https://discord.gg/b4FTWkxdvT)
## Summary
- [High Level Documentation](#high-level-documentation)
- [Building UI Hierarchies](#building-ui-hierarchies)
- [Configuring Layout and Styling UI Elements](#configuring-layout-and-styling-ui-elements)
- [Element IDs](#element-ids)
- [Mouse, Touch and Pointer Interactions](#mouse-touch-and-pointer-interactions)
- [Scrolling Elements](#scrolling-elements)
- [Floating Elements](#floating-elements-absolute-positioning)
- [Custom Elements](#laying-out-your-own-custom-elements)
- [Retained Mode Rendering](#retained-mode-rendering)
- [Visibility Culling](#visibility-culling)
- [Preprocessor Directives](#preprocessor-directives)
- [Bindings](#bindings-for-non-c)
- [Debug Tools](#debug-tools)
- [API](#api)
- [Naming Conventions](#naming-conventions)
- [Public Functions](#public-functions)
- [Lifecycle](#lifecycle-for-public-functions)
- [Clay_MinMemorySize](#clay_minmemorysize)
- [Clay_CreateArenaWithCapacityAndMemory](#clay_createarenawithcapacityandmemory)
- [Clay_SetMeasureTextFunction](#clay_setmeasuretextfunction)
- [Clay_ResetMeasureTextCache](#clau_resetmeasuretextcache)
- [Clay_SetMaxElementCount](clay_setmaxelementcount)
- [Clay_SetMaxMeasureTextCacheWordCount](#clay_setmaxmeasuretextcachewordcount)
- [Clay_Initialize](#clay_initialize)
- [Clay_GetCurrentContext](#clay_getcurrentcontext)
- [Clay_SetCurrentContext](#clay_setcurrentcontext)
- [Clay_SetLayoutDimensions](#clay_setlayoutdimensions)
- [Clay_SetPointerState](#clay_setpointerstate)
- [Clay_UpdateScrollContainers](#clay_updatescrollcontainers)
- [Clay_BeginLayout](#clay_beginlayout)
- [Clay_EndLayout](#clay_endlayout)
- [Clay_Hovered](#clay_hovered)
- [Clay_OnHover](#clay_onhover)
- [Clay_PointerOver](#clay_pointerover)
- [Clay_GetScrollContainerData](#clay_getscrollcontainerdata)
- [Clay_GetElementId](#clay_getelementid)
- [Element Macros](#element-macros)
- [CLAY](#clay-1)
- [CLAY_ID](#clay_id)
- [CLAY_IDI](#clay_idi)
- [CLAY_LAYOUT](#clay_layout)
- [CLAY_RECTANGLE](#clay_rectangle)
- [CLAY_TEXT](#clay_text)
- [CLAY_IMAGE](#clay_image)
- [CLAY_SCROLL](#clay_scroll)
- [CLAY_BORDER](#clay_border)
- [CLAY_FLOATING](#clay_floating)
- [CLAY_CUSTOM_ELEMENT](#clay_custom_element)
- [Data Structures & Defs](data-structures--definitions)
- [Clay_String](#clay_string)
- [Clay_ElementId](#clay_elementid)
- [Clay_RenderCommandArray](#clay_rendercommandarray)
- [Clay_RenderCommand](#clay_rendercommand)
- [Clay_ScrollContainerData](#clay_scrollcontainerdata)
- [Clay_ErrorHandler](#clay_errorhandler)
- [Clay_ErrorData](#clay_errordata)
## High Level Documentation
### Building UI Hierarchies
@ -159,7 +201,7 @@ Clay UIs are built using the C macro `CLAY()`. This macro creates a new empty el
Child elements are added by opening a block: `{}` after calling the `CLAY()` macro (exactly like you would with an `if` statement or `for` loop), and declaring child components inside the braces.
```C
// Parent element with 8px of padding
CLAY(CLAY_LAYOUT({ .padding = 8 })) {
CLAY(CLAY_LAYOUT({ .padding = CLAY_PADDING_ALL(8) })) {
// Child element 1
CLAY_TEXT(CLAY_STRING("Hello World"), CLAY_TEXT_CONFIG({ .fontSize = 16 }));
// Child element 2 with red background
@ -174,7 +216,7 @@ However, unlike HTML and other declarative DSLs, these macros are just C. As a r
// Re-usable "components" are just functions that declare more UI
void ButtonComponent(Clay_String buttonText) {
// Red box button with 8px of padding
CLAY(CLAY_LAYOUT({ .padding = { 8, 8 }}), CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY(CLAY_LAYOUT({ .padding = CLAY_PADDING_ALL(8)}), CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY_TEXT(buttonText, textConfig);
}
}
@ -187,7 +229,7 @@ CLAY(CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
}
// Only render this element if we're on a mobile screen
if (isMobileScreen) {
CLAY() {
CLAY(0) {
// etc
}
}
@ -200,11 +242,11 @@ CLAY(CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
### Configuring Layout and Styling UI Elements
The layout of clay elements is configured with the `CLAY_LAYOUT()` macro.
```C
CLAY(CLAY_LAYOUT({ .padding = {.x = 8, .y = 8}, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
CLAY(CLAY_LAYOUT({ .padding = { 8, 8, 8, 8 }, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
// Children are 8px inset into parent, and laid out top to bottom
}
```
This macro isn't magic - all it's doing is wrapping the standard designated initializer syntax and adding the result to an internal array. e.g. `(Clay_LayoutConfig) { .padding = { .x = 8, .y = 8 } ...`.
This macro isn't magic - all it's doing is wrapping the standard designated initializer syntax and adding the result to an internal array. e.g. `(Clay_LayoutConfig) { .padding = { .left = 8, .right = 8 } ...`.
See the [Clay_LayoutConfig](#clay_layout) API for the full list of options.
@ -274,7 +316,7 @@ void HandleButtonInteraction(Clay_ElementId elementId, Clay_PointerData pointerI
ButtonData linkButton = (ButtonData) { .link = "https://github.com/nicbarker/clay" };
// HandleButtonInteraction will be called for each frame the mouse / pointer / touch is inside the button boundaries
CLAY(CLAY_LAYOUT({ .padding = { 8, 8 }}), Clay_OnHover(HandleButtonInteraction, &linkButton)) {
CLAY(CLAY_LAYOUT({ .padding = CLAY_PADDING_ALL(8)}), Clay_OnHover(HandleButtonInteraction, &linkButton)) {
CLAY_TEXT(CLAY_STRING("Button"), &headerTextConfig);
}
```
@ -362,7 +404,7 @@ typedef struct t_CustomElementData {
Model myModel = Load3DModel(filePath);
CustomElement modelElement = (CustomElement) { .type = CUSTOM_ELEMENT_TYPE_MODEL, .model = myModel }
// ...
CLAY() {
CLAY(0) {
// This config is type safe and contains the CustomElementData struct
CLAY(CLAY_CUSTOM_ELEMENT({ .customData = { .type = CUSTOM_ELEMENT_TYPE_MODEL, .model = myModel } })) {}
}
@ -425,8 +467,7 @@ Clay is usable out of the box as a `.h` include in both C99 and C++20 with desig
There are also supported bindings for other languages, including:
- [Odin Bindings](https://github.com/nicbarker/clay/tree/main/bindings/odin)
Unfortunately clay does **not** support Microsoft C11 or C17 via MSVC at this time.
- [Rust Bindings](https://github.com/clay-ui-rs/clay)
### Debug Tools
@ -490,18 +531,24 @@ render(renderCommands2);
**Each Frame**
`Clay_SetLayoutDimensions` -> `Clay_SetPointerState` -> `Clay_UpdateScrollContainers` -> `Clay_BeginLayout` -> `CLAY() etc...` -> `Clay_EndLayout`
---
### Clay_MinMemorySize
`uint32_t Clay_MinMemorySize()`
Returns the minimum amount of memory **in bytes** that clay needs to accomodate the current [CLAY_MAX_ELEMENT_COUNT](#preprocessor-directives).
---
### Clay_CreateArenaWithCapacityAndMemory
`Clay_Arena Clay_CreateArenaWithCapacityAndMemory(uint32_t capacity, void *offset)`
Creates a `Clay_Arena` struct with the given capacity and base memory pointer, which can be passed to [Clay_Initialize](#clay_initialize).
---
### Clay_SetMeasureTextFunction
`void Clay_SetMeasureTextFunction(Clay_Dimensions (*measureTextFunction)(Clay_String *text, Clay_TextElementConfig *config))`
@ -512,6 +559,16 @@ Takes a pointer to a function that can be used to measure the `width, height` di
**Note 2: It is essential that this function is as fast as possible.** For text heavy use-cases this function is called many times, and despite the fact that clay caches text measurements internally, it can easily become the dominant overall layout cost if the provided function is slow. **This is on the hot path!**
---
### Clay_ResetMeasureTextCache
`void Clay_ResetMeasureTextCache(void)`
Clay caches measurements from the provided MeasureTextFunction, and this will be sufficient for the majority of use-cases. However, if the measurements can depend on external factors that clay does not know about, like DPI changes, then the cached values may be incorrect. When one of these external factors changes, Clay_ResetMeasureTextCache can be called to force clay to recalculate all string measurements in the next frame.
---
### Clay_SetMaxElementCount
`void Clay_SetMaxElementCount(uint32_t maxElementCount)`
@ -520,6 +577,8 @@ Sets the internal maximum element count that will be used in subsequent [Clay_In
**Note: You will need to reinitialize clay, after calling [Clay_MinMemorySize()](#clay_minmemorysize) to calculate updated memory requirements.**
---
### Clay_SetMaxMeasureTextCacheWordCount
`void Clay_SetMaxMeasureTextCacheWordCount(uint32_t maxMeasureTextCacheWordCount)`
@ -528,6 +587,8 @@ Sets the internal text measurement cache size that will be used in subsequent [C
**Note: You will need to reinitialize clay, after calling [Clay_MinMemorySize()](#clay_minmemorysize) to calculate updated memory requirements.**
---
### Clay_Initialize
`Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler)`
@ -536,30 +597,40 @@ Initializes the internal memory mapping, sets the internal dimensions for layout
Reference: [Clay_Arena](#clay_createarenawithcapacityandmemory), [Clay_ErrorHandler](#clay_errorhandler), [Clay_SetCurrentContext](#clay_setcurrentcontext)
---
### Clay_SetCurrentContext
`void Clay_SetCurrentContext(Clay_Context* context)`
Sets the context that subsequent clay commands will operate on. You can get this reference from [Clay_Initialize](#clay_initialize) or [Clay_GetCurrentContext](#clay_getcurrentcontext). See [Running more than one Clay instance](#running-more-than-one-clay-instance).
---
### Clay_GetCurrentContext
`Clay_Context* Clay_GetCurrentContext()`
Returns the context that clay commands are currently operating on, or null if no context has been set. See [Running more than one Clay instance](#running-more-than-one-clay-instance).
---
### Clay_SetLayoutDimensions
`void Clay_SetLayoutDimensions(Clay_Dimensions dimensions)`
Sets the internal layout dimensions. Cheap enough to be called every frame with your screen dimensions to automatically respond to window resizing, etc.
---
### Clay_SetPointerState
`void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown)`
Sets the internal pointer position and state (i.e. current mouse / touch position) and recalculates overlap info, which is used for mouseover / click calculation (via [Clay_PointerOver](#clay_pointerover) and updating scroll containers with [Clay_UpdateScrollContainers](#clay_updatescrollcontainers). **isPointerDown should represent the current state this frame, e.g. it should be `true` for the entire duration the left mouse button is held down.** Clay has internal handling for detecting click / touch start & end.
---
### Clay_UpdateScrollContainers
`void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime)`
@ -570,24 +641,32 @@ Touch / drag scrolling only occurs if the `enableDragScrolling` parameter is `tr
`deltaTime` is the time **in seconds** since the last frame (e.g. 0.016 is **16 milliseconds**), and is used to normalize & smooth scrolling across different refresh rates.
---
### Clay_BeginLayout
`void Clay_BeginLayout()`
Prepares clay to calculate a new layout. Called each frame / layout **before** any of the [Element Macros](#element-macros).
---
### Clay_EndLayout
`Clay_RenderCommandArray Clay_EndLayout()`
Ends declaration of element macros and calculates the results of the current layout. Renders a [Clay_RenderCommandArray](#clay_rendercommandarray) containing the results of the layout calculation.
---
### Clay_Hovered
`bool Clay_Hovered()`
Called **during** layout declaration, and returns `true` if the pointer position previously set with `Clay_SetPointerState` is inside the bounding box of the currently open element. Note: this is based on the element's position from the **last** frame.
---
### Clay_OnHover
`void Clay_OnHover(void (*onHoverFunction)(Clay_ElementId elementId, Clay_PointerData pointerData, intptr_t userData), intptr_t userData)`
@ -607,11 +686,13 @@ void HandleButtonInteraction(Clay_ElementId elementId, Clay_PointerData pointerD
ButtonData linkButton = (ButtonData) { .link = "https://github.com/nicbarker/clay" };
// HandleButtonInteraction will be called for each frame the mouse / pointer / touch is inside the button boundaries
CLAY(CLAY_LAYOUT({ .padding = { 8, 8 }}), Clay_OnHover(HandleButtonInteraction, &buttonData)) {
CLAY(CLAY_LAYOUT({ .padding = CLAY_PADDING_ALL(8)}), Clay_OnHover(HandleButtonInteraction, &buttonData)) {
CLAY_TEXT(CLAY_STRING("Button"), &headerTextConfig);
}
```
---
### Clay_PointerOver
`bool Clay_PointerOver(Clay_ElementId id)`
@ -624,6 +705,8 @@ Returns `true` if the pointer position previously set with `Clay_SetPointerState
Returns [Clay_ScrollContainerData](#clay_scrollcontainerdata) for the scroll container matching the provided ID. This function allows imperative manipulation of scroll position, allowing you to build things such as scroll bars, buttons that "jump" to somewhere in a scroll container, etc.
---
### Clay_GetElementId
`Clay_ElementId Clay_GetElementId(Clay_String idString)`
@ -644,11 +727,12 @@ Returns a [Clay_ElementId](#clay_elementid) for the provided id string, used for
**Notes**
**CLAY** opens a generic empty container, that is configurable and supports nested children.
**CLAY** requires at least 1 parameter, so if you want to create an element without any configuration, use `CLAY(0)`.
**Examples**
```C
// Define an element with 16px of x and y padding
CLAY(CLAY_ID("Outer"), CLAY_LAYOUT({ .padding = {16, 16} })) {
CLAY(CLAY_ID("Outer"), CLAY_LAYOUT({ .padding = CLAY_PADDING_ALL(16) })) {
// A nested child element
CLAY(CLAY_ID("SideBar"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 16 })) {
// Children laid out top to bottom with a 16 px gap between them
@ -664,6 +748,8 @@ CLAY(CLAY_ID("Outer"), CLAY_LAYOUT({ .padding = {16, 16} })) {
}
```
---
### CLAY_ID
**Usage**
@ -686,7 +772,7 @@ To regenerate the same ID outside of layout declaration when using utility funct
// Tag a button with the Id "Button"
CLAY(
CLAY_ID("Button"),
CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW() }, .padding = {16, 16}, .childGap = 16) })
CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16) })
) {
// ...children
}
@ -698,12 +784,63 @@ if (buttonIsHovered && leftMouseButtonPressed) {
}
```
---
### CLAY_IDI()
`Clay_ElementId CLAY_IDI(char *label, int index)`
`Clay_ElementId CLAY_IDI(char *label, int32_t index)`
An offset version of [CLAY_ID](#clay_id). Generates a [Clay_ElementId](#clay_elementid) string id from the provided `char *label`, combined with the `int index`. Used for generating ids for sequential elements (such as in a `for` loop) without having to construct dynamic strings at runtime.
---
### CLAY_ID_LOCAL()
**Usage**
`CLAY(CLAY_ID_LOCAL(char* idString)) {}`
**Lifecycle**
`Clay_BeginLayout()` -> `CLAY(` -> `CLAY_ID_LOCAL()` -> `)` -> `Clay_EndLayout()`
**Notes**
**CLAY_ID_LOCAL()** is used to generate and attach a [Clay_ElementId](#clay_elementid) to a layout element during declaration.
Unlike [CLAY_ID](#clay_id) which needs to be globally unique, a local ID is based on the ID of it's parent and only needs to be unique among its siblings.
As a result, local id is suitable for use in reusable components and loops.
**Examples**
```C
void RenderHeaderButton(ButtonData button) {
CLAY(
CLAY_ID_LOCAL("HeaderButton"),
CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16) })
) {
// ...children
}
}
for (int i = 0; i < headerButtons.length; i++) {
RenderHeaderButton(headerButtons.items[i]);
}
```
---
---
### CLAY_IDI_LOCAL()
`Clay_ElementId CLAY_IDI_LOCAL(char *label, int32_t index)`
An offset version of [CLAY_ID_LOCAL](#clay_local_id). Generates a [Clay_ElementId](#clay_elementid) string id from the provided `char *label`, combined with the `int index`. Used for generating ids for sequential elements (such as in a `for` loop) without having to construct dynamic strings at runtime.
---
### CLAY_LAYOUT
**Usage**
@ -725,7 +862,7 @@ An offset version of [CLAY_ID](#clay_id). Generates a [Clay_ElementId](#clay_ele
Clay_LayoutConfig {
Clay_LayoutDirection layoutDirection = CLAY_LEFT_TO_RIGHT (default) | CLAY_TOP_TO_BOTTOM;
Clay_Padding padding {
float x; float y;
u16 left; u16 right; u16 top; u16 bottom;
};
uint16_t childGap;
Clay_ChildAlignment childAlignment {
@ -733,8 +870,8 @@ Clay_LayoutConfig {
.y = CLAY_ALIGN_Y_TOP (default) | CLAY_ALIGN_Y_CENTER | CLAY_ALIGN_Y_BOTTOM;
};
Clay_Sizing sizing { // Recommended to use the provided macros here - see #sizing for more in depth explanation
.width = CLAY_SIZING_FIT(float min, float max) (default) | CLAY_SIZING_GROW(float min, float max) | CLAY_SIZING_FIXED(width) | CLAY_SIZING_PERCENT(float percent)
.height = CLAY_SIZING_FIT(float min, float max) (default) | CLAY_SIZING_GROW(float min, float max) | CLAY_SIZING_FIXED(height) | CLAY_SIZING_PERCENT(float percent)
.width = CLAY_SIZING_FIT(float min, float max) (default) | CLAY_SIZING_GROW(float min, float max) | CLAY_SIZING_FIXED(float width) | CLAY_SIZING_PERCENT(float percent)
.height = CLAY_SIZING_FIT(float min, float max) (default) | CLAY_SIZING_GROW(float min, float max) | CLAY_SIZING_FIXED(float height) | CLAY_SIZING_PERCENT(float percent)
}; // See CLAY_SIZING_GROW() etc for more details
};
```
@ -756,11 +893,11 @@ _Did you know that "left to right" and "top to bottom" both have 13 letters?_
**`.padding`** - `Clay_Padding`
`CLAY_LAYOUT({ .padding = { .x = 16, .y = 16 } })`
`CLAY_LAYOUT({ .padding = { .left = 16, .right = 16, .top = 8, .bottom = 8 } })`
Controls horizontal and vertical white-space "padding" around the **outside** of child elements.
Controls white-space "padding" around the **outside** of child elements.
<img width="486" alt="Screenshot 2024-08-22 at 10 50 49 AM" src="https://github.com/user-attachments/assets/9311cf10-b8aa-40fe-922a-5dee3663f1a0">
<img width="486" alt="Screenshot 2024-08-22 at 10 50 49 AM" src="https://github.com/user-attachments/assets/b454fa36-92d5-4b1d-bf8b-e4c25428e9de">
---
@ -810,11 +947,13 @@ Controls how final width and height of element are calculated. The same configur
**Example Usage**
```C
CLAY(CLAY_ID("Button"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW() }, .padding = {16, 16}, .childGap = 16) }) {
CLAY(CLAY_ID("Button"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = CLAY_PADDING_ALL(16, .childGap = 16) }) {
// Children will be laid out vertically with 16px of padding around and between
}
```
---
### CLAY_RECTANGLE
**Usage**
@ -896,6 +1035,8 @@ CLAY(
}
```
---
### CLAY_TEXT
**Usage**
@ -1017,6 +1158,8 @@ Element is subject to [culling](#visibility-culling). Otherwise, multiple `Clay_
`Clay_RenderCommand.textContent` will be populated with a `Clay_String` _slice_ of the original string passed in (i.e. wrapping doesn't reallocate, it just returns a `Clay_String` pointing to the start of the new line with a `length`)
---
### CLAY_IMAGE
**Usage**
@ -1114,6 +1257,8 @@ Image *imageToRender = renderCommand->elementConfig.imageElementConfig->imageDat
Element is subject to [culling](#visibility-culling). Otherwise, a single `Clay_RenderCommand`s with `commandType = CLAY_RENDER_COMMAND_TYPE_IMAGE` will be created. The user will need to access `renderCommand->elementConfig.imageElementConfig->imageData` to retrieve image data referenced during layout creation. It's also up to the user to decide how / if they wish to blend `rectangleElementConfig->color` with the image.
---
### CLAY_SCROLL
**Usage**
@ -1173,6 +1318,8 @@ CLAY(CLAY_SCROLL(.vertical = true)) {
}
```
---
### CLAY_BORDER
**Usage**
@ -1290,6 +1437,8 @@ CLAY(
Element is subject to [culling](#visibility-culling). Otherwise, a single `Clay_RenderCommand` with `commandType = CLAY_RENDER_COMMAND_TYPE_BORDER` representing the container will be created.
Rendering of borders and rounded corners is left up to the user. See the provided [Raylib Renderer](https://github.com/nicbarker/clay/tree/main/renderers/raylib) for examples of how to draw borders using line and curve primitives.
---
### CLAY_FLOATING
**Usage**
@ -1467,17 +1616,17 @@ Controls whether pointer events like hover and click should pass through to cont
```C
// Horizontal container with three option buttons
CLAY(CLAY_ID("OptionsList"), CLAY_LAYOUT(.childGap = 16)) {
CLAY_RECTANGLE(CLAY_IDI("Option", 1), CLAY_LAYOUT(.padding = {16, 16}), CLAY_RECTANGLE(.color = COLOR_BLUE)) {
CLAY_RECTANGLE(CLAY_IDI("Option", 1), CLAY_LAYOUT(.padding = CLAY_PADDING_ALL(16)), CLAY_RECTANGLE(.color = COLOR_BLUE)) {
CLAY_TEXT(CLAY_IDI("OptionText", 1), CLAY_STRING("Option 1"), CLAY_TEXT_CONFIG());
}
CLAY_RECTANGLE(CLAY_IDI("Option", 2), CLAY_LAYOUT(.padding = {16, 16}), CLAY_RECTANGLE(.color = COLOR_BLUE)) {
CLAY_RECTANGLE(CLAY_IDI("Option", 2), CLAY_LAYOUT(.padding = CLAY_PADDING_ALL(16)), CLAY_RECTANGLE(.color = COLOR_BLUE)) {
CLAY_TEXT(CLAY_IDI("OptionText", 2), CLAY_STRING("Option 2"), CLAY_TEXT_CONFIG());
// Floating tooltip will attach above the "Option 2" container and not affect widths or positions of other elements
CLAY_FLOATING(CLAY_ID("OptionTooltip"), &CLAY_LAYOUT_DEFAULT, CLAY_FLOATING({ .zIndex = 1, .attachment = { .element = CLAY_ATTACH_POINT_CENTER_BOTTOM, .parent = CLAY_ATTACH_POINT_CENTER_TOP } })) {
CLAY_TEXT(CLAY_IDI("OptionTooltipText", 1), CLAY_STRING("Most popular!"), CLAY_TEXT_CONFIG());
}
}
CLAY_RECTANGLE(CLAY_IDI("Option", 3), CLAY_LAYOUT(.padding = {16, 16}), CLAY_RECTANGLE(.color = COLOR_BLUE)) {
CLAY_RECTANGLE(CLAY_IDI("Option", 3), CLAY_LAYOUT(.padding = CLAY_PADDING_ALL(16)), CLAY_RECTANGLE(.color = COLOR_BLUE)) {
CLAY_TEXT(CLAY_IDI("OptionText", 3), CLAY_STRING("Option 3"), CLAY_TEXT_CONFIG());
}
}
@ -1501,6 +1650,8 @@ When using `.parentId`, the floating container can be declared anywhere after `B
`CLAY_FLOATING` elements will not generate any render commands.
---
### CLAY_CUSTOM_ELEMENT
**Usage**
@ -1627,6 +1778,8 @@ The number of characters in the string, _not including an optional null terminat
A pointer to the contents of the string. This data is not guaranteed to be null terminated, so if you are passing it to code that expects standard null terminated C strings, you will need to copy the data and append a null terminator.
---
### Clay_ElementId
```C
@ -1664,6 +1817,7 @@ If this id was generated using [CLAY_IDI](#clay_idi), `.baseId` is the hash of t
Stores the original string that was passed in when [CLAY_ID](#clay_id) or [CLAY_IDI](#clay_idi) were called.
---
### Clay_RenderCommandArray
@ -1697,6 +1851,8 @@ Represents the total number of `Clay_RenderCommand` elements stored consecutivel
An array of [Clay_RenderCommand](#clay_rendercommand)s representing the calculated layout. If there was at least one render command, this array will contain elements from `.internalArray[0]` to `.internalArray[.length - 1]`.
---
### Clay_RenderCommand
```C
@ -1763,6 +1919,8 @@ Only used if `.commandType == CLAY_RENDER_COMMAND_TYPE_TEXT`. A `Clay_String` co
The id that was originally used with the element macro that created this render command. See [CLAY_ID](#clay_id) for details.
---
### Clay_ScrollContainerData
```C
@ -1812,6 +1970,8 @@ Dimensions representing the inner width and height of the content _inside_ the s
The [Clay_ScrollElementConfig](#clay_scroll) for the matching scroll container element.
---
### Clay_PointerData
```C
@ -1925,4 +2085,4 @@ A [Clay_String](#clay_string) that provides a human readable description of the
A generic pointer to extra userdata that is transparently passed through from `Clay_Initialize` to Clay's error handler callback. Defaults to NULL.
---
---

1
bindings/cpp/README.md Normal file
View File

@ -0,0 +1 @@
https://github.com/TimothyHoytBSME/ClayMan

View File

@ -2,7 +2,7 @@ cp ../../clay.h clay.c;
# Intel Mac
clang -c -DCLAY_IMPLEMENTATION -o clay.o -static -target x86_64-apple-darwin clay.c -fPIC && ar r clay-odin/macos/clay.a clay.o;
# ARM Mac
clang -c -DCLAY_IMPLEMENTATION -o clay.o -static clay.c -fPIC && ar r clay-odin/macos-arm64/clay.a clay.o;
clang -c -DCLAY_IMPLEMENTATION -g -o clay.o -static clay.c -fPIC && ar r clay-odin/macos-arm64/clay.a clay.o;
# x64 Windows
clang -c -DCLAY_IMPLEMENTATION -o clay-odin/windows/clay.lib -target x86_64-pc-windows-msvc -fuse-ld=llvm-lib -static clay.c;
# Linux

View File

@ -22,6 +22,12 @@ String :: struct {
chars: [^]c.char,
}
StringSlice :: struct {
length: c.int32_t,
chars: [^]c.char,
baseChars: [^]c.char,
}
Vector2 :: [2]c.float
Dimensions :: struct {
@ -105,12 +111,13 @@ TextWrapMode :: enum EnumBackingType {
}
TextElementConfig :: struct {
textColor: Color,
fontId: u16,
fontSize: u16,
letterSpacing: u16,
lineHeight: u16,
wrapMode: TextWrapMode,
textColor: Color,
fontId: u16,
fontSize: u16,
letterSpacing: u16,
lineHeight: u16,
wrapMode: TextWrapMode,
hashStringContents: bool,
}
ImageElementConfig :: struct {
@ -178,7 +185,8 @@ ElementConfigUnion :: struct #raw_union {
RenderCommand :: struct {
boundingBox: BoundingBox,
config: ElementConfigUnion,
text: String,
text: StringSlice,
zIndex: i32,
id: u32,
commandType: RenderCommandType,
}
@ -223,8 +231,10 @@ Sizing :: struct {
}
Padding :: struct {
x: u16,
y: u16,
left: u16,
right: u16,
top: u16,
bottom: u16,
}
LayoutDirection :: enum EnumBackingType {
@ -303,7 +313,7 @@ foreign Clay {
PointerOver :: proc(id: ElementId) -> bool ---
GetElementId :: proc(id: String) -> ElementId ---
GetScrollContainerData :: proc(id: ElementId) -> ScrollContainerData ---
SetMeasureTextFunction :: proc(measureTextFunction: proc "c" (text: ^String, config: ^TextElementConfig) -> Dimensions) ---
SetMeasureTextFunction :: proc(measureTextFunction: proc "c" (text: StringSlice, config: ^TextElementConfig, userData: uintptr) -> Dimensions, userData: uintptr) ---
RenderCommandArray_Get :: proc(array: ^ClayArray(RenderCommand), index: i32) -> ^RenderCommand ---
SetDebugModeEnabled :: proc(enabled: bool) ---
}
@ -350,6 +360,10 @@ Layout :: proc(config: LayoutConfig) -> TypedConfig {
return {type = ElementConfigType.Layout, config = _StoreLayoutConfig(config) }
}
PaddingAll :: proc (padding: u16) -> Padding {
return { padding, padding, padding, padding }
}
Rectangle :: proc(config: RectangleElementConfig) -> TypedConfig {
return {type = ElementConfigType.Rectangle, config = _StoreRectangleElementConfig(config)}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -60,7 +60,7 @@ headerTextConfig := clay.TextElementConfig {
LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Color, text: string, image: ^raylib.Texture2D) {
if clay.UI(
clay.ID("HeroBlob", index),
clay.Layout({sizing = {width = clay.SizingGrow({max = 480})}, padding = clay.Padding{16, 16}, childGap = 16, childAlignment = clay.ChildAlignment{y = .CENTER}}),
clay.Layout({sizing = {width = clay.SizingGrow({max = 480})}, padding = clay.PaddingAll(16), childGap = 16, childAlignment = clay.ChildAlignment{y = .CENTER}}),
clay.BorderOutsideRadius({2, color}, 10),
) {
if clay.UI(
@ -75,11 +75,11 @@ LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Colo
LandingPageDesktop :: proc() {
if clay.UI(
clay.ID("LandingPage1Desktop"),
clay.Layout({sizing = {width = clay.SizingGrow({}), height = clay.SizingFit({min = cast(f32)windowHeight - 70})}, childAlignment = {y = .CENTER}, padding = {x = 50}}),
clay.Layout({sizing = {width = clay.SizingGrow({}), height = clay.SizingFit({min = cast(f32)windowHeight - 70})}, childAlignment = {y = .CENTER}, padding = {left = 50, right = 50}}),
) {
if clay.UI(
clay.ID("LandingPage1"),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, childAlignment = {y = .CENTER}, padding = {32, 32}, childGap = 32}),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, childAlignment = {y = .CENTER}, padding = clay.PaddingAll(32), childGap = 32}),
clay.Border({left = {2, COLOR_RED}, right = {2, COLOR_RED}}),
) {
if clay.UI(clay.ID("LeftText"), clay.Layout({sizing = {width = clay.SizingPercent(0.55)}, layoutDirection = .TOP_TO_BOTTOM, childGap = 8})) {
@ -115,7 +115,7 @@ LandingPageMobile :: proc() {
layoutDirection = .TOP_TO_BOTTOM,
sizing = {width = clay.SizingGrow({}), height = clay.SizingFit({min = cast(f32)windowHeight - 70})},
childAlignment = {x = .CENTER, y = .CENTER},
padding = {16, 32},
padding = {16, 16, 32, 32},
childGap = 32,
},
),
@ -148,9 +148,9 @@ FeatureBlocks :: proc(widthSizing: clay.SizingAxis, outerPadding: u16) {
textConfig := clay.TextConfig({fontSize = 24, fontId = FONT_ID_BODY_24, textColor = COLOR_RED})
if clay.UI(
clay.ID("HFileBoxOuter"),
clay.Layout({layoutDirection = .TOP_TO_BOTTOM, sizing = {width = widthSizing}, childAlignment = {y = .CENTER}, padding = {outerPadding, 32}, childGap = 8}),
clay.Layout({layoutDirection = .TOP_TO_BOTTOM, sizing = {width = widthSizing}, childAlignment = {y = .CENTER}, padding = {outerPadding, outerPadding, 32, 32}, childGap = 8}),
) {
if clay.UI(clay.ID("HFileIncludeOuter"), clay.Layout({padding = {8, 4}}), clay.Rectangle({color = COLOR_RED, cornerRadius = clay.CornerRadiusAll(8)})) {
if clay.UI(clay.ID("HFileIncludeOuter"), clay.Layout({padding = {8, 8, 4, 4}}), clay.Rectangle({color = COLOR_RED, cornerRadius = clay.CornerRadiusAll(8)})) {
clay.Text("#include clay.h", clay.TextConfig({fontSize = 24, fontId = FONT_ID_BODY_24, textColor = COLOR_LIGHT}))
}
clay.Text("~2000 lines of C99.", textConfig)
@ -158,7 +158,7 @@ FeatureBlocks :: proc(widthSizing: clay.SizingAxis, outerPadding: u16) {
}
if clay.UI(
clay.ID("BringYourOwnRendererOuter"),
clay.Layout({layoutDirection = .TOP_TO_BOTTOM, sizing = {width = widthSizing}, childAlignment = {y = .CENTER}, padding = {x = outerPadding, y = 32}, childGap = 8}),
clay.Layout({layoutDirection = .TOP_TO_BOTTOM, sizing = {width = widthSizing}, childAlignment = {y = .CENTER}, padding = {outerPadding, outerPadding, 32, 32}, childGap = 8}),
) {
clay.Text("Renderer agnostic.", clay.TextConfig({fontId = FONT_ID_BODY_24, fontSize = 24, textColor = COLOR_ORANGE}))
clay.Text("Layout with clay, then render with Raylib, WebGL Canvas or even as HTML.", textConfig)
@ -217,11 +217,11 @@ DeclarativeSyntaxPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizi
DeclarativeSyntaxPageDesktop :: proc() {
if clay.UI(
clay.ID("SyntaxPageDesktop"),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingFit({min = cast(f32)windowHeight - 50})}, childAlignment = {y = .CENTER}, padding = {x = 50}}),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingFit({min = cast(f32)windowHeight - 50})}, childAlignment = {y = .CENTER}, padding = {left = 50, right = 50}}),
) {
if clay.UI(
clay.ID("SyntaxPage"),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, childAlignment = {y = .CENTER}, padding = {32, 32}, childGap = 32}),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, childAlignment = {y = .CENTER}, padding = clay.PaddingAll(32), childGap = 32}),
clay.Border({left = {2, COLOR_RED}, right = {2, COLOR_RED}}),
) {
DeclarativeSyntaxPage({fontSize = 52, fontId = FONT_ID_TITLE_52, textColor = COLOR_RED}, clay.SizingPercent(0.5))
@ -237,7 +237,7 @@ DeclarativeSyntaxPageMobile :: proc() {
layoutDirection = .TOP_TO_BOTTOM,
sizing = {clay.SizingGrow({}), clay.SizingFit({min = cast(f32)windowHeight - 50})},
childAlignment = {x = .CENTER, y = .CENTER},
padding = {16, 32},
padding = {16, 16, 32, 32},
childGap = 16,
},
),
@ -277,14 +277,14 @@ HighPerformancePage :: proc(lerpValue: f32, titleTextConfig: clay.TextElementCon
) {
if clay.UI(
clay.ID("AnimationDemoContainerLeft"),
clay.Layout({sizing = {clay.SizingPercent(0.35 + 0.3 * lerpValue), clay.SizingGrow({})}, childAlignment = {y = .CENTER}, padding = {16, 16}}),
clay.Layout({sizing = {clay.SizingPercent(0.35 + 0.3 * lerpValue), clay.SizingGrow({})}, childAlignment = {y = .CENTER}, padding = clay.PaddingAll(16)}),
clay.Rectangle({color = ColorLerp(COLOR_RED, COLOR_ORANGE, lerpValue)}),
) {
clay.Text(LOREM_IPSUM_TEXT, clay.TextConfig({fontSize = 16, fontId = FONT_ID_BODY_16, textColor = COLOR_LIGHT}))
}
if clay.UI(
clay.ID("AnimationDemoContainerRight"),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, childAlignment = {y = .CENTER}, padding = {16, 16}}),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, childAlignment = {y = .CENTER}, padding = clay.PaddingAll(16)}),
clay.Rectangle({color = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue)}),
) {
clay.Text(LOREM_IPSUM_TEXT, clay.TextConfig({fontSize = 16, fontId = FONT_ID_BODY_16, textColor = COLOR_LIGHT}))
@ -297,7 +297,7 @@ HighPerformancePageDesktop :: proc(lerpValue: f32) {
if clay.UI(
clay.ID("PerformanceDesktop"),
clay.Layout(
{sizing = {clay.SizingGrow({}), clay.SizingFit({min = cast(f32)windowHeight - 50})}, childAlignment = {y = .CENTER}, padding = {x = 82, y = 32}, childGap = 64},
{sizing = {clay.SizingGrow({}), clay.SizingFit({min = cast(f32)windowHeight - 50})}, childAlignment = {y = .CENTER}, padding = {82, 82, 32, 32}, childGap = 64},
),
clay.Rectangle({color = COLOR_RED}),
) {
@ -313,7 +313,7 @@ HighPerformancePageMobile :: proc(lerpValue: f32) {
layoutDirection = .TOP_TO_BOTTOM,
sizing = {clay.SizingGrow({}), clay.SizingFit({min = cast(f32)windowHeight - 50})},
childAlignment = {x = .CENTER, y = .CENTER},
padding = {x = 16, y = 32},
padding = { 16, 16, 32, 32},
childGap = 32,
},
),
@ -325,7 +325,7 @@ HighPerformancePageMobile :: proc(lerpValue: f32) {
RendererButtonActive :: proc(index: i32, text: string) {
if clay.UI(
clay.Layout({sizing = {width = clay.SizingFixed(300)}, padding = {16, 16}}),
clay.Layout({sizing = {width = clay.SizingFixed(300)}, padding = clay.PaddingAll(16)}),
clay.Rectangle({color = COLOR_RED, cornerRadius = clay.CornerRadiusAll(10)}),
) {
clay.Text(text, clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_LIGHT}))
@ -336,7 +336,7 @@ RendererButtonInactive :: proc(index: u32, text: string) {
if clay.UI(clay.Layout({}), clay.BorderOutsideRadius({2, COLOR_RED}, 10)) {
if clay.UI(
clay.ID("RendererButtonInactiveInner", index),
clay.Layout({sizing = {width = clay.SizingFixed(300)}, padding = {16, 16}}),
clay.Layout({sizing = {width = clay.SizingFixed(300)}, padding = clay.PaddingAll(16)}),
clay.Rectangle({color = COLOR_LIGHT, cornerRadius = clay.CornerRadiusAll(10)}),
) {
clay.Text(text, clay.TextConfig({fontSize = 28, fontId = FONT_ID_BODY_28, textColor = COLOR_RED}))
@ -374,11 +374,11 @@ RendererPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizing: clay.
RendererPageDesktop :: proc() {
if clay.UI(
clay.ID("RendererPageDesktop"),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingFit({min = cast(f32)windowHeight - 50})}, childAlignment = {y = .CENTER}, padding = {x = 50}}),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingFit({min = cast(f32)windowHeight - 50})}, childAlignment = {y = .CENTER}, padding = {left = 50, right = 50}}),
) {
if clay.UI(
clay.ID("RendererPage"),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, childAlignment = {y = .CENTER}, padding = {32, 32}, childGap = 32}),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingGrow({})}, childAlignment = {y = .CENTER}, padding = clay.PaddingAll(32), childGap = 32}),
clay.Border({left = {2, COLOR_RED}, right = {2, COLOR_RED}}),
) {
RendererPage({fontSize = 52, fontId = FONT_ID_TITLE_52, textColor = COLOR_RED}, clay.SizingPercent(0.5))
@ -394,7 +394,7 @@ RendererPageMobile :: proc() {
layoutDirection = .TOP_TO_BOTTOM,
sizing = {clay.SizingGrow({}), clay.SizingFit({min = cast(f32)windowHeight - 50})},
childAlignment = {x = .CENTER, y = .CENTER},
padding = {x = 16, y = 32},
padding = {16, 16, 32, 32},
childGap = 32,
},
),
@ -423,7 +423,7 @@ createLayout :: proc(lerpValue: f32) -> clay.ClayArray(clay.RenderCommand) {
) {
if clay.UI(
clay.ID("Header"),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingFixed(50)}, childAlignment = {y = .CENTER}, childGap = 24, padding = {x = 32}}),
clay.Layout({sizing = {clay.SizingGrow({}), clay.SizingFixed(50)}, childAlignment = {y = .CENTER}, childGap = 24, padding = {left = 32, right = 32}}),
) {
clay.Text("Clay", &headerTextConfig)
if clay.UI(clay.Layout({sizing = {width = clay.SizingGrow({})}})) {}
@ -438,7 +438,7 @@ createLayout :: proc(lerpValue: f32) -> clay.ClayArray(clay.RenderCommand) {
}
if clay.UI(
clay.ID("LinkGithubOuter"),
clay.Layout({padding = {16, 6}}),
clay.Layout({padding = {16, 16, 6, 6}}),
clay.BorderOutsideRadius({2, COLOR_RED}, 10),
clay.Rectangle({cornerRadius = clay.CornerRadiusAll(10), color = clay.PointerOver(clay.GetElementId(clay.MakeString("LinkGithubOuter"))) ? COLOR_LIGHT_HOVER : COLOR_LIGHT})
) {
@ -493,8 +493,8 @@ main :: proc() {
minMemorySize: u32 = clay.MinMemorySize()
memory := make([^]u8, minMemorySize)
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(minMemorySize, memory)
clay.SetMeasureTextFunction(measureText)
clay.Initialize(arena, {cast(f32)raylib.GetScreenWidth(), cast(f32)raylib.GetScreenHeight()}, { handler = errorHandler })
clay.SetMeasureTextFunction(measureText, 0)
raylib.SetConfigFlags({.VSYNC_HINT, .WINDOW_RESIZABLE, .WINDOW_HIGHDPI, .MSAA_4X_HINT})
raylib.InitWindow(windowWidth, windowHeight, "Raylib Odin Example")

View File

@ -16,7 +16,7 @@ clayColorToRaylibColor :: proc(color: clay.Color) -> raylib.Color {
raylibFonts := [10]RaylibFont{}
measureText :: proc "c" (text: ^clay.String, config: ^clay.TextElementConfig) -> clay.Dimensions {
measureText :: proc "c" (text: clay.StringSlice, config: ^clay.TextElementConfig, userData: uintptr) -> clay.Dimensions {
// Measure string size for Font
textSize: clay.Dimensions = {0, 0}

2
bindings/zig/README Normal file
View File

@ -0,0 +1,2 @@
https://codeberg.org/Zettexe/clay-zig
https://github.com/johan0A/clay-zig-bindings

2981
clay.h

File diff suppressed because it is too large Load Diff

View File

@ -23,6 +23,15 @@ FetchContent_Declare(
)
FetchContent_MakeAvailable(SDL2_ttf)
FetchContent_Declare(
SDL2_image
GIT_REPOSITORY "https://github.com/libsdl-org/SDL_image.git"
GIT_TAG "release-2.8.4"
GIT_PROGRESS TRUE
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(SDL2_image)
add_executable(SDL2_video_demo main.c)
target_compile_options(SDL2_video_demo PUBLIC)
@ -32,10 +41,15 @@ target_link_libraries(SDL2_video_demo PUBLIC
SDL2::SDL2main
SDL2::SDL2-static
SDL2_ttf::SDL2_ttf-static
SDL2_image::SDL2_image-static
)
set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O3")
if(MSVC)
set(CMAKE_C_FLAGS_DEBUG "/D CLAY_DEBUG")
else()
set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O3")
endif()
add_custom_command(
TARGET SDL2_video_demo POST_BUILD

View File

@ -10,13 +10,14 @@
#include <stdint.h>
#include <stdlib.h>
const int FONT_ID_BODY_16 = 0;
Clay_Color COLOR_WHITE = { 255, 255, 255, 255};
SDL_Surface *sample_image;
void RenderHeaderButton(Clay_String text) {
CLAY(
CLAY_LAYOUT({ .padding = { 16, 8 }}),
CLAY_LAYOUT({ .padding = { 16, 16, 8, 8 }}),
CLAY_RECTANGLE({
.color = { 140, 140, 140, 255 },
.cornerRadius = 5
@ -31,7 +32,7 @@ void RenderHeaderButton(Clay_String text) {
}
void RenderDropdownMenuItem(Clay_String text) {
CLAY(CLAY_LAYOUT({ .padding = { 16, 16 }})) {
CLAY(CLAY_LAYOUT({ .padding = CLAY_PADDING_ALL(16)})) {
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
.fontId = FONT_ID_BODY_16,
.fontSize = 16,
@ -74,8 +75,8 @@ void HandleSidebarInteraction(
static Clay_RenderCommandArray CreateLayout() {
Clay_BeginLayout();
Clay_Sizing layoutExpand = {
.width = CLAY_SIZING_GROW(),
.height = CLAY_SIZING_GROW()
.width = CLAY_SIZING_GROW(0),
.height = CLAY_SIZING_GROW(0)
};
Clay_RectangleElementConfig contentBackgroundConfig = {
@ -91,7 +92,7 @@ static Clay_RenderCommandArray CreateLayout() {
CLAY_LAYOUT({
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.sizing = layoutExpand,
.padding = { 16, 16 },
.padding = CLAY_PADDING_ALL(16),
.childGap = 16
})
) {
@ -102,7 +103,7 @@ static Clay_RenderCommandArray CreateLayout() {
CLAY_LAYOUT({
.sizing = {
.height = CLAY_SIZING_FIXED(60),
.width = CLAY_SIZING_GROW()
.width = CLAY_SIZING_GROW(0)
},
.padding = { 16 },
.childGap = 16,
@ -112,9 +113,18 @@ static Clay_RenderCommandArray CreateLayout() {
})
) {
// Header buttons go here
CLAY(
CLAY_LAYOUT({ .padding = { 16, 16, 8, 8 }}),
CLAY_BORDER_ALL({ 2, COLOR_WHITE })
) {
CLAY(
CLAY_LAYOUT({ .padding = { 8, 8, 8, 8 }}),
CLAY_IMAGE({ sample_image, { 23, 42 } })
) {}
}
CLAY(
CLAY_ID("FileButton"),
CLAY_LAYOUT({ .padding = { 16, 8 }}),
CLAY_LAYOUT({ .padding = { 16, 16, 8, 8 }}),
CLAY_RECTANGLE({
.color = { 140, 140, 140, 255 },
.cornerRadius = 5
@ -164,7 +174,7 @@ static Clay_RenderCommandArray CreateLayout() {
}
}
RenderHeaderButton(CLAY_STRING("Edit"));
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }})) {}
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }})) {}
RenderHeaderButton(CLAY_STRING("Upload"));
RenderHeaderButton(CLAY_STRING("Media"));
RenderHeaderButton(CLAY_STRING("Support"));
@ -179,19 +189,19 @@ static Clay_RenderCommandArray CreateLayout() {
CLAY_RECTANGLE(contentBackgroundConfig),
CLAY_LAYOUT({
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.padding = { 16, 16 },
.padding = CLAY_PADDING_ALL(16),
.childGap = 8,
.sizing = {
.width = CLAY_SIZING_FIXED(250),
.height = CLAY_SIZING_GROW()
.height = CLAY_SIZING_GROW(0)
}
})
) {
for (int i = 0; i < documents.length; i++) {
Document document = documents.documents[i];
Clay_LayoutConfig sidebarButtonLayout = {
.sizing = { .width = CLAY_SIZING_GROW() },
.padding = { 16, 16 }
.sizing = { .width = CLAY_SIZING_GROW(0) },
.padding = CLAY_PADDING_ALL(16)
};
if (i == selectedDocumentIndex) {
@ -236,7 +246,7 @@ static Clay_RenderCommandArray CreateLayout() {
CLAY_LAYOUT({
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.childGap = 16,
.padding = { 16, 16 },
.padding = CLAY_PADDING_ALL(16),
.sizing = layoutExpand
})
) {
@ -262,7 +272,7 @@ void HandleClayErrors(Clay_ErrorData errorData) {
printf("%s", errorData.errorText.chars);
}
int main(void) {
int main(int argc, char *argv[]) {
documents.documents = (Document[]) {
{ .title = CLAY_STRING("Squirrels"), .contents = CLAY_STRING("The Secret Life of Squirrels: Nature's Clever Acrobats\n""Squirrels are often overlooked creatures, dismissed as mere park inhabitants or backyard nuisances. Yet, beneath their fluffy tails and twitching noses lies an intricate world of cunning, agility, and survival tactics that are nothing short of fascinating. As one of the most common mammals in North America, squirrels have adapted to a wide range of environments from bustling urban centers to tranquil forests and have developed a variety of unique behaviors that continue to intrigue scientists and nature enthusiasts alike.\n""\n""Master Tree Climbers\n""At the heart of a squirrel's skill set is its impressive ability to navigate trees with ease. Whether they're darting from branch to branch or leaping across wide gaps, squirrels possess an innate talent for acrobatics. Their powerful hind legs, which are longer than their front legs, give them remarkable jumping power. With a tail that acts as a counterbalance, squirrels can leap distances of up to ten times the length of their body, making them some of the best aerial acrobats in the animal kingdom.\n""But it's not just their agility that makes them exceptional climbers. Squirrels' sharp, curved claws allow them to grip tree bark with precision, while the soft pads on their feet provide traction on slippery surfaces. Their ability to run at high speeds and scale vertical trunks with ease is a testament to the evolutionary adaptations that have made them so successful in their arboreal habitats.\n""\n""Food Hoarders Extraordinaire\n""Squirrels are often seen frantically gathering nuts, seeds, and even fungi in preparation for winter. While this behavior may seem like instinctual hoarding, it is actually a survival strategy that has been honed over millions of years. Known as \"scatter hoarding,\" squirrels store their food in a variety of hidden locations, often burying it deep in the soil or stashing it in hollowed-out tree trunks.\n""Interestingly, squirrels have an incredible memory for the locations of their caches. Research has shown that they can remember thousands of hiding spots, often returning to them months later when food is scarce. However, they don't always recover every stash some forgotten caches eventually sprout into new trees, contributing to forest regeneration. This unintentional role as forest gardeners highlights the ecological importance of squirrels in their ecosystems.\n""\n""The Great Squirrel Debate: Urban vs. Wild\n""While squirrels are most commonly associated with rural or wooded areas, their adaptability has allowed them to thrive in urban environments as well. In cities, squirrels have become adept at finding food sources in places like parks, streets, and even garbage cans. However, their urban counterparts face unique challenges, including traffic, predators, and the lack of natural shelters. Despite these obstacles, squirrels in urban areas are often observed using human infrastructure such as buildings, bridges, and power lines as highways for their acrobatic escapades.\n""There is, however, a growing concern regarding the impact of urban life on squirrel populations. Pollution, deforestation, and the loss of natural habitats are making it more difficult for squirrels to find adequate food and shelter. As a result, conservationists are focusing on creating squirrel-friendly spaces within cities, with the goal of ensuring these resourceful creatures continue to thrive in both rural and urban landscapes.\n""\n""A Symbol of Resilience\n""In many cultures, squirrels are symbols of resourcefulness, adaptability, and preparation. Their ability to thrive in a variety of environments while navigating challenges with agility and grace serves as a reminder of the resilience inherent in nature. Whether you encounter them in a quiet forest, a city park, or your own backyard, squirrels are creatures that never fail to amaze with their endless energy and ingenuity.\n""In the end, squirrels may be small, but they are mighty in their ability to survive and thrive in a world that is constantly changing. So next time you spot one hopping across a branch or darting across your lawn, take a moment to appreciate the remarkable acrobat at work a true marvel of the natural world.\n") },
{ .title = CLAY_STRING("Lorem Ipsum"), .contents = CLAY_STRING("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.") },
@ -279,17 +289,26 @@ int main(void) {
fprintf(stderr, "Error: could not initialize TTF: %s\n", TTF_GetError());
return 1;
}
if (IMG_Init(IMG_INIT_PNG) < 0) {
fprintf(stderr, "Error: could not initialize IMG: %s\n", IMG_GetError());
return 1;
}
TTF_Font *font = TTF_OpenFont("resources/Roboto-Regular.ttf", 16);
if (!font) {
fprintf(stderr, "Error: could not load font: %s\n", TTF_GetError());
return 1;
}
SDL2_fonts[FONT_ID_BODY_16] = (SDL2_Font) {
SDL2_Font fonts[1] = {};
fonts[FONT_ID_BODY_16] = (SDL2_Font) {
.fontId = FONT_ID_BODY_16,
.font = font,
};
sample_image = IMG_Load("resources/sample.png");
SDL_Window *window = NULL;
SDL_Renderer *renderer = NULL;
if (SDL_CreateWindowAndRenderer(800, 600, SDL_WINDOW_RESIZABLE, &window, &renderer) < 0) {
@ -299,12 +318,13 @@ int main(void) {
uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
Clay_SetMeasureTextFunction(SDL2_MeasureText);
int windowWidth = 0;
int windowHeight = 0;
SDL_GetWindowSize(window, &windowWidth, &windowHeight);
Clay_Initialize(clayMemory, (Clay_Dimensions) { (float)windowWidth, (float)windowHeight }, (Clay_ErrorHandler) { HandleClayErrors });
Clay_SetMeasureTextFunction(SDL2_MeasureText, (uintptr_t)&fonts);
Uint64 NOW = SDL_GetPerformanceCounter();
Uint64 LAST = 0;
double deltaTime = 0;
@ -345,7 +365,7 @@ int main(void) {
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
Clay_SDL2_Render(renderer, renderCommands);
Clay_SDL2_Render(renderer, renderCommands, fonts);
SDL_RenderPresent(renderer);
}
@ -353,6 +373,7 @@ int main(void) {
quit:
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
IMG_Quit();
TTF_Quit();
SDL_Quit();
return 0;

Binary file not shown.

After

Width:  |  Height:  |  Size: 850 B

View File

@ -0,0 +1,49 @@
cmake_minimum_required(VERSION 3.27)
# Project setup
project(clay_examples_sdl3_simple_demo C)
set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -g")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3")
include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)
# Download SDL3
FetchContent_Declare(
SDL
GIT_REPOSITORY https://github.com/libsdl-org/SDL.git
GIT_TAG preview-3.1.6
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
message(STATUS "Using SDL via FetchContent")
FetchContent_MakeAvailable(SDL)
set_property(DIRECTORY "${sdl_SOURCE_DIR}" PROPERTY EXCLUDE_FROM_ALL TRUE)
# Download SDL_ttf
FetchContent_Declare(
SDL_ttf
GIT_REPOSITORY https://github.com/libsdl-org/SDL_ttf.git
GIT_TAG main # Slightly risky to use main branch, but it's the only one available
GIT_SHALLOW TRUE
GIT_PROGRESS TRUE
)
message(STATUS "Using SDL_ttf via FetchContent")
FetchContent_MakeAvailable(SDL_ttf)
set_property(DIRECTORY "${sdl_ttf_SOURCE_DIR}" PROPERTY EXCLUDE_FROM_ALL TRUE)
# Example executable
add_executable(${PROJECT_NAME} main.c)
target_link_libraries(${PROJECT_NAME} PRIVATE
SDL3::SDL3
SDL3_ttf::SDL3_ttf
)
add_custom_command(
TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/resources
${CMAKE_CURRENT_BINARY_DIR}/resources
)

View File

@ -0,0 +1,215 @@
#define SDL_MAIN_USE_CALLBACKS
#include <SDL3/SDL_main.h>
#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
#define CLAY_IMPLEMENTATION
#include "../../clay.h"
#include <stdio.h>
#include "../../renderers/SDL3/clay_renderer_SDL3.c"
static const Uint32 FONT_ID = 0;
static const Clay_Color COLOR_ORANGE = (Clay_Color) {225, 138, 50, 255};
static const Clay_Color COLOR_BLUE = (Clay_Color) {111, 173, 162, 255};
static const Clay_Color COLOR_LIGHT = (Clay_Color) {224, 215, 210, 255};
typedef struct app_state {
SDL_Window *window;
SDL_Renderer *renderer;
} AppState;
static inline Clay_Dimensions SDL_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData)
{
TTF_Font *font = gFonts[config->fontId];
int width, height;
if (!TTF_GetStringSize(font, text.chars, text.length, &width, &height)) {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to measure text: %s", SDL_GetError());
}
return (Clay_Dimensions) { (float) width, (float) height };
}
static void Label(const Clay_String text, const int cornerRadius)
{
CLAY(CLAY_LAYOUT({ .padding = {8, 8} }),
CLAY_RECTANGLE({
.color = Clay_Hovered() ? COLOR_BLUE : COLOR_ORANGE,
.cornerRadius = cornerRadius,
})) {
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
.textColor = { 255, 255, 255, 255 },
.fontId = FONT_ID,
.fontSize = 24,
}));
}
}
static void LabelBorder(const Clay_String text, const int cornerRadius, const int thickness)
{
CLAY(
CLAY_LAYOUT({
.padding = {16, 16, 8, 8 } }),
CLAY_BORDER_OUTSIDE_RADIUS(
thickness,
COLOR_BLUE,
cornerRadius)
){
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
.textColor = { 255, 255, 255, 255 },
.fontId = FONT_ID,
.fontSize = 24,
}));
}
}
static Clay_RenderCommandArray Clay_CreateLayout()
{
Clay_BeginLayout();
CLAY(CLAY_ID("MainContent"),
CLAY_LAYOUT({
.sizing = {
.width = CLAY_SIZING_GROW(),
.height = CLAY_SIZING_GROW(),
},
.childAlignment = {
.x = CLAY_ALIGN_X_CENTER,
.y = CLAY_ALIGN_Y_CENTER,
},
.childGap = 10,
.padding = { 10, 10 },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
}),
CLAY_BORDER({
.left = { 20, COLOR_BLUE },
.right = { 20, COLOR_BLUE },
.bottom = { 20, COLOR_BLUE }
}),
CLAY_RECTANGLE({
.color = COLOR_LIGHT,
})
) {
Label(CLAY_STRING("Rounded - Button 1"), 10);
Label(CLAY_STRING("Straight - Button 2") , 0);
Label(CLAY_STRING("Rounded+ - Button 3") , 20);
LabelBorder(CLAY_STRING("Border - Button 4"), 0, 5);
LabelBorder(CLAY_STRING("RoundedBorder - Button 5"), 10, 5);
LabelBorder(CLAY_STRING("RoundedBorder - Button 6"), 40, 15);
}
return Clay_EndLayout();
}
void HandleClayErrors(Clay_ErrorData errorData) {
printf("%s", errorData.errorText.chars);
}
SDL_AppResult SDL_AppInit(void **appstate, int argc, char *argv[])
{
(void) argc;
(void) argv;
if (!TTF_Init()) {
return SDL_APP_FAILURE;
}
AppState *state = SDL_calloc(1, sizeof(AppState));
if (!state) {
return SDL_APP_FAILURE;
}
*appstate = state;
if (!SDL_CreateWindowAndRenderer("Clay Demo", 640, 480, 0, &state->window, &state->renderer)) {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to create window and renderer: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
SDL_SetWindowResizable(state->window, true);
TTF_Font *font = TTF_OpenFont("resources/Roboto-Regular.ttf", 24);
if (!font) {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to load font: %s", SDL_GetError());
return SDL_APP_FAILURE;
}
gFonts[FONT_ID] = font;
/* Initialize Clay */
uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena clayMemory = (Clay_Arena) {
.memory = SDL_malloc(totalMemorySize),
.capacity = totalMemorySize
};
int width, height;
SDL_GetWindowSize(state->window, &width, &height);
Clay_Initialize(clayMemory, (Clay_Dimensions) { (float) width, (float) height }, (Clay_ErrorHandler) { HandleClayErrors });
Clay_SetMeasureTextFunction(SDL_MeasureText, 0);
*appstate = state;
return SDL_APP_CONTINUE;
}
SDL_AppResult SDL_AppEvent(void *appstate, SDL_Event *event)
{
SDL_AppResult ret_val = SDL_APP_CONTINUE;
switch (event->type) {
case SDL_EVENT_QUIT:
ret_val = SDL_APP_SUCCESS;
break;
case SDL_EVENT_WINDOW_RESIZED:
Clay_SetLayoutDimensions((Clay_Dimensions) { (float) event->window.data1, (float) event->window.data2 });
break;
case SDL_EVENT_MOUSE_MOTION:
Clay_SetPointerState((Clay_Vector2) { event->motion.x, event->motion.y },
event->motion.state & SDL_BUTTON_LEFT);
break;
case SDL_EVENT_MOUSE_WHEEL:
Clay_UpdateScrollContainers(true, (Clay_Vector2) { event->motion.xrel, event->motion.yrel }, 0.01f);
break;
default:
break;
};
return ret_val;
}
SDL_AppResult SDL_AppIterate(void *appstate)
{
AppState *state = appstate;
Clay_RenderCommandArray render_commands = Clay_CreateLayout();
SDL_SetRenderDrawColor(state->renderer, 0, 0, 0, 255);
SDL_RenderClear(state->renderer);
SDL_RenderClayCommands(state->renderer, &render_commands);
SDL_RenderPresent(state->renderer);
return SDL_APP_CONTINUE;
}
void SDL_AppQuit(void *appstate, SDL_AppResult result)
{
(void) result;
if (result != SDL_APP_SUCCESS) {
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Application failed to run");
}
AppState *state = appstate;
if (state) {
if (state->renderer)
SDL_DestroyRenderer(state->renderer);
if (state->window)
SDL_DestroyWindow(state->window);
SDL_free(state);
}
TTF_Quit();
}

Binary file not shown.

View File

@ -37,12 +37,12 @@ void Layout() {
static Clay_Color BACKGROUND = { 0xF4, 0xEB, 0xE6, 255 };
static Clay_Color ACCENT = { 0xFA, 0xE0, 0xD4, 255 };
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() },
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) },
.layoutDirection = CLAY_TOP_TO_BOTTOM }),
CLAY_RECTANGLE({ .color = BACKGROUND })) {
CLAY(CLAY_ID("PageMargins"),
CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() },
.padding = { 70., 50. }, // Some nice looking page margins
CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) },
.padding = { 70, 70, 50, 50 }, // Some nice looking page margins
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.childGap = 10})) {
@ -57,12 +57,12 @@ void Layout() {
));
// Feature Box
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT() }, .childGap = 10 })) {
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT() }}), CLAY_RECTANGLE({
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(0) }, .childGap = 10 })) {
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(0) }}), CLAY_RECTANGLE({
.color = ACCENT,
.cornerRadius = CLAY_CORNER_RADIUS(12),
})) {
CLAY(CLAY_LAYOUT({.padding = { 20., 20. }, .childGap = 4, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
CLAY(CLAY_LAYOUT({.padding = CLAY_PADDING_ALL(20), .childGap = 4, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
CLAY_TEXT(CLAY_STRING("- High performance"),
CLAY_TEXT_CONFIG({ .textColor = PRIMARY, .fontSize = 14, .fontFamily = CLAY_STRING("Quicksand SemiBold") }));
CLAY_TEXT(CLAY_STRING("- Declarative syntax"),
@ -76,16 +76,16 @@ void Layout() {
}
}
CLAY(CLAY_LAYOUT({
.sizing = {CLAY_SIZING_FIT(), CLAY_SIZING_GROW()},
.padding = { 10, 10 },
.sizing = {CLAY_SIZING_FIT(0), CLAY_SIZING_GROW(0)},
.padding = CLAY_PADDING_ALL(10),
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.childAlignment = { CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER },
.childGap = 4
}), CLAY_RECTANGLE({ .color = ACCENT, .cornerRadius = CLAY_CORNER_RADIUS(8) })) {
// Profile picture
CLAY(CLAY_LAYOUT({
.sizing = {CLAY_SIZING_FIT(), CLAY_SIZING_GROW()},
.padding = { 30, 0 },
.sizing = {CLAY_SIZING_FIT(0), CLAY_SIZING_GROW(0)},
.padding = { 30, 30, 0, 0 },
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.childAlignment = { CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER }}), CLAY_BORDER_OUTSIDE_RADIUS(2, PRIMARY, 10)) {
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_FIXED(32), CLAY_SIZING_FIXED(32) } }), CLAY_IMAGE({ .sourceDimensions = { 32, 32 }, .path = CLAY_STRING("resources/check.png") }));
@ -93,11 +93,11 @@ void Layout() {
}
}
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(16) } }));
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(16) } }));
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childGap = 10, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childGap = 10, .layoutDirection = CLAY_TOP_TO_BOTTOM })) {
CLAY_TEXT(CLAY_STRING("Cairo"), CLAY_TEXT_CONFIG({ .fontFamily = CLAY_STRING("Calistoga"), .fontSize = 24, .textColor = PRIMARY }));
CLAY(CLAY_LAYOUT({ .padding = { 10, 10 } }), CLAY_RECTANGLE({ .color = ACCENT, .cornerRadius = CLAY_CORNER_RADIUS(10) })) {
CLAY(CLAY_LAYOUT({ .padding = CLAY_PADDING_ALL(10) }), CLAY_RECTANGLE({ .color = ACCENT, .cornerRadius = CLAY_CORNER_RADIUS(10) })) {
CLAY_TEXT(CLAY_STRING("Officiis quia quia qui inventore ratione voluptas et. Quidem sunt unde similique. Qui est et exercitationem cumque harum illum. Numquam placeat aliquid quo voluptatem. "
"Deleniti saepe nihil exercitationem nemo illo. Consequatur beatae repellat provident similique. Provident qui exercitationem deserunt sapiente. Quam qui dolor corporis odit. "
"Assumenda corrupti sunt culpa pariatur. Vero sit ut minima. In est consequatur minus et cum sint illum aperiam. Qui ipsa quas nisi omnis aut quia nobis. "

View File

@ -96,6 +96,11 @@
{name: 'length', type: 'uint32_t' },
{name: 'chars', type: 'uint32_t' },
]};
let stringSliceDefinition = { type: 'struct', members: [
{name: 'length', type: 'uint32_t' },
{name: 'chars', type: 'uint32_t' },
{name: 'baseChars', type: 'uint32_t' },
]};
let borderDefinition = { type: 'struct', members: [
{name: 'width', type: 'uint32_t'},
{name: 'color', ...colorDefinition},
@ -155,7 +160,8 @@
{ name: 'height', type: 'float' },
]},
{ name: 'config', type: 'uint32_t'},
{ name: 'text', ...stringDefinition },
{ name: 'text', ...stringSliceDefinition },
{ name: 'zIndex', type: 'int32_t' },
{ name: 'id', type: 'uint32_t' },
{ name: 'commandType', type: 'uint32_t', },
]
@ -314,7 +320,7 @@
const importObject = {
clay: {
measureTextFunction: (addressOfDimensions, textToMeasure, addressOfConfig) => {
measureTextFunction: (addressOfDimensions, textToMeasure, addressOfConfig, userData) => {
let stringLength = memoryDataView.getUint32(textToMeasure, true);
let pointerToString = memoryDataView.getUint32(textToMeasure + 4, true);
let textConfig = readStructAtAddress(addressOfConfig, textConfigDefinition);

View File

@ -96,6 +96,11 @@
{name: 'length', type: 'uint32_t' },
{name: 'chars', type: 'uint32_t' },
]};
let stringSliceDefinition = { type: 'struct', members: [
{name: 'length', type: 'uint32_t' },
{name: 'chars', type: 'uint32_t' },
{name: 'baseChars', type: 'uint32_t' },
]};
let borderDefinition = { type: 'struct', members: [
{name: 'width', type: 'uint32_t'},
{name: 'color', ...colorDefinition},
@ -155,7 +160,8 @@
{ name: 'height', type: 'float' },
]},
{ name: 'config', type: 'uint32_t'},
{ name: 'text', ...stringDefinition },
{ name: 'text', ...stringSliceDefinition },
{ name: 'zIndex', type: 'int32_t' },
{ name: 'id', type: 'uint32_t' },
{ name: 'commandType', type: 'uint32_t', },
]
@ -314,7 +320,7 @@
const importObject = {
clay: {
measureTextFunction: (addressOfDimensions, textToMeasure, addressOfConfig) => {
measureTextFunction: (addressOfDimensions, textToMeasure, addressOfConfig, userData) => {
let stringLength = memoryDataView.getUint32(textToMeasure, true);
let pointerToString = memoryDataView.getUint32(textToMeasure + 4, true);
let textConfig = readStructAtAddress(addressOfConfig, textConfigDefinition);

View File

@ -41,18 +41,18 @@ Clay_TextElementConfig headerTextConfig = (Clay_TextElementConfig) { .fontId = 2
Clay_TextElementConfig blobTextConfig = (Clay_TextElementConfig) { .fontId = 2, .fontSize = 30, .textColor = {244, 235, 230, 255} };
void LandingPageBlob(int index, int fontSize, Clay_Color color, Clay_String text, Clay_String imageURL) {
CLAY(CLAY_IDI("HeroBlob", index), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 480 }) }, .padding = {16, 16}, .childGap = 16, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }), CLAY_BORDER_OUTSIDE_RADIUS(2, color, 10)) {
CLAY(CLAY_IDI("HeroBlob", index), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 480) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }), CLAY_BORDER_OUTSIDE_RADIUS(2, color, 10)) {
CLAY(CLAY_IDI("CheckImage", index), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_FIXED(32) } }), CLAY_IMAGE({ .sourceDimensions = { 128, 128 }, .sourceURL = imageURL })) {}
CLAY_TEXT(text, CLAY_TEXT_CONFIG({ .fontSize = fontSize, .fontId = FONT_ID_BODY_24, .textColor = color }));
}
}
void LandingPageDesktop() {
CLAY(CLAY_ID("LandingPage1Desktop"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT({ .min = windowHeight - 70 }) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = { .x = 50 } })) {
CLAY(CLAY_ID("LandingPage1"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = { 32, 32 }, .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) {
CLAY(CLAY_ID("LandingPage1Desktop"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(.min = windowHeight - 70) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = { 50, 50 } })) {
CLAY(CLAY_ID("LandingPage1"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = CLAY_PADDING_ALL(32), .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) {
CLAY(CLAY_ID("LeftText"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_PERCENT(0.55f) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance."), CLAY_TEXT_CONFIG({ .fontSize = 56, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED }));
CLAY(CLAY_ID("LandingPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(32) } })) {}
CLAY(CLAY_ID("LandingPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(32) } })) {}
CLAY_TEXT(CLAY_STRING("Clay is laying out this webpage right now!"), CLAY_TEXT_CONFIG({ .fontSize = 36, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE }));
}
CLAY(CLAY_ID("HeroImageOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_PERCENT(0.45f) }, .childAlignment = { CLAY_ALIGN_X_CENTER }, .childGap = 16 })) {
@ -67,13 +67,13 @@ void LandingPageDesktop() {
}
void LandingPageMobile() {
CLAY(CLAY_ID("LandingPage1Mobile"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIT({ .min = windowHeight - 70 }) }, .childAlignment = {CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER}, .padding = { 16, 32 }, .childGap = 32 })) {
CLAY(CLAY_ID("LeftText"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY(CLAY_ID("LandingPage1Mobile"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIT(.min = windowHeight - 70) }, .childAlignment = {CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER}, .padding = { 16, 16, 32, 32 }, .childGap = 32 })) {
CLAY(CLAY_ID("LeftText"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("Clay is a flex-box style UI auto layout library in C, with declarative syntax and microsecond performance."), CLAY_TEXT_CONFIG({ .fontSize = 48, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED }));
CLAY(CLAY_ID("LandingPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(32) } })) {}
CLAY(CLAY_ID("LandingPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(32) } })) {}
CLAY_TEXT(CLAY_STRING("Clay is laying out this webpage right now!"), CLAY_TEXT_CONFIG({ .fontSize = 32, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE }));
}
CLAY(CLAY_ID("HeroImageOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW() }, .childAlignment = { CLAY_ALIGN_X_CENTER }, .childGap = 16 })) {
CLAY(CLAY_ID("HeroImageOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(0) }, .childAlignment = { CLAY_ALIGN_X_CENTER }, .childGap = 16 })) {
LandingPageBlob(1, 28, COLOR_BLOB_BORDER_5, CLAY_STRING("High performance"), CLAY_STRING("/clay/images/check_5.png"));
LandingPageBlob(2, 28, COLOR_BLOB_BORDER_4, CLAY_STRING("Flexbox-style responsive layout"), CLAY_STRING("/clay/images/check_4.png"));
LandingPageBlob(3, 28, COLOR_BLOB_BORDER_3, CLAY_STRING("Declarative syntax"), CLAY_STRING("/clay/images/check_3.png"));
@ -84,17 +84,17 @@ void LandingPageMobile() {
}
void FeatureBlocksDesktop() {
CLAY(CLAY_ID("FeatureBlocksOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() } })) {
CLAY(CLAY_ID("FeatureBlocksInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } }), CLAY_BORDER({ .betweenChildren = { .width = 2, .color = COLOR_RED } })) {
CLAY(CLAY_ID("FeatureBlocksOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) } })) {
CLAY(CLAY_ID("FeatureBlocksInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } }), CLAY_BORDER({ .betweenChildren = { .width = 2, .color = COLOR_RED } })) {
Clay_TextElementConfig *textConfig = CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_BODY_24, .textColor = COLOR_RED });
CLAY(CLAY_ID("HFileBoxOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_PERCENT(0.5f) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {50, 32}, .childGap = 8 })) {
CLAY(CLAY_ID("HFileBoxOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_PERCENT(0.5f) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {50, 50, 32, 32}, .childGap = 8 })) {
CLAY(CLAY_ID("HFileIncludeOuter"), CLAY_LAYOUT({ .padding = {8, 4} }), CLAY_RECTANGLE({ .color = COLOR_RED, .cornerRadius = CLAY_CORNER_RADIUS(8) })) {
CLAY_TEXT(CLAY_STRING("#include clay.h"), CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_BODY_24, .textColor = COLOR_LIGHT }));
}
CLAY_TEXT(CLAY_STRING("~2000 lines of C99."), textConfig);
CLAY_TEXT(CLAY_STRING("Zero dependencies, including no C standard library."), textConfig);
}
CLAY(CLAY_ID("BringYourOwnRendererOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_PERCENT(0.5f) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 50, .y = 32}, .childGap = 8 })) {
CLAY(CLAY_ID("BringYourOwnRendererOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_PERCENT(0.5f) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {50, 50, 32, 32}, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("Renderer agnostic."), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = COLOR_ORANGE }));
CLAY_TEXT(CLAY_STRING("Layout with clay, then render with Raylib, WebGL Canvas or even as HTML."), textConfig);
CLAY_TEXT(CLAY_STRING("Flexible output for easy compositing in your custom engine or environment."), textConfig);
@ -104,16 +104,16 @@ void FeatureBlocksDesktop() {
}
void FeatureBlocksMobile() {
CLAY(CLAY_ID("FeatureBlocksInner"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW() } }), CLAY_BORDER({ .betweenChildren = { .width = 2, .color = COLOR_RED } })) {
CLAY(CLAY_ID("FeatureBlocksInner"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0) } }), CLAY_BORDER({ .betweenChildren = { .width = 2, .color = COLOR_RED } })) {
Clay_TextElementConfig *textConfig = CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_BODY_24, .textColor = COLOR_RED });
CLAY(CLAY_ID("HFileBoxOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW() }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {16, 32}, .childGap = 8 })) {
CLAY(CLAY_ID("HFileBoxOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {16, 16, 32, 32}, .childGap = 8 })) {
CLAY(CLAY_ID("HFileIncludeOuter"), CLAY_LAYOUT({ .padding = {8, 4} }), CLAY_RECTANGLE({ .color = COLOR_RED, .cornerRadius = CLAY_CORNER_RADIUS(8) })) {
CLAY_TEXT(CLAY_STRING("#include clay.h"), CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_BODY_24, .textColor = COLOR_LIGHT }));
}
CLAY_TEXT(CLAY_STRING("~2000 lines of C99."), textConfig);
CLAY_TEXT(CLAY_STRING("Zero dependencies, including no C standard library."), textConfig);
}
CLAY(CLAY_ID("BringYourOwnRendererOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW() }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, .y = 32}, .childGap = 8 })) {
CLAY(CLAY_ID("BringYourOwnRendererOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {16, 16, 32, 32}, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("Renderer agnostic."), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = COLOR_ORANGE }));
CLAY_TEXT(CLAY_STRING("Layout with clay, then render with Raylib, WebGL Canvas or even as HTML."), textConfig);
CLAY_TEXT(CLAY_STRING("Flexible output for easy compositing in your custom engine or environment."), textConfig);
@ -122,33 +122,33 @@ void FeatureBlocksMobile() {
}
void DeclarativeSyntaxPageDesktop() {
CLAY(CLAY_ID("SyntaxPageDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 50} })) {
CLAY(CLAY_ID("SyntaxPage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .padding = { 32, 32 }, .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) {
CLAY(CLAY_ID("SyntaxPageDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = { 50, 50 } })) {
CLAY(CLAY_ID("SyntaxPage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .padding = CLAY_PADDING_ALL(32), .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) {
CLAY(CLAY_ID("SyntaxPageLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("Declarative Syntax"), CLAY_TEXT_CONFIG({ .fontSize = 52, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED }));
CLAY(CLAY_ID("SyntaxSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) } })) {}
CLAY(CLAY_ID("SyntaxSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) } })) {}
CLAY_TEXT(CLAY_STRING("Flexible and readable declarative syntax with nested UI element hierarchies."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
CLAY_TEXT(CLAY_STRING("Mix elements with standard C code like loops, conditionals and functions."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
CLAY_TEXT(CLAY_STRING("Create your own library of re-usable components from UI primitives like text, images and rectangles."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
}
CLAY(CLAY_ID("SyntaxPageRightImage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} })) {
CLAY(CLAY_ID("SyntaxPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 568 }) } }), CLAY_IMAGE({ .sourceDimensions = {1136, 1194}, .sourceURL = CLAY_STRING("/clay/images/declarative.png") })) {}
CLAY(CLAY_ID("SyntaxPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 568) } }), CLAY_IMAGE({ .sourceDimensions = {1136, 1194}, .sourceURL = CLAY_STRING("/clay/images/declarative.png") })) {}
}
}
}
}
void DeclarativeSyntaxPageMobile() {
CLAY(CLAY_ID("SyntaxPageDesktop"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER}, .padding = {16, 32}, .childGap = 16 })) {
CLAY(CLAY_ID("SyntaxPageLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY(CLAY_ID("SyntaxPageDesktop"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER}, .padding = {16, 16, 32, 32}, .childGap = 16 })) {
CLAY(CLAY_ID("SyntaxPageLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("Declarative Syntax"), CLAY_TEXT_CONFIG({ .fontSize = 48, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED }));
CLAY(CLAY_ID("SyntaxSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) } })) {}
CLAY(CLAY_ID("SyntaxSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) } })) {}
CLAY_TEXT(CLAY_STRING("Flexible and readable declarative syntax with nested UI element hierarchies."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
CLAY_TEXT(CLAY_STRING("Mix elements with standard C code like loops, conditionals and functions."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
CLAY_TEXT(CLAY_STRING("Create your own library of re-usable components from UI primitives like text, images and rectangles."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
}
CLAY(CLAY_ID("SyntaxPageRightImage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} })) {
CLAY(CLAY_ID("SyntaxPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 568 }) } }), CLAY_IMAGE({ .sourceDimensions = {1136, 1194}, .sourceURL = CLAY_STRING("/clay/images/declarative.png") } )) {}
CLAY(CLAY_ID("SyntaxPageRightImage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} })) {
CLAY(CLAY_ID("SyntaxPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 568) } }), CLAY_IMAGE({ .sourceDimensions = {1136, 1194}, .sourceURL = CLAY_STRING("/clay/images/declarative.png") } )) {}
}
}
}
@ -165,20 +165,20 @@ Clay_Color ColorLerp(Clay_Color a, Clay_Color b, float amount) {
Clay_String LOREM_IPSUM_TEXT = CLAY_STRING("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
void HighPerformancePageDesktop(float lerpValue) {
CLAY(CLAY_ID("PerformancePageOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 82, 32}, .childGap = 64 }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY(CLAY_ID("PerformanceOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {82, 82, 32, 32}, .childGap = 64 }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY(CLAY_ID("PerformanceLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("High Performance"), CLAY_TEXT_CONFIG({ .fontSize = 52, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT }));
CLAY(CLAY_ID("PerformanceSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {}
CLAY(CLAY_ID("PerformanceSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) }})) {}
CLAY_TEXT(CLAY_STRING("Fast enough to recompute your entire UI every frame."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
CLAY_TEXT(CLAY_STRING("Small memory footprint (3.5mb default) with static allocation & reuse. No malloc / free."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
CLAY_TEXT(CLAY_STRING("Simplify animations and reactive UI design by avoiding the standard performance hacks."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
}
CLAY(CLAY_ID("PerformanceRightImageOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {CLAY_ALIGN_X_CENTER} })) {
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(400) } }), CLAY_BORDER_ALL({ .width = 2, .color = COLOR_LIGHT })) {
CLAY(CLAY_ID("AnimationDemoContainerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.3f + 0.4f * lerpValue), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {32, 32} }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_RED, COLOR_ORANGE, lerpValue) })) {
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(400) } }), CLAY_BORDER_ALL({ .width = 2, .color = COLOR_LIGHT })) {
CLAY(CLAY_ID("AnimationDemoContainerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.3f + 0.4f * lerpValue), CLAY_SIZING_GROW(0) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = CLAY_PADDING_ALL(32) }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_RED, COLOR_ORANGE, lerpValue) })) {
CLAY_TEXT(LOREM_IPSUM_TEXT, CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT }));
}
CLAY(CLAY_ID("AnimationDemoContainerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {32, 32} }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue) })) {
CLAY(CLAY_ID("AnimationDemoContainerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = CLAY_PADDING_ALL(32) }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue) })) {
CLAY_TEXT(LOREM_IPSUM_TEXT, CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT }));
}
}
@ -187,20 +187,20 @@ void HighPerformancePageDesktop(float lerpValue) {
}
void HighPerformancePageMobile(float lerpValue) {
CLAY(CLAY_ID("PerformancePageOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, 32}, .childGap = 32 }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY(CLAY_ID("PerformanceLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY(CLAY_ID("PerformanceOuter"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER}, .padding = {16, 16, 32, 32}, .childGap = 32 }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY(CLAY_ID("PerformanceLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("High Performance"), CLAY_TEXT_CONFIG({ .fontSize = 48, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT }));
CLAY(CLAY_ID("PerformanceSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {}
CLAY(CLAY_ID("PerformanceSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) }})) {}
CLAY_TEXT(CLAY_STRING("Fast enough to recompute your entire UI every frame."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
CLAY_TEXT(CLAY_STRING("Small memory footprint (3.5mb default) with static allocation & reuse. No malloc / free."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
CLAY_TEXT(CLAY_STRING("Simplify animations and reactive UI design by avoiding the standard performance hacks."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
}
CLAY(CLAY_ID("PerformanceRightImageOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .childAlignment = {CLAY_ALIGN_X_CENTER} })) {
CLAY(CLAY_ID(""), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(400) } }), CLAY_BORDER_ALL({ .width = 2, .color = COLOR_LIGHT })) {
CLAY(CLAY_ID("AnimationDemoContainerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.35f + 0.3f * lerpValue), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {16, 16} }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_RED, COLOR_ORANGE, lerpValue) })) {
CLAY(CLAY_ID("PerformanceRightImageOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {CLAY_ALIGN_X_CENTER} })) {
CLAY(CLAY_ID(""), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(400) } }), CLAY_BORDER_ALL({ .width = 2, .color = COLOR_LIGHT })) {
CLAY(CLAY_ID("AnimationDemoContainerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.35f + 0.3f * lerpValue), CLAY_SIZING_GROW(0) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = CLAY_PADDING_ALL(16) }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_RED, COLOR_ORANGE, lerpValue) })) {
CLAY_TEXT(LOREM_IPSUM_TEXT, CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT }));
}
CLAY(CLAY_ID("AnimationDemoContainerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = {16, 16} }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue) })) {
CLAY(CLAY_ID("AnimationDemoContainerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER}, .padding = CLAY_PADDING_ALL(16) }), CLAY_RECTANGLE({ .color = ColorLerp(COLOR_ORANGE, COLOR_RED, lerpValue) })) {
CLAY_TEXT(LOREM_IPSUM_TEXT, CLAY_TEXT_CONFIG({ .fontSize = 24, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT }));
}
}
@ -217,7 +217,7 @@ void HandleRendererButtonInteraction(Clay_ElementId elementId, Clay_PointerData
}
void RendererButtonActive(Clay_String text) {
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED(300) }, .padding = {16, 16} }),
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED(300) }, .padding = CLAY_PADDING_ALL(16) }),
CLAY_RECTANGLE({ .color = Clay_Hovered() ? COLOR_RED_HOVER : COLOR_RED, .cornerRadius = CLAY_CORNER_RADIUS(10) })
) {
CLAY_TEXT(text, CLAY_TEXT_CONFIG({ .disablePointerEvents = true, .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
@ -225,7 +225,7 @@ void RendererButtonActive(Clay_String text) {
}
void RendererButtonInactive(Clay_String text, size_t rendererIndex) {
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED(300)}, .padding = {16, 16} }),
CLAY(CLAY_LAYOUT({ .sizing = {CLAY_SIZING_FIXED(300)}, .padding = CLAY_PADDING_ALL(16) }),
CLAY_BORDER_OUTSIDE_RADIUS(2, COLOR_RED, 10),
CLAY_RECTANGLE({ .color = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT, .cornerRadius = CLAY_CORNER_RADIUS(10), .cursorPointer = true }),
Clay_OnHover(HandleRendererButtonInteraction, rendererIndex)
@ -235,18 +235,18 @@ void RendererButtonInactive(Clay_String text, size_t rendererIndex) {
}
void RendererPageDesktop() {
CLAY(CLAY_ID("RendererPageDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 50} })) {
CLAY(CLAY_ID("RendererPage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .padding = { 32, 32 }, .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) {
CLAY(CLAY_ID("RendererPageDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = { 50, 50 } })) {
CLAY(CLAY_ID("RendererPage"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .padding = CLAY_PADDING_ALL(32), .childGap = 32 }), CLAY_BORDER({ .left = { 2, COLOR_RED }, .right = { 2, COLOR_RED } })) {
CLAY(CLAY_ID("RendererLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("Renderer & Platform Agnostic"), CLAY_TEXT_CONFIG({ .fontSize = 52, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED }));
CLAY(CLAY_ID("RendererSpacerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {}
CLAY(CLAY_ID("RendererSpacerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) }})) {}
CLAY_TEXT(CLAY_STRING("Clay outputs a sorted array of primitive render commands, such as RECTANGLE, TEXT or IMAGE."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
CLAY_TEXT(CLAY_STRING("Write your own renderer in a few hundred lines of code, or use the provided examples for Raylib, WebGL canvas and more."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
CLAY_TEXT(CLAY_STRING("There's even an HTML renderer - you're looking at it right now!"), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
}
CLAY(CLAY_ID("RendererRightText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .childAlignment = {CLAY_ALIGN_X_CENTER}, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 16 })) {
CLAY_TEXT(CLAY_STRING("Try changing renderer!"), CLAY_TEXT_CONFIG({ .fontSize = 36, .fontId = FONT_ID_BODY_36, .textColor = COLOR_ORANGE }));
CLAY(CLAY_ID("RendererSpacerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 32 }) } })) {}
CLAY(CLAY_ID("RendererSpacerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 32) } })) {}
if (ACTIVE_RENDERER_INDEX == 0) {
RendererButtonActive(CLAY_STRING("HTML Renderer"));
RendererButtonInactive(CLAY_STRING("Canvas Renderer"), 1);
@ -260,17 +260,17 @@ void RendererPageDesktop() {
}
void RendererPageMobile() {
CLAY(CLAY_ID("RendererMobile"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER}, .padding = {.x = 16, 32}, .childGap = 32 }), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) {
CLAY(CLAY_ID("RendererLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY(CLAY_ID("RendererMobile"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_CENTER}, .padding = { 16, 16, 32, 32}, .childGap = 32 }), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) {
CLAY(CLAY_ID("RendererLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("Renderer & Platform Agnostic"), CLAY_TEXT_CONFIG({ .fontSize = 48, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_RED }));
CLAY(CLAY_ID("RendererSpacerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {}
CLAY(CLAY_ID("RendererSpacerLeft"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) }})) {}
CLAY_TEXT(CLAY_STRING("Clay outputs a sorted array of primitive render commands, such as RECTANGLE, TEXT or IMAGE."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
CLAY_TEXT(CLAY_STRING("Write your own renderer in a few hundred lines of code, or use the provided examples for Raylib, WebGL canvas and more."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
CLAY_TEXT(CLAY_STRING("There's even an HTML renderer - you're looking at it right now!"), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_RED }));
}
CLAY(CLAY_ID("RendererRightText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 16 })) {
CLAY(CLAY_ID("RendererRightText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 16 })) {
CLAY_TEXT(CLAY_STRING("Try changing renderer!"), CLAY_TEXT_CONFIG({ .fontSize = 36, .fontId = FONT_ID_BODY_36, .textColor = COLOR_ORANGE }));
CLAY(CLAY_ID("RendererSpacerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 32}) }})) {}
CLAY(CLAY_ID("RendererSpacerRight"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 32) }})) {}
if (ACTIVE_RENDERER_INDEX == 0) {
RendererButtonActive(CLAY_STRING("HTML Renderer"));
RendererButtonInactive(CLAY_STRING("Canvas Renderer"), 1);
@ -283,17 +283,17 @@ void RendererPageMobile() {
}
void DebuggerPageDesktop() {
CLAY(CLAY_ID("DebuggerDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIT({ .min = windowHeight - 50 }) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = {.x = 82, 32}, .childGap = 64 }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY(CLAY_ID("DebuggerDesktop"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIT(.min = windowHeight - 50) }, .childAlignment = {0, CLAY_ALIGN_Y_CENTER}, .padding = { 82, 82, 32, 32 }, .childGap = 64 }), CLAY_RECTANGLE({ .color = COLOR_RED })) {
CLAY(CLAY_ID("DebuggerLeftText"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.5) }, .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 8 })) {
CLAY_TEXT(CLAY_STRING("Integrated Debug Tools"), CLAY_TEXT_CONFIG({ .fontSize = 52, .fontId = FONT_ID_TITLE_56, .textColor = COLOR_LIGHT }));
CLAY(CLAY_ID("DebuggerSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 16 }) }})) {}
CLAY(CLAY_ID("DebuggerSpacer"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 16) }})) {}
CLAY_TEXT(CLAY_STRING("Clay includes built in \"Chrome Inspector\"-style debug tooling."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
CLAY_TEXT(CLAY_STRING("View your layout hierarchy and config in real time."), CLAY_TEXT_CONFIG({ .fontSize = 28, .fontId = FONT_ID_BODY_36, .textColor = COLOR_LIGHT }));
CLAY(CLAY_ID("DebuggerPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(), .height = CLAY_SIZING_FIXED(32) } })) {}
CLAY(CLAY_ID("DebuggerPageSpacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(32) } })) {}
CLAY_TEXT(CLAY_STRING("Press the \"d\" key to try it out now!"), CLAY_TEXT_CONFIG({ .fontSize = 32, .fontId = FONT_ID_TITLE_36, .textColor = COLOR_ORANGE }));
}
CLAY(CLAY_ID("DebuggerRightImageOuter"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {CLAY_ALIGN_X_CENTER} })) {
CLAY(CLAY_ID("DebuggerPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW({ .max = 558 }) } }), CLAY_IMAGE({ .sourceDimensions = {1620, 1474}, .sourceURL = CLAY_STRING("/clay/images/debugger.png") })) {}
CLAY(CLAY_ID("DebuggerPageRightImageInner"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(.max = 558) } }), CLAY_IMAGE({ .sourceDimensions = {1620, 1474}, .sourceURL = CLAY_STRING("/clay/images/debugger.png") })) {}
}
}
}
@ -310,19 +310,19 @@ float animationLerpValue = -1.0f;
Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
Clay_BeginLayout();
CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() } }), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) {
CLAY(CLAY_ID("Header"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(50) }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .childGap = 16, .padding = { 32 } })) {
CLAY(CLAY_ID("OuterContainer"), CLAY_LAYOUT({ .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) } }), CLAY_RECTANGLE({ .color = COLOR_LIGHT })) {
CLAY(CLAY_ID("Header"), CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(50) }, .childAlignment = { 0, CLAY_ALIGN_Y_CENTER }, .childGap = 16, .padding = { 32, 32 } })) {
CLAY_TEXT(CLAY_STRING("Clay"), &headerTextConfig);
CLAY(CLAY_ID("Spacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW() } })) {}
CLAY(CLAY_ID("Spacer"), CLAY_LAYOUT({ .sizing = { .width = CLAY_SIZING_GROW(0) } })) {}
if (!mobileScreen) {
CLAY(CLAY_ID("LinkExamplesOuter"), CLAY_LAYOUT({ .padding = {8} }), CLAY_RECTANGLE({ .link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples"), .color = {0,0,0,0} })) {
CLAY(CLAY_ID("LinkExamplesOuter"), CLAY_LAYOUT({ .padding = {8, 8} }), CLAY_RECTANGLE({ .link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples"), .color = {0,0,0,0} })) {
CLAY_TEXT(CLAY_STRING("Examples"), CLAY_TEXT_CONFIG({ .disablePointerEvents = true, .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
}
CLAY(CLAY_ID("LinkDocsOuter"), CLAY_LAYOUT({ .padding = {8} }), CLAY_RECTANGLE({ .link = CLAY_STRING("https://github.com/nicbarker/clay/blob/main/README.md"), .color = {0,0,0,0} })) {
CLAY(CLAY_ID("LinkDocsOuter"), CLAY_LAYOUT({ .padding = {8, 8} }), CLAY_RECTANGLE({ .link = CLAY_STRING("https://github.com/nicbarker/clay/blob/main/README.md"), .color = {0,0,0,0} })) {
CLAY_TEXT(CLAY_STRING("Docs"), CLAY_TEXT_CONFIG({ .disablePointerEvents = true, .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
}
}
CLAY(CLAY_LAYOUT({ .padding = {16, 6} }),
CLAY(CLAY_LAYOUT({ .padding = {16, 16, 6, 6} }),
CLAY_RECTANGLE({
.cornerRadius = CLAY_CORNER_RADIUS(10),
.link = CLAY_STRING("https://discord.gg/b4FTWkxdvT"),
@ -331,21 +331,21 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
) {
CLAY_TEXT(CLAY_STRING("Discord"), CLAY_TEXT_CONFIG({ .disablePointerEvents = true, .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
}
CLAY(CLAY_LAYOUT({ .padding = {16, 6} }),
CLAY(CLAY_LAYOUT({ .padding = {16, 16, 6, 6} }),
CLAY_RECTANGLE({ .cornerRadius = CLAY_CORNER_RADIUS(10), .link = CLAY_STRING("https://github.com/nicbarker/clay"), .color = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT }),
CLAY_BORDER_OUTSIDE_RADIUS(2, COLOR_RED, 10)
) {
CLAY_TEXT(CLAY_STRING("Github"), CLAY_TEXT_CONFIG({ .disablePointerEvents = true, .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
}
}
Clay_LayoutConfig topBorderConfig = (Clay_LayoutConfig) { .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_FIXED(4) }};
Clay_LayoutConfig topBorderConfig = (Clay_LayoutConfig) { .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(4) }};
CLAY(CLAY_ID("TopBorder1"), CLAY_LAYOUT(topBorderConfig), CLAY_RECTANGLE({ .color = COLOR_TOP_BORDER_5 })) {}
CLAY(CLAY_ID("TopBorder2"), CLAY_LAYOUT(topBorderConfig), CLAY_RECTANGLE({ .color = COLOR_TOP_BORDER_4 })) {}
CLAY(CLAY_ID("TopBorder3"), CLAY_LAYOUT(topBorderConfig), CLAY_RECTANGLE({ .color = COLOR_TOP_BORDER_3 })) {}
CLAY(CLAY_ID("TopBorder4"), CLAY_LAYOUT(topBorderConfig), CLAY_RECTANGLE({ .color = COLOR_TOP_BORDER_2 })) {}
CLAY(CLAY_ID("TopBorder5"), CLAY_LAYOUT(topBorderConfig), CLAY_RECTANGLE({ .color = COLOR_TOP_BORDER_1 })) {}
CLAY(CLAY_ID("OuterScrollContainer"),
CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(), CLAY_SIZING_GROW() }, .layoutDirection = CLAY_TOP_TO_BOTTOM }),
CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM }),
CLAY_SCROLL({ .vertical = true }),
CLAY_BORDER({ .betweenChildren = {2, COLOR_RED} })
) {
@ -391,10 +391,10 @@ CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(floa
windowHeight = height;
Clay_SetLayoutDimensions((Clay_Dimensions) { width, height });
Clay_ScrollContainerData scrollContainerData = Clay_GetScrollContainerData(Clay_GetElementId(CLAY_STRING("OuterScrollContainer")));
Clay_LayoutElementHashMapItem *perfPage = Clay__GetHashMapItem(Clay_GetElementId(CLAY_STRING("PerformancePageOuter")).id);
Clay_LayoutElementHashMapItem *perfPage = Clay__GetHashMapItem(Clay_GetElementId(CLAY_STRING("PerformanceOuter")).id);
// NaN propagation can cause pain here
float perfPageYOffset = perfPage->boundingBox.y + scrollContainerData.scrollPosition->y;
if (deltaTime == deltaTime && perfPageYOffset < height && perfPageYOffset + perfPage->boundingBox.height > 0) {
if (deltaTime == deltaTime && (ACTIVE_RENDERER_INDEX == 1 || (perfPageYOffset < height && perfPageYOffset + perfPage->boundingBox.height > 0))) {
animationLerpValue += deltaTime;
if (animationLerpValue > 1) {
animationLerpValue -= 2;
@ -457,4 +457,4 @@ CLAY_WASM_EXPORT("UpdateDrawFrame") Clay_RenderCommandArray UpdateDrawFrame(floa
// Dummy main() to please cmake - TODO get wasm working with cmake on this example
int main() {
return 0;
}
}

View File

@ -2,11 +2,15 @@ cmake_minimum_required(VERSION 3.27)
project(clay_examples_cpp_project_example CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g")
if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer -g")
endif()
add_executable(clay_examples_cpp_project_example main.cpp)
target_include_directories(clay_examples_cpp_project_example PUBLIC .)
set(CMAKE_CXX_FLAGS_DEBUG "-Werror -Wall")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
if(NOT MSVC)
set(CMAKE_CXX_FLAGS_DEBUG "-Werror -Wall")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
endif()

View File

@ -13,7 +13,9 @@ int main(void) {
Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, (char *)malloc(totalMemorySize));
Clay_Initialize(clayMemory, Clay_Dimensions {1024,768}, Clay_ErrorHandler { HandleClayErrors });
Clay_BeginLayout();
CLAY(CLAY_RECTANGLE({ .color = {255,255,255,0} }), CLAY_LAYOUT(layoutElement)) {}
CLAY(CLAY_RECTANGLE({ .color = {255,255,255,0} }), CLAY_LAYOUT(layoutElement)) {
CLAY_TEXT(CLAY_STRING(""), CLAY_TEXT_CONFIG({ .fontId = 0 }));
}
Clay_EndLayout();
return 0;
}

View File

@ -25,8 +25,12 @@ target_include_directories(clay_examples_introducing_clay_video_demo PUBLIC .)
target_link_libraries(clay_examples_introducing_clay_video_demo PUBLIC raylib)
set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O3")
if(MSVC)
set(CMAKE_C_FLAGS_DEBUG "/D CLAY_DEBUG")
else()
set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O3")
endif()
add_custom_command(
TARGET clay_examples_introducing_clay_video_demo POST_BUILD

View File

@ -7,7 +7,7 @@ Clay_Color COLOR_WHITE = { 255, 255, 255, 255};
void RenderHeaderButton(Clay_String text) {
CLAY(
CLAY_LAYOUT({ .padding = { 16, 8 }}),
CLAY_LAYOUT({ .padding = { 16, 16, 8, 8 }}),
CLAY_RECTANGLE({
.color = { 140, 140, 140, 255 },
.cornerRadius = 5
@ -22,7 +22,7 @@ void RenderHeaderButton(Clay_String text) {
}
void RenderDropdownMenuItem(Clay_String text) {
CLAY(CLAY_LAYOUT({ .padding = { 16, 16 }})) {
CLAY(CLAY_LAYOUT({ .padding = CLAY_PADDING_ALL(16)})) {
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
.fontId = FONT_ID_BODY_16,
.fontSize = 16,
@ -84,7 +84,7 @@ int main(void) {
.width = GetScreenWidth(),
.height = GetScreenHeight()
}, (Clay_ErrorHandler) { HandleClayErrors }); // This final argument is new since the video was published
Clay_SetMeasureTextFunction(Raylib_MeasureText);
Clay_SetMeasureTextFunction(Raylib_MeasureText, 0);
Raylib_fonts[FONT_ID_BODY_16] = (Raylib_Font) {
.font = LoadFontEx("resources/Roboto-Regular.ttf", 48, 0, 400),
.fontId = FONT_ID_BODY_16
@ -111,13 +111,13 @@ int main(void) {
);
Clay_Sizing layoutExpand = {
.width = CLAY_SIZING_GROW(),
.height = CLAY_SIZING_GROW()
.width = CLAY_SIZING_GROW(0),
.height = CLAY_SIZING_GROW(0)
};
Clay_RectangleElementConfig contentBackgroundConfig = {
.color = { 90, 90, 90, 255 },
.cornerRadius = 8
.cornerRadius = CLAY_CORNER_RADIUS(8)
};
Clay_BeginLayout();
@ -128,7 +128,7 @@ int main(void) {
CLAY_LAYOUT({
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.sizing = layoutExpand,
.padding = { 16, 16 },
.padding = CLAY_PADDING_ALL(16),
.childGap = 16
})
) {
@ -139,9 +139,9 @@ int main(void) {
CLAY_LAYOUT({
.sizing = {
.height = CLAY_SIZING_FIXED(60),
.width = CLAY_SIZING_GROW()
.width = CLAY_SIZING_GROW(0)
},
.padding = { 16 },
.padding = { 16, 16, 0, 0 },
.childGap = 16,
.childAlignment = {
.y = CLAY_ALIGN_Y_CENTER
@ -151,10 +151,10 @@ int main(void) {
// Header buttons go here
CLAY(
CLAY_ID("FileButton"),
CLAY_LAYOUT({ .padding = { 16, 8 }}),
CLAY_LAYOUT({ .padding = { 16, 16, 8, 8 }}),
CLAY_RECTANGLE({
.color = { 140, 140, 140, 255 },
.cornerRadius = 5
.cornerRadius = CLAY_CORNER_RADIUS(5)
})
) {
CLAY_TEXT(CLAY_STRING("File"), CLAY_TEXT_CONFIG({
@ -177,7 +177,7 @@ int main(void) {
},
}),
CLAY_LAYOUT({
.padding = {0, 8 }
.padding = {0, 0, 8, 8 }
})
) {
CLAY(
@ -189,7 +189,7 @@ int main(void) {
}),
CLAY_RECTANGLE({
.color = { 40, 40, 40, 255 },
.cornerRadius = 8
.cornerRadius = CLAY_CORNER_RADIUS(8)
})
) {
// Render dropdown items here
@ -201,7 +201,7 @@ int main(void) {
}
}
RenderHeaderButton(CLAY_STRING("Edit"));
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW() }})) {}
CLAY(CLAY_LAYOUT({ .sizing = { CLAY_SIZING_GROW(0) }})) {}
RenderHeaderButton(CLAY_STRING("Upload"));
RenderHeaderButton(CLAY_STRING("Media"));
RenderHeaderButton(CLAY_STRING("Support"));
@ -216,19 +216,19 @@ int main(void) {
CLAY_RECTANGLE(contentBackgroundConfig),
CLAY_LAYOUT({
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.padding = { 16, 16 },
.padding = CLAY_PADDING_ALL(16),
.childGap = 8,
.sizing = {
.width = CLAY_SIZING_FIXED(250),
.height = CLAY_SIZING_GROW()
.height = CLAY_SIZING_GROW(0)
}
})
) {
for (int i = 0; i < documents.length; i++) {
Document document = documents.documents[i];
Clay_LayoutConfig sidebarButtonLayout = {
.sizing = { .width = CLAY_SIZING_GROW() },
.padding = { 16, 16 }
.sizing = { .width = CLAY_SIZING_GROW(0) },
.padding = CLAY_PADDING_ALL(16)
};
if (i == selectedDocumentIndex) {
@ -236,7 +236,7 @@ int main(void) {
CLAY_LAYOUT(sidebarButtonLayout),
CLAY_RECTANGLE({
.color = { 120, 120, 120, 255 },
.cornerRadius = 8,
.cornerRadius = CLAY_CORNER_RADIUS(8),
})
) {
CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({
@ -252,7 +252,7 @@ int main(void) {
Clay_Hovered()
? CLAY_RECTANGLE({
.color = { 120, 120, 120, 120 },
.cornerRadius = 8
.cornerRadius = CLAY_CORNER_RADIUS(8)
})
: 0
) {
@ -273,7 +273,7 @@ int main(void) {
CLAY_LAYOUT({
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.childGap = 16,
.padding = { 16, 16 },
.padding = CLAY_PADDING_ALL(16),
.sizing = layoutExpand
})
) {

View File

@ -0,0 +1,35 @@
cmake_minimum_required(VERSION 3.27)
project(clay_examples_multi_context_raylib_sidebar_scrolling_container C)
set(CMAKE_C_STANDARD 99)
# Adding Raylib
include(FetchContent)
set(FETCHCONTENT_QUIET FALSE)
set(BUILD_EXAMPLES OFF CACHE BOOL "" FORCE) # don't build the supplied examples
set(BUILD_GAMES OFF CACHE BOOL "" FORCE) # don't build the supplied example games
FetchContent_Declare(
raylib
GIT_REPOSITORY "https://github.com/raysan5/raylib.git"
GIT_TAG "master"
GIT_PROGRESS TRUE
GIT_SHALLOW TRUE
)
FetchContent_MakeAvailable(raylib)
add_executable(clay_examples_multi_context_raylib_sidebar_scrolling_container main.c)
target_compile_options(clay_examples_multi_context_raylib_sidebar_scrolling_container PUBLIC)
target_include_directories(clay_examples_multi_context_raylib_sidebar_scrolling_container PUBLIC .)
target_link_libraries(clay_examples_multi_context_raylib_sidebar_scrolling_container PUBLIC raylib)
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG")
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
add_custom_command(
TARGET clay_examples_multi_context_raylib_sidebar_scrolling_container POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
${CMAKE_CURRENT_SOURCE_DIR}/resources
${CMAKE_CURRENT_BINARY_DIR}/resources)

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -25,7 +25,7 @@ target_include_directories(clay_examples_raylib_multi_context PUBLIC .)
target_link_libraries(clay_examples_raylib_multi_context PUBLIC raylib)
set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG")
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
set(CMAKE_C_FLAGS_RELEASE "-O3")
add_custom_command(

View File

@ -7,10 +7,10 @@ Clay_Color COLOR_WHITE = { 255, 255, 255, 255};
void RenderHeaderButton(Clay_String text) {
CLAY(
CLAY_LAYOUT({ .padding = { 16, 8 }}),
CLAY_LAYOUT({ .padding = { 16, 16, 8, 8 }}),
CLAY_RECTANGLE({
.color = { 140, 140, 140, 255 },
.cornerRadius = 5
.cornerRadius = CLAY_CORNER_RADIUS(5)
})
) {
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
@ -22,7 +22,7 @@ void RenderHeaderButton(Clay_String text) {
}
void RenderDropdownMenuItem(Clay_String text) {
CLAY(CLAY_LAYOUT({ .padding = { 16, 16 }})) {
CLAY(CLAY_LAYOUT({ .padding = CLAY_PADDING_ALL(16)})) {
CLAY_TEXT(text, CLAY_TEXT_CONFIG({
.fontId = FONT_ID_BODY_16,
.fontSize = 16,
@ -79,7 +79,7 @@ typedef struct {
intptr_t memory;
} Arena;
Arena frameArena = {};
Arena frameArena = {0};
Clay_RenderCommandArray CreateLayout(Clay_Context* context, float yOffset, int32_t* documentIndex) {
Clay_SetCurrentContext(context);
@ -104,13 +104,13 @@ Clay_RenderCommandArray CreateLayout(Clay_Context* context, float yOffset, int32
);
Clay_Sizing layoutExpand = {
.width = CLAY_SIZING_GROW(),
.height = CLAY_SIZING_GROW()
.width = CLAY_SIZING_GROW(0),
.height = CLAY_SIZING_GROW(0)
};
Clay_RectangleElementConfig contentBackgroundConfig = {
.color = { 90, 90, 90, 255 },
.cornerRadius = 8
.cornerRadius = CLAY_CORNER_RADIUS(8)
};
Clay_BeginLayout();
@ -121,7 +121,7 @@ Clay_RenderCommandArray CreateLayout(Clay_Context* context, float yOffset, int32
CLAY_LAYOUT({
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.sizing = layoutExpand,
.padding = { 16, 16 },
.padding = CLAY_PADDING_ALL(16),
.childGap = 16
})
) {
@ -134,19 +134,19 @@ Clay_RenderCommandArray CreateLayout(Clay_Context* context, float yOffset, int32
CLAY_RECTANGLE(contentBackgroundConfig),
CLAY_LAYOUT({
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.padding = { 16, 16 },
.padding = CLAY_PADDING_ALL(16),
.childGap = 8,
.sizing = {
.width = CLAY_SIZING_FIXED(250),
.height = CLAY_SIZING_GROW()
.height = CLAY_SIZING_GROW(0)
}
})
) {
for (int i = 0; i < documents.length; i++) {
Document document = documents.documents[i];
Clay_LayoutConfig sidebarButtonLayout = {
.sizing = { .width = CLAY_SIZING_GROW() },
.padding = { 16, 16 }
.sizing = { .width = CLAY_SIZING_GROW(0) },
.padding = CLAY_PADDING_ALL(16)
};
if (i == *documentIndex) {
@ -154,7 +154,7 @@ Clay_RenderCommandArray CreateLayout(Clay_Context* context, float yOffset, int32
CLAY_LAYOUT(sidebarButtonLayout),
CLAY_RECTANGLE({
.color = { 120, 120, 120, 255 },
.cornerRadius = 8,
.cornerRadius = CLAY_CORNER_RADIUS(8),
})
) {
CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({
@ -173,9 +173,9 @@ Clay_RenderCommandArray CreateLayout(Clay_Context* context, float yOffset, int32
Clay_Hovered()
? CLAY_RECTANGLE({
.color = { 120, 120, 120, 120 },
.cornerRadius = 8
.cornerRadius = CLAY_CORNER_RADIUS(8)
})
: 0
: (void)0
) {
CLAY_TEXT(document.title, CLAY_TEXT_CONFIG({
.fontId = FONT_ID_BODY_16,
@ -194,7 +194,7 @@ Clay_RenderCommandArray CreateLayout(Clay_Context* context, float yOffset, int32
CLAY_LAYOUT({
.layoutDirection = CLAY_TOP_TO_BOTTOM,
.childGap = 16,
.padding = { 16, 16 },
.padding = CLAY_PADDING_ALL(16),
.sizing = layoutExpand
})
) {
@ -247,7 +247,7 @@ int main(void) {
.height = GetScreenHeight() / 2
}, (Clay_ErrorHandler) { HandleClayErrors }); // This final argument is new since the video was published
Clay_SetMeasureTextFunction(Raylib_MeasureText);
Clay_SetMeasureTextFunction(Raylib_MeasureText, 0);
Raylib_fonts[FONT_ID_BODY_16] = (Raylib_Font) {
.font = LoadFontEx("resources/Roboto-Regular.ttf", 48, 0, 400),
.fontId = FONT_ID_BODY_16

View File

@ -24,9 +24,12 @@ target_compile_options(clay_examples_raylib_sidebar_scrolling_container PUBLIC)
target_include_directories(clay_examples_raylib_sidebar_scrolling_container PUBLIC .)
target_link_libraries(clay_examples_raylib_sidebar_scrolling_container PUBLIC raylib)
set(CMAKE_C_FLAGS_DEBUG "-Wall -Werror -Wno-error=missing-braces -DCLAY_DEBUG")
set(CMAKE_C_FLAGS_RELEASE "-O3")
if(MSVC)
set(CMAKE_C_FLAGS_DEBUG "/D CLAY_DEBUG")
else()
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -O3")
endif()
add_custom_command(
TARGET clay_examples_raylib_sidebar_scrolling_container POST_BUILD

File diff suppressed because one or more lines are too long

View File

@ -3,7 +3,7 @@
// NOTE: This file only exists to make sure that clay works when included in multiple translation units.
void SatisfyCompiler() {
CLAY(CLAY_ID("SatisfyCompiler"), CLAY_LAYOUT({})) {
CLAY({ .id = CLAY_ID("SatisfyCompiler") }) {
CLAY_TEXT(CLAY_STRING("Test"), CLAY_TEXT_CONFIG({ .fontId = 0, .fontSize = 24 }));
}
}

View File

@ -1,7 +0,0 @@
$TYPE$ *$NAME$_Add($NAME$ *array, $TYPE$ item) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
return &array->internalArray[array->length - 1];
}
return $DEFAULT_VALUE$;
}

View File

@ -1,5 +0,0 @@
void $NAME$_Add($NAME$ *array, $TYPE$ item) {
if (Clay__Array_AddCapacityCheck(array->length, array->capacity)) {
array->internalArray[array->length++] = item;
}
}

View File

@ -1,3 +0,0 @@
$NAME$ $NAME$_Allocate_Arena(int32_t capacity, Clay_Arena *arena) {
return CLAY__INIT($NAME$){.capacity = capacity, .length = 0, .internalArray = ($TYPE$ *)Clay__Array_Allocate_Arena(capacity, sizeof($TYPE$), CLAY__ALIGNMENT($TYPE$), arena)};
}

View File

@ -1,3 +0,0 @@
$NAME$ $NAME$_Allocate_Arena(int32_t capacity, Clay_Arena *arena) {
return CLAY__INIT($NAME$){.capacity = capacity, .length = 0, .internalArray = ($TYPE$ *)Clay__Array_Allocate_Arena(capacity, sizeof($TYPE$), CLAY__POINTER_ALIGNMENT, arena)};
}

View File

@ -1,6 +0,0 @@
CLAY__TYPEDEF($NAME$, struct
{
int32_t capacity;
int32_t length;
$TYPE$ *internalArray;
});

View File

@ -1,5 +0,0 @@
CLAY__TYPEDEF($NAME$Slice, struct
{
int32_t length;
$TYPE$ *internalArray;
});

View File

@ -1,3 +0,0 @@
$TYPE$ *$NAME$_Get($NAME$ *array, int32_t index) {
return Clay__Array_RangeCheck(index, array->length) ? &array->internalArray[index] : $DEFAULT_VALUE$;
}

View File

@ -1,3 +0,0 @@
$TYPE$ *$NAME$Slice_Get($NAME$Slice *slice, int32_t index) {
return Clay__Array_RangeCheck(index, slice->length) ? &slice->internalArray[index] : $DEFAULT_VALUE$;
}

View File

@ -1,3 +0,0 @@
$TYPE$ $NAME$_Get($NAME$ *array, int32_t index) {
return Clay__Array_RangeCheck(index, array->length) ? array->internalArray[index] : $DEFAULT_VALUE$;
}

View File

@ -1,9 +0,0 @@
$TYPE$ $NAME$_RemoveSwapback($NAME$ *array, int32_t index) {
if (Clay__Array_RangeCheck(index, array->length)) {
array->length--;
$TYPE$ removed = array->internalArray[index];
array->internalArray[index] = array->internalArray[array->length];
return removed;
}
return $DEFAULT_VALUE$;
}

View File

@ -1,6 +0,0 @@
void $NAME$_Set($NAME$ *array, int32_t index, $TYPE$ value) {
if (Clay__Array_RangeCheck(index, array->capacity)) {
array->internalArray[index] = value;
array->length = index < array->length ? array->length : index + 1;
}
}

View File

@ -1,69 +0,0 @@
const fs = require('fs');
const path = require('path');
let files = ['../clay.h'];
let templates = ['./'];
function readCTemplatesRecursive(directory) {
fs.readdirSync(directory).forEach(template => {
const absolute = path.join(directory, template);
if (fs.statSync(absolute).isDirectory()) return readCTemplatesRecursive(absolute);
else if (template.endsWith('template.c')) {
return templates.push(absolute);
}
});
}
readCTemplatesRecursive(__dirname);
for (const file of files) {
const contents = fs.readFileSync(file, 'utf8');
const lines = contents.split('\n');
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
if (line.startsWith('// __GENERATED__ template')) {
const [comment, generated, templateOpen, templateNames, ...args] = line.split(" ");
let matchingEndingLine = -1;
for (let j = i + 1; j < lines.length; j++) {
if (lines[j].startsWith('// __GENERATED__ template')) {
matchingEndingLine = j;
break;
}
}
if (matchingEndingLine !== -1) {
i++;
lines.splice(i, matchingEndingLine - (i));
lines.splice(i, 0, ['#pragma region generated']);
i++;
for (const templateName of templateNames.split(',')) {
var matchingTemplate = templates.find(t => t.endsWith(`${templateName}.template.c`));
if (matchingTemplate) {
let templateContents = fs.readFileSync(matchingTemplate, 'utf8');
for (const arg of args) {
[argName, argValue] = arg.split('=');
templateContents = templateContents.replaceAll(`\$${argName}\$`, argValue);
}
let remainingTokens = templateContents.split('$');
if (remainingTokens.length > 1) {
console.log(`Error at ${file}:${i}: Template is missing parameter ${remainingTokens[1]}`)
process.exit();
} else {
templateContents = templateContents.split('\n');
lines.splice(i, 0, ...templateContents);
i += templateContents.length;
}
} else {
console.log(`Error at ${file}:${i + 1}: no template with name ${templateName}.template.c was found.`);
process.exit();
}
}
lines.splice(i, 0, ['#pragma endregion']);
i++;
} else {
console.log(`Error at ${file}:${i + 1}: template was opened and not closed again.`);
process.exit();
}
}
}
fs.writeFileSync(file, lines.join('\n'));
}

View File

@ -1,7 +1,5 @@
Please note, the SDL2 renderer is not 100% feature complete. It is currently missing:
- Border rendering
- Image rendering
- Rounded rectangle corners
Note: on Mac OSX, SDL2 for some reason decides to automatically disable momentum scrolling on macbook trackpads.
@ -10,4 +8,4 @@ You can re enable it in objective C using:
```C
[[NSUserDefaults standardUserDefaults] setBool: YES
forKey: @"AppleMomentumScrollSupported"];
```
```

View File

@ -1,6 +1,10 @@
#include "../../clay.h"
#include <SDL.h>
#include <SDL_ttf.h>
#include <SDL_image.h>
#include <stdio.h>
#define CLAY_COLOR_TO_SDL_COLOR_ARGS(color) color.r, color.g, color.b, color.a
typedef struct
{
@ -8,13 +12,14 @@ typedef struct
TTF_Font *font;
} SDL2_Font;
static SDL2_Font SDL2_fonts[1];
static Clay_Dimensions SDL2_MeasureText(Clay_String *text, Clay_TextElementConfig *config)
static Clay_Dimensions SDL2_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData)
{
TTF_Font *font = SDL2_fonts[config->fontId].font;
char *chars = (char *)calloc(text->length + 1, 1);
memcpy(chars, text->chars, text->length);
SDL2_Font *fonts = (SDL2_Font*)userData;
TTF_Font *font = fonts[config->fontId].font;
char *chars = (char *)calloc(text.length + 1, 1);
memcpy(chars, text.chars, text.length);
int width = 0;
int height = 0;
if (TTF_SizeUTF8(font, chars, &width, &height) < 0) {
@ -30,7 +35,7 @@ static Clay_Dimensions SDL2_MeasureText(Clay_String *text, Clay_TextElementConfi
SDL_Rect currentClippingRectangle;
static void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray renderCommands)
static void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray renderCommands, SDL2_Font *fonts)
{
for (uint32_t i = 0; i < renderCommands.length; i++)
{
@ -53,10 +58,10 @@ static void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray ren
}
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
Clay_TextElementConfig *config = renderCommand->config.textElementConfig;
Clay_String text = renderCommand->text;
Clay_StringSlice text = renderCommand->text;
char *cloned = (char *)calloc(text.length + 1, 1);
memcpy(cloned, text.chars, text.length);
TTF_Font* font = SDL2_fonts[config->fontId].font;
TTF_Font* font = fonts[config->fontId].font;
SDL_Surface *surface = TTF_RenderUTF8_Blended(font, cloned, (SDL_Color) {
.r = (Uint8)config->textColor.r,
.g = (Uint8)config->textColor.g,
@ -92,10 +97,60 @@ static void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray ren
SDL_RenderSetClipRect(renderer, NULL);
break;
}
case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
SDL_Surface *image = (SDL_Surface *)renderCommand->config.imageElementConfig->imageData;
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, image);
SDL_Rect destination = (SDL_Rect){
.x = boundingBox.x,
.y = boundingBox.y,
.w = boundingBox.width,
.h = boundingBox.height,
};
SDL_RenderCopy(renderer, texture, NULL, &destination);
break;
}
case CLAY_RENDER_COMMAND_TYPE_BORDER: {
Clay_BorderElementConfig *config = renderCommand->config.borderElementConfig;
if (config->left.width > 0) {
SDL_SetRenderDrawColor(renderer, CLAY_COLOR_TO_SDL_COLOR_ARGS(config->left.color));
SDL_FRect rect = { boundingBox.x, boundingBox.y + config->cornerRadius.topLeft, config->left.width, boundingBox.height - config->cornerRadius.topLeft - config->cornerRadius.bottomLeft };
SDL_RenderFillRectF(renderer, &rect);
}
if (config->right.width > 0) {
SDL_SetRenderDrawColor(renderer, CLAY_COLOR_TO_SDL_COLOR_ARGS(config->right.color));
SDL_FRect rect = { boundingBox.x + boundingBox.width - config->right.width, boundingBox.y + config->cornerRadius.topRight, config->right.width, boundingBox.height - config->cornerRadius.topRight - config->cornerRadius.bottomRight };
SDL_RenderFillRectF(renderer, &rect);
}
if (config->right.width > 0) {
SDL_SetRenderDrawColor(renderer, CLAY_COLOR_TO_SDL_COLOR_ARGS(config->right.color));
SDL_FRect rect = { boundingBox.x + boundingBox.width - config->right.width, boundingBox.y + config->cornerRadius.topRight, config->right.width, boundingBox.height - config->cornerRadius.topRight - config->cornerRadius.bottomRight };
SDL_RenderFillRectF(renderer, &rect);
}
if (config->top.width > 0) {
SDL_SetRenderDrawColor(renderer, CLAY_COLOR_TO_SDL_COLOR_ARGS(config->right.color));
SDL_FRect rect = { boundingBox.x + config->cornerRadius.topLeft, boundingBox.y, boundingBox.width - config->cornerRadius.topLeft - config->cornerRadius.topRight, config->top.width };
SDL_RenderFillRectF(renderer, &rect);
}
if (config->bottom.width > 0) {
SDL_SetRenderDrawColor(renderer, CLAY_COLOR_TO_SDL_COLOR_ARGS(config->bottom.color));
SDL_FRect rect = { boundingBox.x + config->cornerRadius.bottomLeft, boundingBox.y + boundingBox.height - config->bottom.width, boundingBox.width - config->cornerRadius.bottomLeft - config->cornerRadius.bottomRight, config->bottom.width };
SDL_RenderFillRectF(renderer, &rect);
}
break;
}
default: {
fprintf(stderr, "Error: unhandled render command: %d\n", renderCommand->commandType);
exit(1);
}
}
}
}
}

4
renderers/SDL3/README Normal file
View File

@ -0,0 +1,4 @@
Please note, the SDL3 renderer is not 100% feature complete. It is currently missing:
- Images
- Scroll / Scissor handling

View File

@ -0,0 +1,242 @@
#include "../../clay.h"
#include <SDL3/SDL_main.h>
#include <SDL3/SDL.h>
#include <SDL3_ttf/SDL_ttf.h>
/* This needs to be global because the "MeasureText" callback doesn't have a
* user data parameter */
static TTF_Font *gFonts[1];
/* Global for convenience. Even in 4K this is enough for smooth curves (low radius or rect size coupled with
* no AA or low resolution might make it appear as jagged curves) */
static int NUM_CIRCLE_SEGMENTS = 16;
//all rendering is performed by a single SDL call, avoiding multiple RenderRect + plumbing choice for circles.
static void SDL_RenderFillRoundedRect(SDL_Renderer *renderer, const SDL_FRect rect, const float cornerRadius, const Clay_Color _color) {
const SDL_FColor color = { _color.r/255, _color.g/255, _color.b/255, _color.a/255 };
int indexCount = 0, vertexCount = 0;
const float minRadius = SDL_min(rect.w, rect.h) / 2.0f;
const float clampedRadius = SDL_min(cornerRadius, minRadius);
const int numCircleSegments = SDL_max(NUM_CIRCLE_SEGMENTS, (int) clampedRadius * 0.5f);
int totalVertices = 4 + (4 * (numCircleSegments * 2)) + 2*4;
int totalIndices = 6 + (4 * (numCircleSegments * 3)) + 6*4;
SDL_Vertex vertices[totalVertices];
int indices[totalIndices];
//define center rectangle
vertices[vertexCount++] = (SDL_Vertex){ {rect.x + clampedRadius, rect.y + clampedRadius}, color, {0, 0} }; //0 center TL
vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w - clampedRadius, rect.y + clampedRadius}, color, {1, 0} }; //1 center TR
vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w - clampedRadius, rect.y + rect.h - clampedRadius}, color, {1, 1} }; //2 center BR
vertices[vertexCount++] = (SDL_Vertex){ {rect.x + clampedRadius, rect.y + rect.h - clampedRadius}, color, {0, 1} }; //3 center BL
indices[indexCount++] = 0;
indices[indexCount++] = 1;
indices[indexCount++] = 3;
indices[indexCount++] = 1;
indices[indexCount++] = 2;
indices[indexCount++] = 3;
//define rounded corners as triangle fans
const float step = (SDL_PI_F/2) / numCircleSegments;
for (int i = 0; i < numCircleSegments; i++) {
const float angle1 = (float)i * step;
const float angle2 = ((float)i + 1.0f) * step;
for (int j = 0; j < 4; j++) { // Iterate over four corners
float cx, cy, signX, signY;
switch (j) {
case 0: cx = rect.x + clampedRadius; cy = rect.y + clampedRadius; signX = -1; signY = -1; break; // Top-left
case 1: cx = rect.x + rect.w - clampedRadius; cy = rect.y + clampedRadius; signX = 1; signY = -1; break; // Top-right
case 2: cx = rect.x + rect.w - clampedRadius; cy = rect.y + rect.h - clampedRadius; signX = 1; signY = 1; break; // Bottom-right
case 3: cx = rect.x + clampedRadius; cy = rect.y + rect.h - clampedRadius; signX = -1; signY = 1; break; // Bottom-left
default: return;
}
vertices[vertexCount++] = (SDL_Vertex){ {cx + SDL_cosf(angle1) * clampedRadius * signX, cy + SDL_sinf(angle1) * clampedRadius * signY}, color, {0, 0} };
vertices[vertexCount++] = (SDL_Vertex){ {cx + SDL_cosf(angle2) * clampedRadius * signX, cy + SDL_sinf(angle2) * clampedRadius * signY}, color, {0, 0} };
indices[indexCount++] = j; // Connect to corresponding central rectangle vertex
indices[indexCount++] = vertexCount - 2;
indices[indexCount++] = vertexCount - 1;
}
}
//Define edge rectangles
// Top edge
vertices[vertexCount++] = (SDL_Vertex){ {rect.x + clampedRadius, rect.y}, color, {0, 0} }; //TL
vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w - clampedRadius, rect.y}, color, {1, 0} }; //TR
indices[indexCount++] = 0;
indices[indexCount++] = vertexCount - 2; //TL
indices[indexCount++] = vertexCount - 1; //TR
indices[indexCount++] = 1;
indices[indexCount++] = 0;
indices[indexCount++] = vertexCount - 1; //TR
// Right edge
vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w, rect.y + clampedRadius}, color, {1, 0} }; //RT
vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w, rect.y + rect.h - clampedRadius}, color, {1, 1} }; //RB
indices[indexCount++] = 1;
indices[indexCount++] = vertexCount - 2; //RT
indices[indexCount++] = vertexCount - 1; //RB
indices[indexCount++] = 2;
indices[indexCount++] = 1;
indices[indexCount++] = vertexCount - 1; //RB
// Bottom edge
vertices[vertexCount++] = (SDL_Vertex){ {rect.x + rect.w - clampedRadius, rect.y + rect.h}, color, {1, 1} }; //BR
vertices[vertexCount++] = (SDL_Vertex){ {rect.x + clampedRadius, rect.y + rect.h}, color, {0, 1} }; //BL
indices[indexCount++] = 2;
indices[indexCount++] = vertexCount - 2; //BR
indices[indexCount++] = vertexCount - 1; //BL
indices[indexCount++] = 3;
indices[indexCount++] = 2;
indices[indexCount++] = vertexCount - 1; //BL
// Left edge
vertices[vertexCount++] = (SDL_Vertex){ {rect.x, rect.y + rect.h - clampedRadius}, color, {0, 1} }; //LB
vertices[vertexCount++] = (SDL_Vertex){ {rect.x, rect.y + clampedRadius}, color, {0, 0} }; //LT
indices[indexCount++] = 3;
indices[indexCount++] = vertexCount - 2; //LB
indices[indexCount++] = vertexCount - 1; //LT
indices[indexCount++] = 0;
indices[indexCount++] = 3;
indices[indexCount++] = vertexCount - 1; //LT
// Render everything
SDL_RenderGeometry(renderer, NULL, vertices, vertexCount, indices, indexCount);
}
static void SDL_RenderArc(SDL_Renderer *renderer, const SDL_FPoint center, const float radius, const float startAngle, const float endAngle, const float thickness, const Clay_Color color) {
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
const float radStart = startAngle * (SDL_PI_F / 180.0f);
const float radEnd = endAngle * (SDL_PI_F / 180.0f);
const int numCircleSegments = SDL_max(NUM_CIRCLE_SEGMENTS, (int)(radius * 1.5f)); //increase circle segments for larger circles, 1.5 is arbitrary.
const float angleStep = (radEnd - radStart) / (float)numCircleSegments;
const float thicknessStep = 0.4f; //arbitrary value to avoid overlapping lines. Changing THICKNESS_STEP or numCircleSegments might cause artifacts.
for (float t = thicknessStep; t < thickness - thicknessStep; t += thicknessStep) {
SDL_FPoint points[numCircleSegments + 1];
const float clampedRadius = SDL_max(radius - t, 1.0f);
for (int i = 0; i <= numCircleSegments; i++) {
const float angle = radStart + i * angleStep;
points[i] = (SDL_FPoint){
SDL_roundf(center.x + SDL_cosf(angle) * clampedRadius),
SDL_roundf(center.y + SDL_sinf(angle) * clampedRadius) };
}
SDL_RenderLines(renderer, points, numCircleSegments + 1);
}
}
static void SDL_RenderClayCommands(SDL_Renderer *renderer, Clay_RenderCommandArray *rcommands)
{
for (size_t i = 0; i < rcommands->length; i++) {
Clay_RenderCommand *rcmd = Clay_RenderCommandArray_Get(rcommands, i);
const Clay_BoundingBox bounding_box = rcmd->boundingBox;
const SDL_FRect rect = { bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height };
switch (rcmd->commandType) {
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
const Clay_RectangleElementConfig *config = rcmd->config.rectangleElementConfig;
const Clay_Color color = config->color;
SDL_SetRenderDrawColor(renderer, color.r, color.g, color.b, color.a);
if (config->cornerRadius.topLeft > 0) {
SDL_RenderFillRoundedRect(renderer, rect, config->cornerRadius.topLeft, color);
} else {
SDL_RenderFillRect(renderer, &rect);
}
} break;
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
const Clay_TextElementConfig *config = rcmd->config.textElementConfig;
const Clay_StringSlice *text = &rcmd->text;
const SDL_Color color = { config->textColor.r, config->textColor.g, config->textColor.b, config->textColor.a };
TTF_Font *font = gFonts[config->fontId];
SDL_Surface *surface = TTF_RenderText_Blended(font, text->chars, text->length, color);
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
SDL_RenderTexture(renderer, texture, NULL, &rect);
SDL_DestroySurface(surface);
SDL_DestroyTexture(texture);
} break;
case CLAY_RENDER_COMMAND_TYPE_BORDER: {
const Clay_BorderElementConfig *config = rcmd->config.borderElementConfig;
const float minRadius = SDL_min(rect.w, rect.h) / 2.0f;
const Clay_CornerRadius clampedRadii = {
.topLeft = SDL_min(config->cornerRadius.topLeft, minRadius),
.topRight = SDL_min(config->cornerRadius.topRight, minRadius),
.bottomLeft = SDL_min(config->cornerRadius.bottomLeft, minRadius),
.bottomRight = SDL_min(config->cornerRadius.bottomRight, minRadius)
};
//edges
SDL_SetRenderDrawColor(renderer, config->left.color.r, config->left.color.g, config->left.color.b, config->left.color.a);
if (config->left.width > 0) {
const float starting_y = rect.y + clampedRadii.topLeft;
const float length = rect.h - clampedRadii.topLeft - clampedRadii.bottomLeft;
SDL_FRect line = { rect.x, starting_y, config->left.width, length };
SDL_RenderFillRect(renderer, &line);
}
if (config->right.width > 0) {
const float starting_x = rect.x + rect.w - (float)config->right.width;
const float starting_y = rect.y + clampedRadii.topRight;
const float length = rect.h - clampedRadii.topRight - clampedRadii.bottomRight;
SDL_FRect line = { starting_x, starting_y, config->right.width, length };
SDL_RenderFillRect(renderer, &line);
}
if (config->top.width > 0) {
const float starting_x = rect.x + clampedRadii.topLeft;
const float length = rect.w - clampedRadii.topLeft - clampedRadii.topRight;
SDL_FRect line = { starting_x, rect.y, length, config->top.width };
SDL_RenderFillRect(renderer, &line);
}
if (config->bottom.width > 0) {
const float starting_x = rect.x + clampedRadii.bottomLeft;
const float starting_y = rect.y + rect.h - (float)config->bottom.width;
const float length = rect.w - clampedRadii.bottomLeft - clampedRadii.bottomRight;
SDL_FRect line = { starting_x, starting_y, length, config->bottom.width };
SDL_SetRenderDrawColor(renderer, config->bottom.color.r, config->bottom.color.g, config->bottom.color.b, config->bottom.color.a);
SDL_RenderFillRect(renderer, &line);
}
//corners
if (config->cornerRadius.topLeft > 0) {
const float centerX = rect.x + clampedRadii.topLeft -1;
const float centerY = rect.y + clampedRadii.topLeft;
SDL_RenderArc(renderer, (SDL_FPoint){centerX, centerY}, clampedRadii.topLeft,
180.0f, 270.0f, config->top.width, config->top.color);
}
if (config->cornerRadius.topRight > 0) {
const float centerX = rect.x + rect.w - clampedRadii.topRight -1;
const float centerY = rect.y + clampedRadii.topRight;
SDL_RenderArc(renderer, (SDL_FPoint){centerX, centerY}, clampedRadii.topRight,
270.0f, 360.0f, config->top.width, config->top.color);
}
if (config->cornerRadius.bottomLeft > 0) {
const float centerX = rect.x + clampedRadii.bottomLeft -1;
const float centerY = rect.y + rect.h - clampedRadii.bottomLeft -1;
SDL_RenderArc(renderer, (SDL_FPoint){centerX, centerY}, clampedRadii.bottomLeft,
90.0f, 180.0f, config->bottom.width, config->bottom.color);
}
if (config->cornerRadius.bottomRight > 0) {
const float centerX = rect.x + rect.w - clampedRadii.bottomRight -1; //TODO: why need to -1 in all calculations???
const float centerY = rect.y + rect.h - clampedRadii.bottomRight -1;
SDL_RenderArc(renderer, (SDL_FPoint){centerX, centerY}, clampedRadii.bottomRight,
0.0f, 90.0f, config->bottom.width, config->bottom.color);
}
} break;
default:
SDL_Log("Unknown render command type: %d", rcmd->commandType);
}
}
}

View File

@ -83,7 +83,7 @@ static inline char *Clay_Cairo__NullTerminate(Clay_String *str) {
}
// Measure text using cairo's *toy* text API.
static inline Clay_Dimensions Clay_Cairo_MeasureText(Clay_String *str, Clay_TextElementConfig *config) {
static inline Clay_Dimensions Clay_Cairo_MeasureText(Clay_String *str, Clay_TextElementConfig *config, uintptr_t userData) {
// Edge case: Clay computes the width of a whitespace character
// once. Cairo does not factor in whitespaces when computing text
// extents, this edge-case serves as a short-circuit to introduce

View File

@ -35,7 +35,7 @@ typedef struct
CustomLayoutElementType type;
union {
CustomLayoutElement_3DModel model;
};
} customData;
} CustomLayoutElement;
// Get a ray trace from the screen position (i.e mouse) within a specific section of the screen
@ -87,10 +87,8 @@ Ray GetScreenToWorldPointWithZDistance(Vector2 position, Camera camera, int scre
return ray;
}
uint32_t measureCalls = 0;
static inline Clay_Dimensions Raylib_MeasureText(Clay_String *text, Clay_TextElementConfig *config) {
measureCalls++;
static inline Clay_Dimensions Raylib_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, uintptr_t userData) {
// Measure string size for Font
Clay_Dimensions textSize = { 0 };
@ -99,16 +97,19 @@ static inline Clay_Dimensions Raylib_MeasureText(Clay_String *text, Clay_TextEle
float textHeight = config->fontSize;
Font fontToUse = Raylib_fonts[config->fontId].font;
// Font failed to load, likely the fonts are in the wrong place relative to the execution dir
if (!fontToUse.glyphs) return textSize;
float scaleFactor = config->fontSize/(float)fontToUse.baseSize;
for (int i = 0; i < text->length; ++i)
for (int i = 0; i < text.length; ++i)
{
if (text->chars[i] == '\n') {
if (text.chars[i] == '\n') {
maxTextWidth = fmax(maxTextWidth, lineTextWidth);
lineTextWidth = 0;
continue;
}
int index = text->chars[i] - 32;
int index = text.chars[i] - 32;
if (fontToUse.glyphs[index].advanceX != 0) lineTextWidth += fontToUse.glyphs[index].advanceX;
else lineTextWidth += (fontToUse.recs[index].width + fontToUse.glyphs[index].offsetX);
}
@ -129,7 +130,6 @@ void Clay_Raylib_Initialize(int width, int height, const char *title, unsigned i
void Clay_Raylib_Render(Clay_RenderCommandArray renderCommands)
{
measureCalls = 0;
for (int j = 0; j < renderCommands.length; j++)
{
Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, j);
@ -138,7 +138,7 @@ void Clay_Raylib_Render(Clay_RenderCommandArray renderCommands)
{
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
// Raylib uses standard C strings so isn't compatible with cheap slices, we need to clone the string to append null terminator
Clay_String text = renderCommand->text;
Clay_StringSlice text = renderCommand->text;
char *cloned = (char *)malloc(text.length + 1);
memcpy(cloned, text.chars, text.length);
cloned[text.length] = '\0';
@ -216,7 +216,7 @@ void Clay_Raylib_Render(Clay_RenderCommandArray renderCommands)
float scaleValue = CLAY__MIN(CLAY__MIN(1, 768 / rootBox.height) * CLAY__MAX(1, rootBox.width / 1024), 1.5f);
Ray positionRay = GetScreenToWorldPointWithZDistance((Vector2) { renderCommand->boundingBox.x + renderCommand->boundingBox.width / 2, renderCommand->boundingBox.y + (renderCommand->boundingBox.height / 2) + 20 }, Raylib_camera, (int)roundf(rootBox.width), (int)roundf(rootBox.height), 140);
BeginMode3D(Raylib_camera);
DrawModel(customElement->model.model, positionRay.position, customElement->model.scale * scaleValue, WHITE); // Draw 3d model with texture
DrawModel(customElement->customData.model.model, positionRay.position, customElement->customData.model.scale * scaleValue, WHITE); // Draw 3d model with texture
EndMode3D();
break;
}