mirror of
https://github.com/nicbarker/clay.git
synced 2025-04-15 10:48:04 +00:00
162 lines
7.3 KiB
C
162 lines
7.3 KiB
C
// Must be defined in one file, _before_ #include "clay.h"
|
|
#define CLAY_IMPLEMENTATION
|
|
#include "../../clay.h"
|
|
|
|
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_ElementDeclaration sidebarItemConfig = (Clay_ElementDeclaration) {
|
|
.layout = {
|
|
.sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_FIXED(50) }
|
|
},
|
|
.backgroundColor = COLOR_ORANGE
|
|
};
|
|
|
|
// Re-useable components are just normal functions
|
|
void SidebarItemComponent() {
|
|
CLAY(sidebarItemConfig) {
|
|
// children go here...
|
|
}
|
|
}
|
|
|
|
// This may be slow for large numbers of images,
|
|
// consider allocating and initializing interfaces
|
|
// once outside of this function if it becomes an issue
|
|
HBITMAP LoadImageToBitmap(LPCWSTR filename)
|
|
{
|
|
IWICImagingFactory *imgFactory = NULL;
|
|
IWICBitmapDecoder *bmpDecoder = NULL;
|
|
IWICBitmapFrameDecode *bmpFrame = NULL;
|
|
IWICFormatConverter *formatConverter = NULL;
|
|
|
|
HBITMAP hBitmap = NULL;
|
|
void *bits = NULL;
|
|
UINT width = 0;
|
|
UINT height = 0;
|
|
BITMAPINFO bmi = {0};
|
|
|
|
CoInitialize(NULL); // Lets us use Windows COM correctly
|
|
CoCreateInstance(
|
|
&CLSID_WICImagingFactory,
|
|
NULL,
|
|
CLSCTX_INPROC_SERVER,
|
|
&IID_IWICImagingFactory,
|
|
(void **) &imgFactory);
|
|
imgFactory->lpVtbl->CreateDecoderFromFilename(
|
|
imgFactory,
|
|
filename,
|
|
NULL,
|
|
GENERIC_READ,
|
|
WICDecodeMetadataCacheOnLoad,
|
|
&bmpDecoder);
|
|
bmpDecoder->lpVtbl->GetFrame(decoder, 0, &bmpFrame);
|
|
imgFactory->lpVtbl->CreateFormatConverter(factory, &converter);
|
|
formatConverter->lpVtbl->Initialize(
|
|
formatConverter,
|
|
(IWICBitmapSource*) bmpFrame,
|
|
&GUID_WICPixelFormat32bppPBGRA,
|
|
WICBitmapDitherTypeNone,
|
|
NULL,
|
|
0.0,
|
|
WICBitmapPaletteTypeCustom);
|
|
frame->lpVtbl->GetSize(frame, &width, &height);
|
|
|
|
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
bmi.bmiHeader.biWidth = width;
|
|
bmi.bmiHeader.biHeight = -((LONG) height); // Negative makes it a top down bitmap
|
|
bmi.bmiHeader.biPlanes = 1;
|
|
bmi.bmiHeader.biBitCount = 32;
|
|
bmi.bmiHeader.biCompression = BI_RGB;
|
|
|
|
hBitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &bits, NULL, 0);
|
|
formatConverter->lpVtble->CopyPixels(converter, NULL, width * 4, width * height * 4, (BYTE*) bits);
|
|
if (formatConverter) converter->lpVtbl->Release(formatConverter);
|
|
if (bmpFrame) frame->lpVtbl->Release(bmpFrame);
|
|
if (bmpDecoder) decoder->lpVtbl->Release(bmpDecoder);
|
|
if (imgFactory) factory->lpVtbl->Release(imgFactory);
|
|
CoUninitialize();
|
|
|
|
return hBitmap;
|
|
}
|
|
|
|
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));
|
|
|
|
// Note: screenWidth and screenHeight will need to come from your environment, Clay doesn't handle window related tasks
|
|
Clay_Initialize(arena, (Clay_Dimensions) { screenWidth, screenHeight }, (Clay_ErrorHandler) { HandleClayErrors });
|
|
|
|
// Load image resource
|
|
hBitmap profilePicture = LoadImage(L"reef.jpg");
|
|
|
|
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({ .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("SideBar"),
|
|
.layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM, .sizing = { .width = CLAY_SIZING_FIXED(300), .height = CLAY_SIZING_GROW(0) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16 },
|
|
.backgroundColor = COLOR_LIGHT
|
|
}) {
|
|
CLAY({ .id = CLAY_ID("ProfilePictureOuter"), .layout = { .sizing = { .width = CLAY_SIZING_GROW(0) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16, .childAlignment = { .y = CLAY_ALIGN_Y_CENTER } }, .backgroundColor = COLOR_RED }) {
|
|
CLAY({ .id = CLAY_ID("ProfilePicture"), .layout = { .sizing = { .width = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60) }}, .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({ .id = CLAY_ID("MainContent"), .layout = { .sizing = { .width = CLAY_SIZING_GROW(0), .height = CLAY_SIZING_GROW(0) } }, .backgroundColor = COLOR_LIGHT }) {}
|
|
}
|
|
}
|
|
|
|
// 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->renderData.rectangle.backgroundColor);
|
|
}
|
|
// ... Implement handling of other command types
|
|
}
|
|
}
|
|
}
|
|
}
|