Clay UI Hello World
Draft post. I was looking for something that is a simple intro to Clay UI, but I gave up on it. TBD
- Install SDL3
- Install nasm?
- Set up SDL
- SDL_ttf
- SDL_image
- Set up Clay
- Define and include
- Measure text function
- Handle error function
- Initialization
- Declare elements
Basic SDL Hello world:
// Initial SDL set up
#define SDL_MAIN_HANDLED
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
int main(int argc, char* argv[]) {
int screenWidth = 600;
int screenHeight = 600;
// SDL Setup
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
bool success = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
if(!success) {
SDL_Log("SDL_Init error: %s", SDL_GetError());
return 1;
}
window = SDL_CreateWindow("SDL Hello World",screenWidth,screenHeight,SDL_WINDOW_RESIZABLE);
if(window == NULL) {
SDL_Log("SDL_CreateWindow error: %s", SDL_GetError());
return 1;
}
renderer = SDL_CreateRenderer(window, NULL);
if(renderer == NULL) {
SDL_Log("SDL_CreateRenderer error: %s", SDL_GetError());
return 1;
}
// SDL Render loop
bool running = true;
SDL_Event event;
while(running){
/* Event handling */
while(SDL_PollEvent(&event)){
switch(event.type) {
case SDL_EVENT_QUIT:
running = false;
break;
default:
break;
}
}
/* Rendering */
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 100);
SDL_RenderClear(renderer);
SDL_RenderPresent(renderer);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}
Adding Clay to the SDL setup.
// Initial SDL set up
#define SDL_MAIN_HANDLED
// alternatively use SDL_MAIN_HANDLED
#include <SDL3/SDL.h>
#include <SDL3/SDL_main.h>
#define CLAY_IMPLEMENTATION
#include <clay.H>
// 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
};
}
// Example clay error handler
void HandleClayErrors(Clay_ErrorData errorData) {
SDL_Log("%s", errorData.errorText.chars);
}
// Example clay SDL Renderer
void SDL_Clay_Render(Clay_RenderCommandArray* renderCommands, SDL_Renderer* renderer) {
for(int i = 0; i < renderCommands->length; i++) {
Clay_RenderCommand* rcmd = Clay_RenderCommandArray_Get(renderCommands, i);
const Clay_BoundingBox bounding_box = rcmd->boundingBox;
SDL_FRect rect = { (int)bounding_box.x, (int)bounding_box.y, (int)bounding_box.width, (int)bounding_box.height};
switch(rcmd->commandType) {
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE:
Clay_RectangleRenderData *config = &(rcmd->renderData.rectangle);
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, config->backgroundColor.r, config->backgroundColor.b, config->backgroundColor.g, config->backgroundColor.a);
if(config->cornerRadius.topLeft > 0)
{
SDL_RenderFillRect(renderer, &rect);
} else {
SDL_RenderFillRect(renderer, &rect);
}
break;
case CLAY_RENDER_COMMAND_TYPE_TEXT:
break;
case CLAY_RENDER_COMMAND_TYPE_BORDER:
break;
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END:
break;
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START:
break;
case CLAY_RENDER_COMMAND_TYPE_IMAGE:
break;
default:
SDL_Log("Unknkown render command: %d", rcmd->commandType );
}
}
}
int main(int argc, char* argv[]) {
int screenWidth = 600;
int screenHeight = 600;
// SDL Setup
SDL_Window* window = NULL;
SDL_Renderer* renderer = NULL;
bool success = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS);
if(!success) {
SDL_Log("SDL_Init error: %s", SDL_GetError());
return 1;
}
window = SDL_CreateWindow("SDL Hello World",screenWidth,screenHeight,SDL_WINDOW_RESIZABLE);
if(window == NULL) {
SDL_Log("SDL_CreateWindow error: %s", SDL_GetError());
return 1;
}
renderer = SDL_CreateRenderer(window, NULL);
if(renderer == NULL) {
SDL_Log("SDL_CreateRenderer error: %s", SDL_GetError());
return 1;
}
// Clay Setup
uint64_t totalMemorySize = Clay_MinMemorySize();
Clay_Arena arena = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
Clay_Initialize(arena, (Clay_Dimensions) {screenWidth, screenHeight }, (Clay_ErrorHandler) { HandleClayErrors });
// Set layout dimension in render loop if resizing
Clay_SetLayoutDimensions((Clay_Dimensions) { screenWidth, screenHeight });
// Clay element declaration
/*
<OutterContainer>
<InnerContainer>
<MainContent />
</InnerContainer>
</OutterContainer>
*/
Clay_BeginLayout();
CLAY({ .id = CLAY_ID("OuterContainer"), .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)}, .padding = CLAY_PADDING_ALL(16), .childGap = 16 }, .backgroundColor = {250,250,255,255} }) {
CLAY({
.id = CLAY_ID("InnerContainer"),
.layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_GROW(300), .height = CLAY_SIZING_GROW(1) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16 },
.backgroundColor = (Clay_Color) {224,215,210,255}
}) {
CLAY({ .id = CLAY_ID("MainContent"), .layout = { .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) } }, .backgroundColor = (Clay_Color) {225,138,50,255} }) {}
}
}
Clay_RenderCommandArray renderCommands = Clay_EndLayout();
// SDL Render loop
bool running = true;
SDL_Event event;
while(running){
while(SDL_PollEvent(&event)){
switch(event.type) {
case SDL_EVENT_QUIT:
running = false;
break;
default:
break;
}
}
SDL_SetRenderDrawColor(renderer, 0, 255, 0, 100);
SDL_RenderClear(renderer);
// Custom render function
SDL_Clay_Render(&renderCommands, renderer);
SDL_RenderPresent(renderer);
}
SDL_DestroyWindow(window);
SDL_DestroyRenderer(renderer);
SDL_Quit();
return 0;
}