mirror of
https://github.com/nicbarker/clay.git
synced 2025-09-18 12:36:17 +00:00
Merge branch 'main' into HEAD
For image-related changes
This commit is contained in:
commit
d487d5990b
142
README.md
142
README.md
|
@ -92,7 +92,7 @@ int main() {
|
|||
.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({ .id = CLAY_ID("ProfilePicture"), .layout = { .sizing = { .width = CLAY_SIZING_FIXED(60), .height = CLAY_SIZING_FIXED(60) }}, .image = { .imageData = &profilePicture } }) {}
|
||||
CLAY_TEXT(CLAY_STRING("Clay - UI Library"), CLAY_TEXT_CONFIG({ .fontSize = 24, .textColor = {255, 255, 255, 255} }));
|
||||
}
|
||||
|
||||
|
@ -161,8 +161,8 @@ For help starting out or to discuss clay, considering joining [the discord serve
|
|||
- [Clay_MinMemorySize](#clay_minmemorysize)
|
||||
- [Clay_CreateArenaWithCapacityAndMemory](#clay_createarenawithcapacityandmemory)
|
||||
- [Clay_SetMeasureTextFunction](#clay_setmeasuretextfunction)
|
||||
- [Clay_ResetMeasureTextCache](#clau_resetmeasuretextcache)
|
||||
- [Clay_SetMaxElementCount](clay_setmaxelementcount)
|
||||
- [Clay_ResetMeasureTextCache](#clay_resetmeasuretextcache)
|
||||
- [Clay_SetMaxElementCount](#clay_setmaxelementcount)
|
||||
- [Clay_SetMaxMeasureTextCacheWordCount](#clay_setmaxmeasuretextcachewordcount)
|
||||
- [Clay_Initialize](#clay_initialize)
|
||||
- [Clay_GetCurrentContext](#clay_getcurrentcontext)
|
||||
|
@ -360,11 +360,11 @@ Clay_UpdateScrollContainers(
|
|||
);
|
||||
// ...
|
||||
// Clay internally tracks the scroll containers offset, and Clay_GetScrollOffset returns the x,y offset of the currently open element
|
||||
CLAY({ .clip = vertical, .childOffset = Clay_GetScrollOffset() }) {
|
||||
CLAY({ .clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() } }) {
|
||||
// Scrolling contents
|
||||
}
|
||||
// .childOffset can be provided directly if you would prefer to manage scrolling outside of clay
|
||||
CLAY({ .clip = vertical, .childOffset = myData.scrollContainer.offset }) {
|
||||
CLAY({ .clip = { .vertical = true, .childOffset = myData.scrollContainer.offset } }) {
|
||||
// Scrolling contents
|
||||
}
|
||||
```
|
||||
|
@ -839,7 +839,6 @@ Clay_TextElementConfig {
|
|||
CLAY_TEXT_WRAP_NEWLINES,
|
||||
CLAY_TEXT_WRAP_NONE,
|
||||
};
|
||||
bool hashStringContents
|
||||
};
|
||||
```
|
||||
|
||||
|
@ -899,14 +898,6 @@ Available options are:
|
|||
|
||||
---
|
||||
|
||||
**`.hashStringContents`**
|
||||
|
||||
`CLAY_TEXT_CONFIG(.hashStringContents = true)`
|
||||
|
||||
By default, clay will cache the dimensions of text measured by [the provided MeasureText function](#clay_setmeasuretextfunction) based on the string's pointer and length. Setting `.hashStringContents = true` will cause Clay to hash the entire string contents. Used to fix incorrect measurements caused by re-use of string memory, disabled by default as it will incur significant performance overhead for very large bodies of text.
|
||||
|
||||
---
|
||||
|
||||
**Examples**
|
||||
|
||||
```C
|
||||
|
@ -1062,6 +1053,7 @@ typedef struct {
|
|||
Clay_LayoutConfig layout;
|
||||
Clay_Color backgroundColor;
|
||||
Clay_CornerRadius cornerRadius;
|
||||
Clay_AspectRatioElementConfig aspectRatio;
|
||||
Clay_ImageElementConfig image;
|
||||
Clay_FloatingElementConfig floating;
|
||||
Clay_CustomElementConfig custom;
|
||||
|
@ -1108,9 +1100,17 @@ Note that the `CLAY_CORNER_RADIUS(radius)` function-like macro is available to p
|
|||
|
||||
---
|
||||
|
||||
**`.aspectRatio`** - `Clay_AspectRatioElementConfig`
|
||||
|
||||
`CLAY({ .aspectRatio = 1 })`
|
||||
|
||||
Uses [Clay_AspectRatioElementConfig](#clay_aspectratioelementconfig). Configures the element as an aspect ratio scaling element. Especially useful for rendering images, but can also be used to enforce a fixed width / height ratio of other elements.
|
||||
|
||||
---
|
||||
|
||||
**`.image`** - `Clay_ImageElementConfig`
|
||||
|
||||
`CLAY({ .image = { .imageData = &myImage, .sourceDimensions = { 640, 480 } } })`
|
||||
`CLAY({ .image = { .imageData = &myImage } })`
|
||||
|
||||
Uses [Clay_ImageElementConfig](#clay_imageelementconfig). Configures the element as an image element. Causes a render command with type `IMAGE` to be emitted.
|
||||
|
||||
|
@ -1294,23 +1294,12 @@ CLAY({ .id = CLAY_ID("Button"), .layout = { .layoutDirection = CLAY_TOP_TO_BOTTO
|
|||
|
||||
```C
|
||||
Clay_ImageElementConfig {
|
||||
Clay_Dimensions sourceDimensions {
|
||||
float width; float height;
|
||||
};
|
||||
void * imageData;
|
||||
};
|
||||
```
|
||||
|
||||
**Fields**
|
||||
|
||||
**`.sourceDimensions`** - `Clay_Dimensions`
|
||||
|
||||
`CLAY({ .image = { .sourceDimensions = { 1024, 768 } } }) {}`
|
||||
|
||||
Used to perform **aspect ratio scaling** on the image element. As of this version of clay, aspect ratio scaling only applies to the `height` of an image (i.e. image height will scale with width growth and limitations, but width will not scale with height growth and limitations)
|
||||
|
||||
---
|
||||
|
||||
**`.imageData`** - `void *`
|
||||
|
||||
`CLAY({ .image = { .imageData = &myImage } }) {}`
|
||||
|
@ -1321,7 +1310,7 @@ Used to perform **aspect ratio scaling** on the image element. As of this versio
|
|||
// Load an image somewhere in your code
|
||||
YourImage profilePicture = LoadYourImage("profilePicture.png");
|
||||
// Note that when rendering, .imageData will be void* type.
|
||||
CLAY({ .image = { .imageData = &profilePicture, .sourceDimensions = { 60, 60 } } }) {}
|
||||
CLAY({ .image = { .imageData = &profilePicture } }) {}
|
||||
```
|
||||
|
||||
**Examples**
|
||||
|
@ -1330,11 +1319,105 @@ CLAY({ .image = { .imageData = &profilePicture, .sourceDimensions = { 60, 60 } }
|
|||
// Load an image somewhere in your code
|
||||
YourImage profilePicture = LoadYourImage("profilePicture.png");
|
||||
// Declare a reusable image config
|
||||
Clay_ImageElementConfig imageConfig = (Clay_ImageElementConfig) { .imageData = &profilePicture, .sourceDimensions = {60, 60} };
|
||||
Clay_ImageElementConfig imageConfig = (Clay_ImageElementConfig) { .imageData = &profilePicture };
|
||||
// Declare an image element using a reusable config
|
||||
CLAY({ .image = imageConfig }) {}
|
||||
// Declare an image element using an inline config
|
||||
CLAY({ .image = { .imageData = &profilePicture, .sourceDimensions = {60, 60} } }) {}
|
||||
CLAY({ .image = { .imageData = &profilePicture }, .aspectRatio = 16.0 / 9.0 }) {}
|
||||
// Rendering example
|
||||
YourImage *imageToRender = renderCommand->elementConfig.imageElementConfig->imageData;
|
||||
```
|
||||
|
||||
**Rendering**
|
||||
|
||||
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->renderData.image->imageData` to retrieve image data referenced during layout creation. It's also up to the user to decide how / if they wish to blend `renderCommand->renderData.image->backgroundColor` with the image.
|
||||
|
||||
---
|
||||
|
||||
### Clay_AspectRatioElementConfig
|
||||
|
||||
**Usage**
|
||||
|
||||
`CLAY({ .aspectRatio = 16.0 / 9.0 }) {}`
|
||||
|
||||
**Clay_AspectRatioElementConfig** configures a clay element to enforce a fixed width / height ratio in its final dimensions. Mostly used for image elements, but can also be used for non image elements.
|
||||
|
||||
**Struct API (Pseudocode)**
|
||||
|
||||
```C
|
||||
Clay_AspectRatioElementConfig {
|
||||
float aspectRatio;
|
||||
};
|
||||
```
|
||||
|
||||
**Fields**
|
||||
|
||||
**`.aspectRatio`** - `float`
|
||||
|
||||
`CLAY({ .aspectRatio = { .aspectRatio = 16.0 / 9.0 } }) {}`
|
||||
|
||||
or alternatively, as C will automatically pass the value to the first nested struct field:
|
||||
|
||||
`CLAY({ .aspectRatio = 16.0 / 9.0 }) {}`
|
||||
|
||||
**Examples**
|
||||
|
||||
```C
|
||||
// Load an image somewhere in your code
|
||||
YourImage profilePicture = LoadYourImage("profilePicture.png");
|
||||
// Declare an image element that will grow along the X axis while maintaining its original aspect ratio
|
||||
CLAY({
|
||||
.layout = { .width = CLAY_SIZING_GROW() },
|
||||
.aspectRatio = profilePicture.width / profilePicture.height,
|
||||
.image = { .imageData = &profilePicture },
|
||||
}) {}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Clay_ImageElementConfig
|
||||
**Usage**
|
||||
|
||||
`CLAY({ .image = { ...image config } }) {}`
|
||||
|
||||
**Clay_ImageElementConfig** configures a clay element to render an image as its background.
|
||||
|
||||
**Struct API (Pseudocode)**
|
||||
|
||||
```C
|
||||
Clay_ImageElementConfig {
|
||||
void * imageData;
|
||||
};
|
||||
```
|
||||
|
||||
**Fields**
|
||||
|
||||
**`.imageData`** - `void *`
|
||||
|
||||
`CLAY({ .image = { .imageData = &myImage } }) {}`
|
||||
|
||||
`.imageData` is a generic void pointer that can be used to pass through image data to the renderer.
|
||||
|
||||
```C
|
||||
// Load an image somewhere in your code
|
||||
YourImage profilePicture = LoadYourImage("profilePicture.png");
|
||||
// Note that when rendering, .imageData will be void* type.
|
||||
CLAY({ .image = { .imageData = &profilePicture } }) {}
|
||||
```
|
||||
|
||||
Note: for an image to maintain its original aspect ratio when using dynamic scaling, the [.aspectRatio](#clay_aspectratioelementconfig) config option must be used.
|
||||
|
||||
**Examples**
|
||||
|
||||
```C
|
||||
// Load an image somewhere in your code
|
||||
YourImage profilePicture = LoadYourImage("profilePicture.png");
|
||||
// Declare a reusable image config
|
||||
Clay_ImageElementConfig imageConfig = (Clay_ImageElementConfig) { .imageData = &profilePicture };
|
||||
// Declare an image element using a reusable config
|
||||
CLAY({ .image = imageConfig }) {}
|
||||
// Declare an image element using an inline config
|
||||
CLAY({ .image = { .imageData = &profilePicture }, .aspectRatio = 16.0 / 9.0 }) {}
|
||||
// Rendering example
|
||||
YourImage *imageToRender = renderCommand->elementConfig.imageElementConfig->imageData;
|
||||
```
|
||||
|
@ -2020,7 +2103,6 @@ typedef struct {
|
|||
typedef struct {
|
||||
Clay_Color backgroundColor;
|
||||
Clay_CornerRadius cornerRadius;
|
||||
Clay_Dimensions sourceDimensions;
|
||||
void* imageData;
|
||||
} Clay_ImageRenderData;
|
||||
```
|
||||
|
|
|
@ -41,10 +41,10 @@ error_handler :: proc "c" (errorData: clay.ErrorData) {
|
|||
// Do something with the error data.
|
||||
}
|
||||
|
||||
min_memory_size: u32 = clay.MinMemorySize()
|
||||
min_memory_size := clay.MinMemorySize()
|
||||
memory := make([^]u8, min_memory_size)
|
||||
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(min_memory_size, memory)
|
||||
clay.Initialize(arena, { width = 1080, height = 720 }, { handler = error_handler })
|
||||
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(uint(min_memory_size), memory)
|
||||
clay.Initialize(arena, {1080, 720}, { handler = error_handler })
|
||||
```
|
||||
|
||||
3. Provide a `measure_text(text, config)` proc "c" with [clay.SetMeasureTextFunction(function)](https://github.com/nicbarker/clay/blob/main/README.md#clay_setmeasuretextfunction) so that Clay can measure and wrap text.
|
||||
|
@ -74,7 +74,7 @@ clay.SetMeasureTextFunction(measure_text, nil)
|
|||
```Odin
|
||||
// Update internal pointer position for handling mouseover / click / touch events
|
||||
clay.SetPointerState(
|
||||
clay.Vector2 { mouse_pos_x, mouse_pos_y },
|
||||
{ mouse_pos_x, mouse_pos_y },
|
||||
is_mouse_down,
|
||||
)
|
||||
```
|
||||
|
@ -148,6 +148,7 @@ create_layout :: proc() -> clay.ClayArray(clay.RenderCommand) {
|
|||
sizing = { width = clay.SizingFixed(60), height = clay.SizingFixed(60) },
|
||||
},
|
||||
image = {
|
||||
// How you define `profile_picture` depends on your renderer.
|
||||
imageData = &profile_picture,
|
||||
sourceDimensions = {
|
||||
width = 60,
|
||||
|
@ -179,8 +180,7 @@ create_layout :: proc() -> clay.ClayArray(clay.RenderCommand) {
|
|||
}
|
||||
|
||||
// Returns a list of render commands
|
||||
render_commands: clay.ClayArray(clay.RenderCommand) = clay.EndLayout()
|
||||
return render_commands
|
||||
return clay.EndLayout()
|
||||
}
|
||||
```
|
||||
|
||||
|
|
|
@ -113,9 +113,12 @@ TextElementConfig :: struct {
|
|||
textAlignment: TextAlignment,
|
||||
}
|
||||
|
||||
AspectRatioElementConfig :: struct {
|
||||
aspectRatio: f32,
|
||||
}
|
||||
|
||||
ImageElementConfig :: struct {
|
||||
imageData: rawptr,
|
||||
sourceDimensions: Dimensions,
|
||||
}
|
||||
|
||||
CustomElementConfig :: struct {
|
||||
|
@ -203,7 +206,6 @@ RectangleRenderData :: struct {
|
|||
ImageRenderData :: struct {
|
||||
backgroundColor: Color,
|
||||
cornerRadius: CornerRadius,
|
||||
sourceDimensions: Dimensions,
|
||||
imageData: rawptr,
|
||||
}
|
||||
|
||||
|
@ -340,6 +342,7 @@ ElementDeclaration :: struct {
|
|||
layout: LayoutConfig,
|
||||
backgroundColor: Color,
|
||||
cornerRadius: CornerRadius,
|
||||
aspectRatio: AspectRatioElementConfig,
|
||||
image: ImageElementConfig,
|
||||
floating: FloatingElementConfig,
|
||||
custom: CustomElementConfig,
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -72,7 +72,8 @@ LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Colo
|
|||
if clay.UI()({
|
||||
id = clay.ID("CheckImage", index),
|
||||
layout = { sizing = { width = clay.SizingFixed(32) } },
|
||||
image = { imageData = image, sourceDimensions = { 128, 128 } },
|
||||
aspectRatio = { 1.0 },
|
||||
image = { imageData = image },
|
||||
}) {}
|
||||
clay.Text(text, clay.TextConfig({fontSize = fontSize, fontId = fontId, textColor = color}))
|
||||
}
|
||||
|
@ -213,7 +214,8 @@ DeclarativeSyntaxPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizi
|
|||
if clay.UI()({
|
||||
id = clay.ID("SyntaxPageRightImageInner"),
|
||||
layout = { sizing = { width = clay.SizingGrow({ max = 568 }) } },
|
||||
image = { imageData = &syntaxImage, sourceDimensions = { 1136, 1194 } },
|
||||
aspectRatio = { 1136.0 / 1194.0 },
|
||||
image = { imageData = &syntaxImage },
|
||||
}) {}
|
||||
}
|
||||
}
|
||||
|
|
241
clay.h
241
clay.h
|
@ -1,4 +1,4 @@
|
|||
// VERSION: 0.13
|
||||
// VERSION: 0.14
|
||||
|
||||
/*
|
||||
NOTE: In order to use this library you must define
|
||||
|
@ -31,7 +31,8 @@
|
|||
#if !( \
|
||||
(defined(__cplusplus) && __cplusplus >= 202002L) || \
|
||||
(defined(__STDC__) && __STDC__ == 1 && defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || \
|
||||
defined(_MSC_VER) \
|
||||
defined(_MSC_VER) || \
|
||||
defined(__OBJC__) \
|
||||
)
|
||||
#error "Clay requires C99, C++20, or MSVC"
|
||||
#endif
|
||||
|
@ -184,7 +185,7 @@ extern "C" {
|
|||
|
||||
// Note: Clay_String is not guaranteed to be null terminated. It may be if created from a literal C string,
|
||||
// but it is also used to represent slices.
|
||||
typedef struct {
|
||||
typedef struct Clay_String {
|
||||
// Set this boolean to true if the char* data underlying this string will live for the entire lifetime of the program.
|
||||
// This will automatically be set for strings created with CLAY_STRING, as the macro requires a string literal.
|
||||
bool isStaticallyAllocated;
|
||||
|
@ -195,7 +196,7 @@ typedef struct {
|
|||
|
||||
// Clay_StringSlice is used to represent non owning string slices, and includes
|
||||
// a baseChars field which points to the string this slice is derived from.
|
||||
typedef struct {
|
||||
typedef struct Clay_StringSlice {
|
||||
int32_t length;
|
||||
const char *chars;
|
||||
const char *baseChars; // The source string / char* that this slice was derived from
|
||||
|
@ -205,33 +206,33 @@ typedef struct Clay_Context Clay_Context;
|
|||
|
||||
// Clay_Arena is a memory arena structure that is used by clay to manage its internal allocations.
|
||||
// Rather than creating it by hand, it's easier to use Clay_CreateArenaWithCapacityAndMemory()
|
||||
typedef struct {
|
||||
typedef struct Clay_Arena {
|
||||
uintptr_t nextAllocation;
|
||||
size_t capacity;
|
||||
char *memory;
|
||||
} Clay_Arena;
|
||||
|
||||
typedef struct {
|
||||
typedef struct Clay_Dimensions {
|
||||
float width, height;
|
||||
} Clay_Dimensions;
|
||||
|
||||
typedef struct {
|
||||
typedef struct Clay_Vector2 {
|
||||
float x, y;
|
||||
} Clay_Vector2;
|
||||
|
||||
// Internally clay conventionally represents colors as 0-255, but interpretation is up to the renderer.
|
||||
typedef struct {
|
||||
typedef struct Clay_Color {
|
||||
float r, g, b, a;
|
||||
} Clay_Color;
|
||||
|
||||
typedef struct {
|
||||
typedef struct Clay_BoundingBox {
|
||||
float x, y, width, height;
|
||||
} Clay_BoundingBox;
|
||||
|
||||
// Primarily created via the CLAY_ID(), CLAY_IDI(), CLAY_ID_LOCAL() and CLAY_IDI_LOCAL() macros.
|
||||
// Represents a hashed string ID used for identifying and finding specific clay UI elements, required
|
||||
// by functions such as Clay_PointerOver() and Clay_GetElementData().
|
||||
typedef struct {
|
||||
typedef struct Clay_ElementId {
|
||||
uint32_t id; // The resulting hash generated from the other fields.
|
||||
uint32_t offset; // A numerical offset applied after computing the hash from stringId.
|
||||
uint32_t baseId; // A base hash value to start from, for example the parent element ID is used when calculating CLAY_ID_LOCAL().
|
||||
|
@ -248,7 +249,7 @@ typedef struct
|
|||
|
||||
// Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
|
||||
// The rounding is determined by drawing a circle inset into the element corner by (radius, radius) pixels.
|
||||
typedef struct {
|
||||
typedef struct Clay_CornerRadius {
|
||||
float topLeft;
|
||||
float topRight;
|
||||
float bottomLeft;
|
||||
|
@ -298,20 +299,20 @@ typedef CLAY_PACKED_ENUM {
|
|||
} Clay__SizingType;
|
||||
|
||||
// Controls how child elements are aligned on each axis.
|
||||
typedef struct {
|
||||
typedef struct Clay_ChildAlignment {
|
||||
Clay_LayoutAlignmentX x; // Controls alignment of children along the x axis.
|
||||
Clay_LayoutAlignmentY y; // Controls alignment of children along the y axis.
|
||||
} Clay_ChildAlignment;
|
||||
|
||||
// Controls the minimum and maximum size in pixels that this element is allowed to grow or shrink to,
|
||||
// overriding sizing types such as FIT or GROW.
|
||||
typedef struct {
|
||||
typedef struct Clay_SizingMinMax {
|
||||
float min; // The smallest final size of the element on this axis will be this value in pixels.
|
||||
float max; // The largest final size of the element on this axis will be this value in pixels.
|
||||
} Clay_SizingMinMax;
|
||||
|
||||
// Controls the sizing of this element along one axis inside its parent container.
|
||||
typedef struct {
|
||||
typedef struct Clay_SizingAxis {
|
||||
union {
|
||||
Clay_SizingMinMax minMax; // Controls the minimum and maximum size in pixels that this element is allowed to grow or shrink to, overriding sizing types such as FIT or GROW.
|
||||
float percent; // Expects 0-1 range. Clamps the axis size to a percent of the parent container's axis size minus padding and child gaps.
|
||||
|
@ -320,14 +321,14 @@ typedef struct {
|
|||
} Clay_SizingAxis;
|
||||
|
||||
// Controls the sizing of this element along one axis inside its parent container.
|
||||
typedef struct {
|
||||
typedef struct Clay_Sizing {
|
||||
Clay_SizingAxis width; // Controls the width sizing of the element, along the x axis.
|
||||
Clay_SizingAxis height; // Controls the height sizing of the element, along the y axis.
|
||||
} Clay_Sizing;
|
||||
|
||||
// Controls "padding" in pixels, which is a gap between the bounding box of this element and where its children
|
||||
// will be placed.
|
||||
typedef struct {
|
||||
typedef struct Clay_Padding {
|
||||
uint16_t left;
|
||||
uint16_t right;
|
||||
uint16_t top;
|
||||
|
@ -338,7 +339,7 @@ CLAY__WRAPPER_STRUCT(Clay_Padding);
|
|||
|
||||
// Controls various settings that affect the size and position of an element, as well as the sizes and positions
|
||||
// of any child elements.
|
||||
typedef struct {
|
||||
typedef struct Clay_LayoutConfig {
|
||||
Clay_Sizing sizing; // Controls the sizing of this element inside it's parent container, including FIT, GROW, PERCENT and FIXED sizing.
|
||||
Clay_Padding padding; // Controls "padding" in pixels, which is a gap between the bounding box of this element and where its children will be placed.
|
||||
uint16_t childGap; // Controls the gap in pixels between child elements along the layout axis (horizontal gap for LEFT_TO_RIGHT, vertical gap for TOP_TO_BOTTOM).
|
||||
|
@ -371,7 +372,7 @@ typedef CLAY_PACKED_ENUM {
|
|||
} Clay_TextAlignment;
|
||||
|
||||
// Controls various functionality related to text elements.
|
||||
typedef struct {
|
||||
typedef struct Clay_TextElementConfig {
|
||||
// A pointer that will be transparently passed through to the resulting render command.
|
||||
void *userData;
|
||||
// The RGBA color of the font to render, conventionally specified as 0-255.
|
||||
|
@ -399,12 +400,20 @@ typedef struct {
|
|||
|
||||
CLAY__WRAPPER_STRUCT(Clay_TextElementConfig);
|
||||
|
||||
// Aspect Ratio --------------------------------
|
||||
|
||||
// Controls various settings related to aspect ratio scaling element.
|
||||
typedef struct Clay_AspectRatioElementConfig {
|
||||
float aspectRatio; // A float representing the target "Aspect ratio" for an element, which is its final width divided by its final height.
|
||||
} Clay_AspectRatioElementConfig;
|
||||
|
||||
CLAY__WRAPPER_STRUCT(Clay_AspectRatioElementConfig);
|
||||
|
||||
// Image --------------------------------
|
||||
|
||||
// Controls various settings related to image elements.
|
||||
typedef struct {
|
||||
typedef struct Clay_ImageElementConfig {
|
||||
void* imageData; // A transparent pointer used to pass image data through to the renderer.
|
||||
Clay_Dimensions sourceDimensions; // The original dimensions of the source image, used to control aspect ratio.
|
||||
} Clay_ImageElementConfig;
|
||||
|
||||
CLAY__WRAPPER_STRUCT(Clay_ImageElementConfig);
|
||||
|
@ -426,7 +435,7 @@ typedef CLAY_PACKED_ENUM {
|
|||
} Clay_FloatingAttachPointType;
|
||||
|
||||
// Controls where a floating element is offset relative to its parent element.
|
||||
typedef struct {
|
||||
typedef struct Clay_FloatingAttachPoints {
|
||||
Clay_FloatingAttachPointType element; // Controls the origin point on a floating element that attaches to its parent.
|
||||
Clay_FloatingAttachPointType parent; // Controls the origin point on the parent element that the floating element attaches to.
|
||||
} Clay_FloatingAttachPoints;
|
||||
|
@ -463,7 +472,7 @@ typedef CLAY_PACKED_ENUM {
|
|||
|
||||
// Controls various settings related to "floating" elements, which are elements that "float" above other elements, potentially overlapping their boundaries,
|
||||
// and not affecting the layout of sibling or parent elements.
|
||||
typedef struct {
|
||||
typedef struct Clay_FloatingElementConfig {
|
||||
// Offsets this floating element by the provided x,y coordinates from its attachPoints.
|
||||
Clay_Vector2 offset;
|
||||
// Expands the boundaries of the outer floating element without affecting its children.
|
||||
|
@ -500,7 +509,7 @@ CLAY__WRAPPER_STRUCT(Clay_FloatingElementConfig);
|
|||
// Custom -----------------------------
|
||||
|
||||
// Controls various settings related to custom elements.
|
||||
typedef struct {
|
||||
typedef struct Clay_CustomElementConfig {
|
||||
// A transparent pointer through which you can pass custom data to the renderer.
|
||||
// Generates CUSTOM render commands.
|
||||
void* customData;
|
||||
|
@ -511,7 +520,7 @@ CLAY__WRAPPER_STRUCT(Clay_CustomElementConfig);
|
|||
// Scroll -----------------------------
|
||||
|
||||
// Controls the axis on which an element switches to "scrolling", which clips the contents and allows scrolling in that direction.
|
||||
typedef struct {
|
||||
typedef struct Clay_ClipElementConfig {
|
||||
bool horizontal; // Clip overflowing elements on the X axis.
|
||||
bool vertical; // Clip overflowing elements on the Y axis.
|
||||
Clay_Vector2 childOffset; // Offsets the x,y positions of all child elements. Used primarily for scrolling containers.
|
||||
|
@ -522,7 +531,7 @@ CLAY__WRAPPER_STRUCT(Clay_ClipElementConfig);
|
|||
// Border -----------------------------
|
||||
|
||||
// Controls the widths of individual element borders.
|
||||
typedef struct {
|
||||
typedef struct Clay_BorderWidth {
|
||||
uint16_t left;
|
||||
uint16_t right;
|
||||
uint16_t top;
|
||||
|
@ -534,7 +543,7 @@ typedef struct {
|
|||
} Clay_BorderWidth;
|
||||
|
||||
// Controls settings related to element borders.
|
||||
typedef struct {
|
||||
typedef struct Clay_BorderElementConfig {
|
||||
Clay_Color color; // Controls the color of all borders with width > 0. Conventionally represented as 0-255, but interpretation is up to the renderer.
|
||||
Clay_BorderWidth width; // Controls the widths of individual borders. At least one of these should be > 0 for a BORDER render command to be generated.
|
||||
} Clay_BorderElementConfig;
|
||||
|
@ -544,7 +553,7 @@ CLAY__WRAPPER_STRUCT(Clay_BorderElementConfig);
|
|||
// Render Command Data -----------------------------
|
||||
|
||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT
|
||||
typedef struct {
|
||||
typedef struct Clay_TextRenderData {
|
||||
// A string slice containing the text to be rendered.
|
||||
// Note: this is not guaranteed to be null terminated.
|
||||
Clay_StringSlice stringContents;
|
||||
|
@ -560,7 +569,7 @@ typedef struct {
|
|||
} Clay_TextRenderData;
|
||||
|
||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_RECTANGLE
|
||||
typedef struct {
|
||||
typedef struct Clay_RectangleRenderData {
|
||||
// The solid background color to fill this rectangle with. Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
|
||||
Clay_Color backgroundColor;
|
||||
// Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
|
||||
|
@ -569,7 +578,7 @@ typedef struct {
|
|||
} Clay_RectangleRenderData;
|
||||
|
||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_IMAGE
|
||||
typedef struct {
|
||||
typedef struct Clay_ImageRenderData {
|
||||
// The tint color for this image. Note that the default value is 0,0,0,0 and should likely be interpreted
|
||||
// as "untinted".
|
||||
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
|
||||
|
@ -577,14 +586,12 @@ typedef struct {
|
|||
// Controls the "radius", or corner rounding of this image.
|
||||
// The rounding is determined by drawing a circle inset into the element corner by (radius, radius) pixels.
|
||||
Clay_CornerRadius cornerRadius;
|
||||
// The original dimensions of the source image, used to control aspect ratio.
|
||||
Clay_Dimensions sourceDimensions;
|
||||
// A pointer transparently passed through from the original element definition, typically used to represent image data.
|
||||
void* imageData;
|
||||
} Clay_ImageRenderData;
|
||||
|
||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_CUSTOM
|
||||
typedef struct {
|
||||
typedef struct Clay_CustomRenderData {
|
||||
// Passed through from .backgroundColor in the original element declaration.
|
||||
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
|
||||
Clay_Color backgroundColor;
|
||||
|
@ -596,13 +603,13 @@ typedef struct {
|
|||
} Clay_CustomRenderData;
|
||||
|
||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_START || commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_END
|
||||
typedef struct {
|
||||
typedef struct Clay_ScrollRenderData {
|
||||
bool horizontal;
|
||||
bool vertical;
|
||||
} Clay_ClipRenderData;
|
||||
|
||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_BORDER
|
||||
typedef struct {
|
||||
typedef struct Clay_BorderRenderData {
|
||||
// Controls a shared color for all this element's borders.
|
||||
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
|
||||
Clay_Color color;
|
||||
|
@ -614,7 +621,7 @@ typedef struct {
|
|||
} Clay_BorderRenderData;
|
||||
|
||||
// A struct union containing data specific to this command's .commandType
|
||||
typedef union {
|
||||
typedef union Clay_RenderData {
|
||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_RECTANGLE
|
||||
Clay_RectangleRenderData rectangle;
|
||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT
|
||||
|
@ -632,7 +639,7 @@ typedef union {
|
|||
// Miscellaneous Structs & Enums ---------------------------------
|
||||
|
||||
// Data representing the current internal state of a scrolling element.
|
||||
typedef struct {
|
||||
typedef struct Clay_ScrollContainerData {
|
||||
// Note: This is a pointer to the real internal scroll position, mutating it may cause a change in final layout.
|
||||
// Intended for use with external functionality that modifies scroll position, such as scroll bars or auto scrolling.
|
||||
Clay_Vector2 *scrollPosition;
|
||||
|
@ -647,7 +654,7 @@ typedef struct {
|
|||
} Clay_ScrollContainerData;
|
||||
|
||||
// Bounding box and other data for a specific UI element.
|
||||
typedef struct {
|
||||
typedef struct Clay_ElementData {
|
||||
// The rectangle that encloses this UI element, with the position relative to the root of the layout.
|
||||
Clay_BoundingBox boundingBox;
|
||||
// Indicates whether an actual Element matched the provided ID or if the default struct was returned.
|
||||
|
@ -674,7 +681,7 @@ typedef CLAY_PACKED_ENUM {
|
|||
CLAY_RENDER_COMMAND_TYPE_CUSTOM,
|
||||
} Clay_RenderCommandType;
|
||||
|
||||
typedef struct {
|
||||
typedef struct Clay_RenderCommand {
|
||||
// A rectangular box that fully encloses this UI element, with the position relative to the root of the layout.
|
||||
Clay_BoundingBox boundingBox;
|
||||
// A struct union containing data specific to this command's commandType.
|
||||
|
@ -699,7 +706,7 @@ typedef struct {
|
|||
} Clay_RenderCommand;
|
||||
|
||||
// A sized array of render commands.
|
||||
typedef struct {
|
||||
typedef struct Clay_RenderCommandArray {
|
||||
// The underlying max capacity of the array, not necessarily all initialized.
|
||||
int32_t capacity;
|
||||
// The number of initialized elements in this array. Used for loops and iteration.
|
||||
|
@ -721,7 +728,7 @@ typedef CLAY_PACKED_ENUM {
|
|||
} Clay_PointerDataInteractionState;
|
||||
|
||||
// Information on the current state of pointer interactions this frame.
|
||||
typedef struct {
|
||||
typedef struct Clay_PointerData {
|
||||
// The position of the mouse / touch / pointer relative to the root of the layout.
|
||||
Clay_Vector2 position;
|
||||
// Represents the current state of interaction with clay this frame.
|
||||
|
@ -732,7 +739,7 @@ typedef struct {
|
|||
Clay_PointerDataInteractionState state;
|
||||
} Clay_PointerData;
|
||||
|
||||
typedef struct {
|
||||
typedef struct Clay_ElementDeclaration {
|
||||
// Primarily created via the CLAY_ID(), CLAY_IDI(), CLAY_ID_LOCAL() and CLAY_IDI_LOCAL() macros.
|
||||
// Represents a hashed string ID used for identifying and finding specific clay UI elements, required by functions such as Clay_PointerOver() and Clay_GetElementData().
|
||||
Clay_ElementId id;
|
||||
|
@ -744,6 +751,8 @@ typedef struct {
|
|||
Clay_Color backgroundColor;
|
||||
// Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
|
||||
Clay_CornerRadius cornerRadius;
|
||||
// Controls settings related to aspect ratio scaling.
|
||||
Clay_AspectRatioElementConfig aspectRatio;
|
||||
// Controls settings related to image elements.
|
||||
Clay_ImageElementConfig image;
|
||||
// Controls whether and how an element "floats", which means it layers over the top of other elements in z order, and doesn't affect the position and size of siblings or parent elements.
|
||||
|
@ -783,7 +792,7 @@ typedef CLAY_PACKED_ENUM {
|
|||
} Clay_ErrorType;
|
||||
|
||||
// Data to identify the error that clay has encountered.
|
||||
typedef struct {
|
||||
typedef struct Clay_ErrorData {
|
||||
// Represents the type of error clay encountered while computing layout.
|
||||
// CLAY_ERROR_TYPE_TEXT_MEASUREMENT_FUNCTION_NOT_PROVIDED - A text measurement function wasn't provided using Clay_SetMeasureTextFunction(), or the provided function was null.
|
||||
// CLAY_ERROR_TYPE_ARENA_CAPACITY_EXCEEDED - Clay attempted to allocate its internal data structures but ran out of space. The arena passed to Clay_Initialize was created with a capacity smaller than that required by Clay_MinMemorySize().
|
||||
|
@ -1058,6 +1067,7 @@ CLAY__ARRAY_DEFINE(char, Clay__charArray)
|
|||
CLAY__ARRAY_DEFINE_FUNCTIONS(Clay_ElementId, Clay_ElementIdArray)
|
||||
CLAY__ARRAY_DEFINE(Clay_LayoutConfig, Clay__LayoutConfigArray)
|
||||
CLAY__ARRAY_DEFINE(Clay_TextElementConfig, Clay__TextElementConfigArray)
|
||||
CLAY__ARRAY_DEFINE(Clay_AspectRatioElementConfig, Clay__AspectRatioElementConfigArray)
|
||||
CLAY__ARRAY_DEFINE(Clay_ImageElementConfig, Clay__ImageElementConfigArray)
|
||||
CLAY__ARRAY_DEFINE(Clay_FloatingElementConfig, Clay__FloatingElementConfigArray)
|
||||
CLAY__ARRAY_DEFINE(Clay_CustomElementConfig, Clay__CustomElementConfigArray)
|
||||
|
@ -1072,6 +1082,7 @@ typedef CLAY_PACKED_ENUM {
|
|||
CLAY__ELEMENT_CONFIG_TYPE_BORDER,
|
||||
CLAY__ELEMENT_CONFIG_TYPE_FLOATING,
|
||||
CLAY__ELEMENT_CONFIG_TYPE_CLIP,
|
||||
CLAY__ELEMENT_CONFIG_TYPE_ASPECT,
|
||||
CLAY__ELEMENT_CONFIG_TYPE_IMAGE,
|
||||
CLAY__ELEMENT_CONFIG_TYPE_TEXT,
|
||||
CLAY__ELEMENT_CONFIG_TYPE_CUSTOM,
|
||||
|
@ -1080,6 +1091,7 @@ typedef CLAY_PACKED_ENUM {
|
|||
|
||||
typedef union {
|
||||
Clay_TextElementConfig *textElementConfig;
|
||||
Clay_AspectRatioElementConfig *aspectRatioElementConfig;
|
||||
Clay_ImageElementConfig *imageElementConfig;
|
||||
Clay_FloatingElementConfig *floatingElementConfig;
|
||||
Clay_CustomElementConfig *customElementConfig;
|
||||
|
@ -1236,13 +1248,14 @@ struct Clay_Context {
|
|||
Clay__int32_tArray layoutElementChildren;
|
||||
Clay__int32_tArray layoutElementChildrenBuffer;
|
||||
Clay__TextElementDataArray textElementData;
|
||||
Clay__int32_tArray imageElementPointers;
|
||||
Clay__int32_tArray aspectRatioElementIndexes;
|
||||
Clay__int32_tArray reusableElementIndexBuffer;
|
||||
Clay__int32_tArray layoutElementClipElementIds;
|
||||
// Configs
|
||||
Clay__LayoutConfigArray layoutConfigs;
|
||||
Clay__ElementConfigArray elementConfigs;
|
||||
Clay__TextElementConfigArray textElementConfigs;
|
||||
Clay__AspectRatioElementConfigArray aspectRatioElementConfigs;
|
||||
Clay__ImageElementConfigArray imageElementConfigs;
|
||||
Clay__FloatingElementConfigArray floatingElementConfigs;
|
||||
Clay__ClipElementConfigArray clipElementConfigs;
|
||||
|
@ -1271,15 +1284,12 @@ struct Clay_Context {
|
|||
|
||||
Clay_Context* Clay__Context_Allocate_Arena(Clay_Arena *arena) {
|
||||
size_t totalSizeBytes = sizeof(Clay_Context);
|
||||
uintptr_t memoryAddress = (uintptr_t)arena->memory;
|
||||
// Make sure the memory address passed in for clay to use is cache line aligned
|
||||
uintptr_t nextAllocOffset = (memoryAddress % 64);
|
||||
if (nextAllocOffset + totalSizeBytes > arena->capacity)
|
||||
if (totalSizeBytes > arena->capacity)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
arena->nextAllocation = nextAllocOffset + totalSizeBytes;
|
||||
return (Clay_Context*)(memoryAddress + nextAllocOffset);
|
||||
arena->nextAllocation += totalSizeBytes;
|
||||
return (Clay_Context*)(arena->memory);
|
||||
}
|
||||
|
||||
Clay_String Clay__WriteStringToCharBuffer(Clay__charArray *buffer, Clay_String string) {
|
||||
|
@ -1310,6 +1320,7 @@ uint32_t Clay__GetParentElementId(void) {
|
|||
|
||||
Clay_LayoutConfig * Clay__StoreLayoutConfig(Clay_LayoutConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &CLAY_LAYOUT_DEFAULT : Clay__LayoutConfigArray_Add(&Clay_GetCurrentContext()->layoutConfigs, config); }
|
||||
Clay_TextElementConfig * Clay__StoreTextElementConfig(Clay_TextElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_TextElementConfig_DEFAULT : Clay__TextElementConfigArray_Add(&Clay_GetCurrentContext()->textElementConfigs, config); }
|
||||
Clay_AspectRatioElementConfig * Clay__StoreAspectRatioElementConfig(Clay_AspectRatioElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_AspectRatioElementConfig_DEFAULT : Clay__AspectRatioElementConfigArray_Add(&Clay_GetCurrentContext()->aspectRatioElementConfigs, config); }
|
||||
Clay_ImageElementConfig * Clay__StoreImageElementConfig(Clay_ImageElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_ImageElementConfig_DEFAULT : Clay__ImageElementConfigArray_Add(&Clay_GetCurrentContext()->imageElementConfigs, config); }
|
||||
Clay_FloatingElementConfig * Clay__StoreFloatingElementConfig(Clay_FloatingElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_FloatingElementConfig_DEFAULT : Clay__FloatingElementConfigArray_Add(&Clay_GetCurrentContext()->floatingElementConfigs, config); }
|
||||
Clay_CustomElementConfig * Clay__StoreCustomElementConfig(Clay_CustomElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_CustomElementConfig_DEFAULT : Clay__CustomElementConfigArray_Add(&Clay_GetCurrentContext()->customElementConfigs, config); }
|
||||
|
@ -1483,7 +1494,7 @@ uint64_t Clay__HashData(const uint8_t* data, size_t length) {
|
|||
uint64_t Clay__HashData(const uint8_t* data, size_t length) {
|
||||
uint64_t hash = 0;
|
||||
|
||||
for (int32_t i = 0; i < length; i++) {
|
||||
for (size_t i = 0; i < length; i++) {
|
||||
hash += data[i];
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
|
@ -1632,7 +1643,10 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
|
|||
char current = text->chars[end];
|
||||
if (current == ' ' || current == '\n') {
|
||||
int32_t length = end - start;
|
||||
Clay_Dimensions dimensions = Clay__MeasureText(CLAY__INIT(Clay_StringSlice) { .length = length, .chars = &text->chars[start], .baseChars = text->chars }, config, context->measureTextUserData);
|
||||
Clay_Dimensions dimensions = {};
|
||||
if (length > 0) {
|
||||
dimensions = Clay__MeasureText(CLAY__INIT(Clay_StringSlice) {.length = length, .chars = &text->chars[start], .baseChars = text->chars}, config, context->measureTextUserData);
|
||||
}
|
||||
measured->minWidth = CLAY__MAX(dimensions.width, measured->minWidth);
|
||||
measuredHeight = CLAY__MAX(measuredHeight, dimensions.height);
|
||||
if (current == ' ') {
|
||||
|
@ -1661,7 +1675,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
|
|||
measuredHeight = CLAY__MAX(measuredHeight, dimensions.height);
|
||||
measured->minWidth = CLAY__MAX(dimensions.width, measured->minWidth);
|
||||
}
|
||||
measuredWidth = CLAY__MAX(lineWidth, measuredWidth);
|
||||
measuredWidth = CLAY__MAX(lineWidth, measuredWidth) - config->letterSpacing;
|
||||
|
||||
measured->measuredWordsStartIndex = tempWord.next;
|
||||
measured->unwrappedDimensions.width = measuredWidth;
|
||||
|
@ -1760,16 +1774,15 @@ bool Clay__ElementHasConfig(Clay_LayoutElement *layoutElement, Clay__ElementConf
|
|||
void Clay__UpdateAspectRatioBox(Clay_LayoutElement *layoutElement) {
|
||||
for (int32_t j = 0; j < layoutElement->elementConfigs.length; j++) {
|
||||
Clay_ElementConfig *config = Clay__ElementConfigArraySlice_Get(&layoutElement->elementConfigs, j);
|
||||
if (config->type == CLAY__ELEMENT_CONFIG_TYPE_IMAGE) {
|
||||
Clay_ImageElementConfig *imageConfig = config->config.imageElementConfig;
|
||||
if (imageConfig->sourceDimensions.width == 0 || imageConfig->sourceDimensions.height == 0) {
|
||||
if (config->type == CLAY__ELEMENT_CONFIG_TYPE_ASPECT) {
|
||||
Clay_AspectRatioElementConfig *aspectConfig = config->config.aspectRatioElementConfig;
|
||||
if (aspectConfig->aspectRatio == 0) {
|
||||
break;
|
||||
}
|
||||
float aspect = imageConfig->sourceDimensions.width / imageConfig->sourceDimensions.height;
|
||||
if (layoutElement->dimensions.width == 0 && layoutElement->dimensions.height != 0) {
|
||||
layoutElement->dimensions.width = layoutElement->dimensions.height * aspect;
|
||||
layoutElement->dimensions.width = layoutElement->dimensions.height * aspectConfig->aspectRatio;
|
||||
} else if (layoutElement->dimensions.width != 0 && layoutElement->dimensions.height == 0) {
|
||||
layoutElement->dimensions.height = layoutElement->dimensions.height * (1 / aspect);
|
||||
layoutElement->dimensions.height = layoutElement->dimensions.width * (1 / aspectConfig->aspectRatio);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -1783,13 +1796,13 @@ void Clay__CloseElement(void) {
|
|||
}
|
||||
Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement();
|
||||
Clay_LayoutConfig *layoutConfig = openLayoutElement->layoutConfig;
|
||||
bool elementHasScrollHorizontal = false;
|
||||
bool elementHasScrollVertical = false;
|
||||
bool elementHasClipHorizontal = false;
|
||||
bool elementHasClipVertical = false;
|
||||
for (int32_t i = 0; i < openLayoutElement->elementConfigs.length; i++) {
|
||||
Clay_ElementConfig *config = Clay__ElementConfigArraySlice_Get(&openLayoutElement->elementConfigs, i);
|
||||
if (config->type == CLAY__ELEMENT_CONFIG_TYPE_CLIP) {
|
||||
elementHasScrollHorizontal = config->config.clipElementConfig->horizontal;
|
||||
elementHasScrollVertical = config->config.clipElementConfig->vertical;
|
||||
elementHasClipHorizontal = config->config.clipElementConfig->horizontal;
|
||||
elementHasClipVertical = config->config.clipElementConfig->vertical;
|
||||
context->openClipElementStack.length--;
|
||||
break;
|
||||
} else if (config->type == CLAY__ELEMENT_CONFIG_TYPE_FLOATING) {
|
||||
|
@ -1810,19 +1823,21 @@ void Clay__CloseElement(void) {
|
|||
Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, childIndex);
|
||||
openLayoutElement->dimensions.width += child->dimensions.width;
|
||||
openLayoutElement->dimensions.height = CLAY__MAX(openLayoutElement->dimensions.height, child->dimensions.height + topBottomPadding);
|
||||
// Minimum size of child elements doesn't matter to scroll containers as they can shrink and hide their contents
|
||||
if (!elementHasScrollHorizontal) {
|
||||
// Minimum size of child elements doesn't matter to clip containers as they can shrink and hide their contents
|
||||
if (!elementHasClipHorizontal) {
|
||||
openLayoutElement->minDimensions.width += child->minDimensions.width;
|
||||
}
|
||||
if (!elementHasScrollVertical) {
|
||||
if (!elementHasClipVertical) {
|
||||
openLayoutElement->minDimensions.height = CLAY__MAX(openLayoutElement->minDimensions.height, child->minDimensions.height + topBottomPadding);
|
||||
}
|
||||
Clay__int32_tArray_Add(&context->layoutElementChildren, childIndex);
|
||||
}
|
||||
float childGap = (float)(CLAY__MAX(openLayoutElement->childrenOrTextContent.children.length - 1, 0) * layoutConfig->childGap);
|
||||
openLayoutElement->dimensions.width += childGap; // TODO this is technically a bug with childgap and scroll containers
|
||||
openLayoutElement->dimensions.width += childGap;
|
||||
if (!elementHasClipHorizontal) {
|
||||
openLayoutElement->minDimensions.width += childGap;
|
||||
}
|
||||
}
|
||||
else if (layoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM) {
|
||||
openLayoutElement->dimensions.height = topBottomPadding;
|
||||
openLayoutElement->minDimensions.height = topBottomPadding;
|
||||
|
@ -1831,19 +1846,21 @@ void Clay__CloseElement(void) {
|
|||
Clay_LayoutElement *child = Clay_LayoutElementArray_Get(&context->layoutElements, childIndex);
|
||||
openLayoutElement->dimensions.height += child->dimensions.height;
|
||||
openLayoutElement->dimensions.width = CLAY__MAX(openLayoutElement->dimensions.width, child->dimensions.width + leftRightPadding);
|
||||
// Minimum size of child elements doesn't matter to scroll containers as they can shrink and hide their contents
|
||||
if (!elementHasScrollVertical) {
|
||||
// Minimum size of child elements doesn't matter to clip containers as they can shrink and hide their contents
|
||||
if (!elementHasClipVertical) {
|
||||
openLayoutElement->minDimensions.height += child->minDimensions.height;
|
||||
}
|
||||
if (!elementHasScrollHorizontal) {
|
||||
if (!elementHasClipHorizontal) {
|
||||
openLayoutElement->minDimensions.width = CLAY__MAX(openLayoutElement->minDimensions.width, child->minDimensions.width + leftRightPadding);
|
||||
}
|
||||
Clay__int32_tArray_Add(&context->layoutElementChildren, childIndex);
|
||||
}
|
||||
float childGap = (float)(CLAY__MAX(openLayoutElement->childrenOrTextContent.children.length - 1, 0) * layoutConfig->childGap);
|
||||
openLayoutElement->dimensions.height += childGap; // TODO this is technically a bug with childgap and scroll containers
|
||||
openLayoutElement->dimensions.height += childGap;
|
||||
if (!elementHasClipVertical) {
|
||||
openLayoutElement->minDimensions.height += childGap;
|
||||
}
|
||||
}
|
||||
|
||||
context->layoutElementChildrenBuffer.length -= openLayoutElement->childrenOrTextContent.children.length;
|
||||
|
||||
|
@ -2048,7 +2065,10 @@ void Clay__ConfigureOpenElementPtr(const Clay_ElementDeclaration *declaration) {
|
|||
}
|
||||
if (declaration->image.imageData) {
|
||||
Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .imageElementConfig = Clay__StoreImageElementConfig(declaration->image) }, CLAY__ELEMENT_CONFIG_TYPE_IMAGE);
|
||||
Clay__int32_tArray_Add(&context->imageElementPointers, context->layoutElements.length - 1);
|
||||
}
|
||||
if (declaration->aspectRatio.aspectRatio > 0) {
|
||||
Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .aspectRatioElementConfig = Clay__StoreAspectRatioElementConfig(declaration->aspectRatio) }, CLAY__ELEMENT_CONFIG_TYPE_ASPECT);
|
||||
Clay__int32_tArray_Add(&context->aspectRatioElementIndexes, context->layoutElements.length - 1);
|
||||
}
|
||||
if (declaration->floating.attachTo != CLAY_ATTACH_TO_NONE) {
|
||||
Clay_FloatingElementConfig floatingConfig = declaration->floating;
|
||||
|
@ -2145,6 +2165,7 @@ void Clay__InitializeEphemeralMemory(Clay_Context* context) {
|
|||
context->layoutConfigs = Clay__LayoutConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->elementConfigs = Clay__ElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->textElementConfigs = Clay__TextElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->aspectRatioElementConfigs = Clay__AspectRatioElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->imageElementConfigs = Clay__ImageElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->floatingElementConfigs = Clay__FloatingElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->clipElementConfigs = Clay__ClipElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||
|
@ -2159,7 +2180,7 @@ void Clay__InitializeEphemeralMemory(Clay_Context* context) {
|
|||
context->layoutElementChildren = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->openLayoutElementStack = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->textElementData = Clay__TextElementDataArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->imageElementPointers = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->aspectRatioElementIndexes = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->renderCommands = Clay_RenderCommandArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->treeNodeVisited = Clay__boolArray_Allocate_Arena(maxElementCount, arena);
|
||||
context->treeNodeVisited.length = context->treeNodeVisited.capacity; // This array is accessed directly rather than behaving as a list
|
||||
|
@ -2248,7 +2269,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
|||
if (childSizing.type != CLAY__SIZING_TYPE_PERCENT
|
||||
&& childSizing.type != CLAY__SIZING_TYPE_FIXED
|
||||
&& (!Clay__ElementHasConfig(childElement, CLAY__ELEMENT_CONFIG_TYPE_TEXT) || (Clay__FindElementConfigWithType(childElement, CLAY__ELEMENT_CONFIG_TYPE_TEXT).textElementConfig->wrapMode == CLAY_TEXT_WRAP_WORDS)) // todo too many loops
|
||||
&& (xAxis || !Clay__ElementHasConfig(childElement, CLAY__ELEMENT_CONFIG_TYPE_IMAGE))
|
||||
// && (xAxis || !Clay__ElementHasConfig(childElement, CLAY__ELEMENT_CONFIG_TYPE_ASPECT))
|
||||
) {
|
||||
Clay__int32_tArray_Add(&resizableContainerBuffer, childElementIndex);
|
||||
}
|
||||
|
@ -2287,9 +2308,9 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
|||
// The content is too large, compress the children as much as possible
|
||||
if (sizeToDistribute < 0) {
|
||||
// If the parent clips content in this axis direction, don't compress children, just leave them alone
|
||||
Clay_ClipElementConfig *scrollElementConfig = Clay__FindElementConfigWithType(parent, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig;
|
||||
if (scrollElementConfig) {
|
||||
if (((xAxis && scrollElementConfig->horizontal) || (!xAxis && scrollElementConfig->vertical))) {
|
||||
Clay_ClipElementConfig *clipElementConfig = Clay__FindElementConfigWithType(parent, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig;
|
||||
if (clipElementConfig) {
|
||||
if (((xAxis && clipElementConfig->horizontal) || (!xAxis && clipElementConfig->vertical))) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
@ -2382,10 +2403,6 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
|||
float minSize = xAxis ? childElement->minDimensions.width : childElement->minDimensions.height;
|
||||
float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.height;
|
||||
|
||||
if (!xAxis && Clay__ElementHasConfig(childElement, CLAY__ELEMENT_CONFIG_TYPE_IMAGE)) {
|
||||
continue; // Currently we don't support resizing aspect ratio images on the Y axis because it would break the ratio
|
||||
}
|
||||
|
||||
float maxSize = parentSize - parentPadding;
|
||||
// If we're laying out the children of a scroll panel, grow containers expand to the size of the inner content, not the outer container
|
||||
if (Clay__ElementHasConfig(parent, CLAY__ELEMENT_CONFIG_TYPE_CLIP)) {
|
||||
|
@ -2500,7 +2517,7 @@ void Clay__CalculateFinalLayout(void) {
|
|||
// measuredWord->length == 0 means a newline character
|
||||
else if (measuredWord->length == 0 || lineWidth + measuredWord->width > containerElement->dimensions.width) {
|
||||
// Wrapped text lines list has overflowed, just render out the line
|
||||
bool finalCharIsSpace = textElementData->text.chars[lineStartOffset + lineLengthChars - 1] == ' ';
|
||||
bool finalCharIsSpace = textElementData->text.chars[CLAY__MAX(lineStartOffset + lineLengthChars - 1, 0)] == ' ';
|
||||
Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { lineWidth + (finalCharIsSpace ? -spaceWidth : 0), lineHeight }, { .length = lineLengthChars + (finalCharIsSpace ? -1 : 0), .chars = &textElementData->text.chars[lineStartOffset] } });
|
||||
textElementData->wrappedLines.length++;
|
||||
if (lineLengthChars == 0 || measuredWord->length == 0) {
|
||||
|
@ -2510,26 +2527,27 @@ void Clay__CalculateFinalLayout(void) {
|
|||
lineLengthChars = 0;
|
||||
lineStartOffset = measuredWord->startOffset;
|
||||
} else {
|
||||
lineWidth += measuredWord->width;
|
||||
lineWidth += measuredWord->width + textConfig->letterSpacing;
|
||||
lineLengthChars += measuredWord->length;
|
||||
wordIndex = measuredWord->next;
|
||||
}
|
||||
}
|
||||
if (lineLengthChars > 0) {
|
||||
Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { lineWidth, lineHeight }, {.length = lineLengthChars, .chars = &textElementData->text.chars[lineStartOffset] } });
|
||||
Clay__WrappedTextLineArray_Add(&context->wrappedTextLines, CLAY__INIT(Clay__WrappedTextLine) { { lineWidth - textConfig->letterSpacing, lineHeight }, {.length = lineLengthChars, .chars = &textElementData->text.chars[lineStartOffset] } });
|
||||
textElementData->wrappedLines.length++;
|
||||
}
|
||||
containerElement->dimensions.height = lineHeight * (float)textElementData->wrappedLines.length;
|
||||
}
|
||||
|
||||
// Scale vertical image heights according to aspect ratio
|
||||
for (int32_t i = 0; i < context->imageElementPointers.length; ++i) {
|
||||
Clay_LayoutElement* imageElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&context->imageElementPointers, i));
|
||||
Clay_ImageElementConfig *config = Clay__FindElementConfigWithType(imageElement, CLAY__ELEMENT_CONFIG_TYPE_IMAGE).imageElementConfig;
|
||||
imageElement->dimensions.height = (config->sourceDimensions.height / CLAY__MAX(config->sourceDimensions.width, 1)) * imageElement->dimensions.width;
|
||||
// Scale vertical heights according to aspect ratio
|
||||
for (int32_t i = 0; i < context->aspectRatioElementIndexes.length; ++i) {
|
||||
Clay_LayoutElement* aspectElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&context->aspectRatioElementIndexes, i));
|
||||
Clay_AspectRatioElementConfig *config = Clay__FindElementConfigWithType(aspectElement, CLAY__ELEMENT_CONFIG_TYPE_ASPECT).aspectRatioElementConfig;
|
||||
aspectElement->dimensions.height = (1 / config->aspectRatio) * aspectElement->dimensions.width;
|
||||
aspectElement->layoutConfig->sizing.height.size.minMax.max = aspectElement->dimensions.height;
|
||||
}
|
||||
|
||||
// Propagate effect of text wrapping, image aspect scaling etc. on height of parents
|
||||
// Propagate effect of text wrapping, aspect scaling etc. on height of parents
|
||||
Clay__LayoutElementTreeNodeArray dfsBuffer = context->layoutElementTreeNodeArray1;
|
||||
dfsBuffer.length = 0;
|
||||
for (int32_t i = 0; i < context->layoutElementTreeRoots.length; ++i) {
|
||||
|
@ -2580,6 +2598,13 @@ void Clay__CalculateFinalLayout(void) {
|
|||
// Calculate sizing along the Y axis
|
||||
Clay__SizeContainersAlongAxis(false);
|
||||
|
||||
// Scale horizontal widths according to aspect ratio
|
||||
for (int32_t i = 0; i < context->aspectRatioElementIndexes.length; ++i) {
|
||||
Clay_LayoutElement* aspectElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&context->aspectRatioElementIndexes, i));
|
||||
Clay_AspectRatioElementConfig *config = Clay__FindElementConfigWithType(aspectElement, CLAY__ELEMENT_CONFIG_TYPE_ASPECT).aspectRatioElementConfig;
|
||||
aspectElement->dimensions.width = config->aspectRatio * aspectElement->dimensions.height;
|
||||
}
|
||||
|
||||
// Sort tree roots by z-index
|
||||
int32_t sortMax = context->layoutElementTreeRoots.length - 1;
|
||||
while (sortMax > 0) { // todo dumb bubble sort
|
||||
|
@ -2670,7 +2695,6 @@ void Clay__CalculateFinalLayout(void) {
|
|||
if (clipConfig->vertical) {
|
||||
rootPosition.y += clipConfig->childOffset.y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
|
||||
.boundingBox = clipHashMapItem->boundingBox,
|
||||
|
@ -2776,6 +2800,7 @@ void Clay__CalculateFinalLayout(void) {
|
|||
// Culling - Don't bother to generate render commands for rectangles entirely outside the screen - this won't stop their children from being rendered if they overflow
|
||||
bool shouldRender = !offscreen;
|
||||
switch (elementConfig->type) {
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_ASPECT:
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_FLOATING:
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_SHARED:
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_BORDER: {
|
||||
|
@ -2798,7 +2823,6 @@ void Clay__CalculateFinalLayout(void) {
|
|||
.image = {
|
||||
.backgroundColor = sharedConfig->backgroundColor,
|
||||
.cornerRadius = sharedConfig->cornerRadius,
|
||||
.sourceDimensions = elementConfig->config.imageElementConfig->sourceDimensions,
|
||||
.imageData = elementConfig->config.imageElementConfig->imageData,
|
||||
}
|
||||
};
|
||||
|
@ -2907,6 +2931,7 @@ void Clay__CalculateFinalLayout(void) {
|
|||
default: break;
|
||||
}
|
||||
currentElementTreeNode->nextChildOffset.x += extraSpace;
|
||||
extraSpace = CLAY__MAX(0, extraSpace);
|
||||
} else {
|
||||
for (int32_t i = 0; i < currentElement->childrenOrTextContent.children.length; ++i) {
|
||||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->childrenOrTextContent.children.elements[i]);
|
||||
|
@ -2920,6 +2945,7 @@ void Clay__CalculateFinalLayout(void) {
|
|||
case CLAY_ALIGN_Y_CENTER: extraSpace /= 2; break;
|
||||
default: break;
|
||||
}
|
||||
extraSpace = CLAY__MAX(0, extraSpace);
|
||||
currentElementTreeNode->nextChildOffset.y += extraSpace;
|
||||
}
|
||||
|
||||
|
@ -3097,6 +3123,7 @@ Clay__DebugElementConfigTypeLabelConfig Clay__DebugGetElementConfigTypeLabel(Cla
|
|||
switch (type) {
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_SHARED: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Shared"), {243,134,48,255} };
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_TEXT: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Text"), {105,210,231,255} };
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_ASPECT: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Aspect"), {101,149,194,255} };
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_IMAGE: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Image"), {121,189,154,255} };
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_FLOATING: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Floating"), {250,105,0,255} };
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_CLIP: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) {CLAY_STRING("Scroll"), {242, 196, 90, 255} };
|
||||
|
@ -3581,21 +3608,25 @@ void Clay__RenderDebugView(void) {
|
|||
}
|
||||
break;
|
||||
}
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_ASPECT: {
|
||||
Clay_AspectRatioElementConfig *aspectRatioConfig = elementConfig->config.aspectRatioElementConfig;
|
||||
CLAY({ .id = CLAY_ID("Clay__DebugViewElementInfoAspectRatioBody"), .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
|
||||
CLAY_TEXT(CLAY_STRING("Aspect Ratio"), infoTitleConfig);
|
||||
// Aspect Ratio
|
||||
CLAY_TEXT(Clay__IntToString(aspectRatioConfig->aspectRatio), infoTextConfig);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLAY__ELEMENT_CONFIG_TYPE_IMAGE: {
|
||||
Clay_ImageElementConfig *imageConfig = elementConfig->config.imageElementConfig;
|
||||
CLAY({ .id = CLAY_ID("Clay__DebugViewElementInfoImageBody"), .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
|
||||
// .sourceDimensions
|
||||
CLAY_TEXT(CLAY_STRING("Source Dimensions"), infoTitleConfig);
|
||||
CLAY({ .id = CLAY_ID("Clay__DebugViewElementInfoImageDimensions") }) {
|
||||
CLAY_TEXT(CLAY_STRING("{ width: "), infoTextConfig);
|
||||
CLAY_TEXT(Clay__IntToString(imageConfig->sourceDimensions.width), infoTextConfig);
|
||||
CLAY_TEXT(CLAY_STRING(", height: "), infoTextConfig);
|
||||
CLAY_TEXT(Clay__IntToString(imageConfig->sourceDimensions.height), infoTextConfig);
|
||||
CLAY_TEXT(CLAY_STRING(" }"), infoTextConfig);
|
||||
Clay_AspectRatioElementConfig aspectConfig = { 1 };
|
||||
if (Clay__ElementHasConfig(selectedItem->layoutElement, CLAY__ELEMENT_CONFIG_TYPE_ASPECT)) {
|
||||
aspectConfig = *Clay__FindElementConfigWithType(selectedItem->layoutElement, CLAY__ELEMENT_CONFIG_TYPE_ASPECT).aspectRatioElementConfig;
|
||||
}
|
||||
CLAY({ .id = CLAY_ID("Clay__DebugViewElementInfoImageBody"), .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) {
|
||||
// Image Preview
|
||||
CLAY_TEXT(CLAY_STRING("Preview"), infoTitleConfig);
|
||||
CLAY({ .layout = { .sizing = { .width = CLAY_SIZING_GROW(0, imageConfig->sourceDimensions.width) }}, .image = *imageConfig }) {}
|
||||
CLAY({ .layout = { .sizing = { .width = CLAY_SIZING_GROW(64, 128), .height = CLAY_SIZING_GROW(64, 128) }}, .aspectRatio = aspectConfig, .image = *imageConfig }) {}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -3793,7 +3824,7 @@ Clay__Warning *Clay__WarningArray_Add(Clay__WarningArray *array, Clay__Warning i
|
|||
void* Clay__Array_Allocate_Arena(int32_t capacity, uint32_t itemSize, Clay_Arena *arena)
|
||||
{
|
||||
size_t totalSizeBytes = capacity * itemSize;
|
||||
uintptr_t nextAllocOffset = arena->nextAllocation + (64 - (arena->nextAllocation % 64));
|
||||
uintptr_t nextAllocOffset = arena->nextAllocation + ((64 - (arena->nextAllocation % 64)) & 63);
|
||||
if (nextAllocOffset + totalSizeBytes <= arena->capacity) {
|
||||
arena->nextAllocation = nextAllocOffset + totalSizeBytes;
|
||||
return (void*)((uintptr_t)arena->memory + (uintptr_t)nextAllocOffset);
|
||||
|
@ -3913,7 +3944,7 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
|
|||
Clay_BoundingBox elementBox = mapItem->boundingBox;
|
||||
elementBox.x -= root->pointerOffset.x;
|
||||
elementBox.y -= root->pointerOffset.y;
|
||||
if ((Clay__PointIsInsideRect(position, elementBox)) && (clipElementId == 0 || (Clay__PointIsInsideRect(position, clipItem->boundingBox)))) {
|
||||
if ((Clay__PointIsInsideRect(position, elementBox)) && (clipElementId == 0 || (Clay__PointIsInsideRect(position, clipItem->boundingBox)) || context->externalScrollHandlingEnabled)) {
|
||||
if (mapItem->onHoverFunction) {
|
||||
mapItem->onHoverFunction(mapItem->elementId, context->pointerInfo, mapItem->hoverFunctionUserData);
|
||||
}
|
||||
|
@ -3961,6 +3992,10 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
|
|||
|
||||
CLAY_WASM_EXPORT("Clay_Initialize")
|
||||
Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler) {
|
||||
// Cacheline align memory passed in
|
||||
uintptr_t baseOffset = 64 - ((uintptr_t)arena.memory % 64);
|
||||
baseOffset = baseOffset == 64 ? 0 : baseOffset;
|
||||
arena.memory += baseOffset;
|
||||
Clay_Context *context = Clay__Context_Allocate_Arena(&arena);
|
||||
if (context == NULL) return NULL;
|
||||
// DEFAULTS
|
||||
|
|
|
@ -55,4 +55,5 @@ add_custom_command(
|
|||
TARGET SDL2_video_demo POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources
|
||||
${CMAKE_CURRENT_BINARY_DIR}/resources)
|
||||
${CMAKE_CURRENT_BINARY_DIR}/resources
|
||||
)
|
||||
|
|
|
@ -26,7 +26,7 @@ set_property(DIRECTORY "${sdl_SOURCE_DIR}" PROPERTY EXCLUDE_FROM_ALL TRUE)
|
|||
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_TAG release-3.2.2
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
)
|
||||
|
@ -38,7 +38,7 @@ set_property(DIRECTORY "${sdl_ttf_SOURCE_DIR}" PROPERTY EXCLUDE_FROM_ALL TRUE)
|
|||
FetchContent_Declare(
|
||||
SDL_image
|
||||
GIT_REPOSITORY "https://github.com/libsdl-org/SDL_image.git"
|
||||
GIT_TAG release-3.2.0 # Slightly risky to use main branch, but it's the only one available
|
||||
GIT_TAG release-3.2.0
|
||||
GIT_SHALLOW TRUE
|
||||
GIT_PROGRESS TRUE
|
||||
)
|
||||
|
|
|
@ -32,6 +32,7 @@ static inline Clay_Dimensions SDL_MeasureText(Clay_StringSlice text, Clay_TextEl
|
|||
TTF_Font *font = fonts[config->fontId];
|
||||
int width, height;
|
||||
|
||||
TTF_SetFontSize(font, config->fontSize);
|
||||
if (!TTF_GetStringSize(font, text.chars, text.length, &width, &height)) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_ERROR, "Failed to measure text: %s", SDL_GetError());
|
||||
}
|
||||
|
@ -65,12 +66,9 @@ Clay_RenderCommandArray ClayImageSample_CreateLayout() {
|
|||
.layout = {
|
||||
.sizing = layoutExpand
|
||||
},
|
||||
.aspectRatio = { 23.0 / 42.0 },
|
||||
.image = {
|
||||
.imageData = sample_image,
|
||||
.sourceDimensions = {
|
||||
.width = 23,
|
||||
.height = 42
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ void Layout() {
|
|||
.childAlignment = { CLAY_ALIGN_X_CENTER, CLAY_ALIGN_Y_CENTER }},
|
||||
.border = { .color = PRIMARY, .width = 2, 2, 2, 2 }, .cornerRadius = 10
|
||||
}) {
|
||||
CLAY({ .layout = { .sizing = { CLAY_SIZING_FIXED(32), CLAY_SIZING_FIXED(32) } }, .image = { .sourceDimensions = { 32, 32 }, .imageData = "resources/check.png" }});
|
||||
CLAY({ .layout = { .sizing = { CLAY_SIZING_FIXED(32), CLAY_SIZING_FIXED(32) } }, .image = { .imageData = "resources/check.png" }});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -97,6 +97,7 @@
|
|||
{name: 'a', type: 'float' },
|
||||
]};
|
||||
let stringDefinition = { type: 'struct', members: [
|
||||
{name: 'isStaticallyAllocated', type: 'uint32_t'},
|
||||
{name: 'length', type: 'uint32_t' },
|
||||
{name: 'chars', type: 'uint32_t' },
|
||||
]};
|
||||
|
@ -144,7 +145,6 @@
|
|||
let imageRenderDataDefinition = { type: 'struct', members: [
|
||||
{ name: 'backgroundColor', ...colorDefinition },
|
||||
{ name: 'cornerRadius', ...cornerRadiusDefinition },
|
||||
{ name: 'sourceDimensions', ...dimensionsDefinition },
|
||||
{ name: 'imageData', type: 'uint32_t' },
|
||||
]};
|
||||
let customRenderDataDefinition = { type: 'struct', members: [
|
||||
|
@ -158,7 +158,7 @@
|
|||
{ name: 'width', ...borderWidthDefinition },
|
||||
{ name: 'padding', type: 'uint16_t'}
|
||||
]};
|
||||
let scrollRenderDataDefinition = { type: 'struct', members: [
|
||||
let clipRenderDataDefinition = { type: 'struct', members: [
|
||||
{ name: 'horizontal', type: 'bool' },
|
||||
{ name: 'vertical', type: 'bool' },
|
||||
]};
|
||||
|
@ -166,9 +166,10 @@
|
|||
{ name: 'link', ...stringDefinition },
|
||||
{ name: 'cursorPointer', type: 'uint8_t' },
|
||||
{ name: 'disablePointerEvents', type: 'uint8_t' },
|
||||
{ name: 'padding', type: 'uint16_t'}
|
||||
]};
|
||||
let renderCommandDefinition = {
|
||||
name: 'CLay_RenderCommand',
|
||||
name: 'Clay_RenderCommand',
|
||||
type: 'struct',
|
||||
members: [
|
||||
{ name: 'boundingBox', type: 'struct', members: [
|
||||
|
@ -183,7 +184,7 @@
|
|||
{ name: 'image', ...imageRenderDataDefinition },
|
||||
{ name: 'custom', ...customRenderDataDefinition },
|
||||
{ name: 'border', ...borderRenderDataDefinition },
|
||||
{ name: 'scroll', ...scrollRenderDataDefinition },
|
||||
{ name: 'clip', ...clipRenderDataDefinition },
|
||||
]},
|
||||
{ name: 'userData', type: 'uint32_t'},
|
||||
{ name: 'id', type: 'uint32_t' },
|
||||
|
@ -380,7 +381,7 @@
|
|||
memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
|
||||
memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
|
||||
instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
|
||||
instance.exports.SetScratchMemory(arenaAddress, clayScratchSpaceAddress);
|
||||
instance.exports.SetScratchMemory(clayScratchSpaceAddress);
|
||||
renderCommandSize = getStructTotalSize(renderCommandDefinition);
|
||||
renderLoop();
|
||||
}
|
||||
|
@ -425,10 +426,13 @@
|
|||
if (!elementCache[renderCommand.id.value]) {
|
||||
let elementType = 'div';
|
||||
switch (renderCommand.commandType.value & 0xff) {
|
||||
case CLAY_RENDER_COMMAND_TYPE_TEXT:
|
||||
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
|
||||
// if (readStructAtAddress(renderCommand.renderData.rectangle.value, rectangleRenderDataDefinition).link.length.value > 0) { TODO reimplement links
|
||||
// elementType = 'a';
|
||||
// }
|
||||
if (renderCommand.userData.value !== 0) {
|
||||
if (readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition).link.length.value > 0) {
|
||||
elementType = 'a';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
|
||||
|
@ -549,7 +553,6 @@
|
|||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
|
||||
let config = renderCommand.renderData.text;
|
||||
let customData = readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition);
|
||||
let configMemory = JSON.stringify(config);
|
||||
let stringContents = new Uint8Array(memoryDataView.buffer.slice(config.stringContents.chars.value, config.stringContents.chars.value + config.stringContents.length.value));
|
||||
if (configMemory !== elementData.previousMemoryConfig) {
|
||||
|
@ -559,7 +562,23 @@
|
|||
element.style.color = `rgba(${textColor.r.value}, ${textColor.g.value}, ${textColor.b.value}, ${textColor.a.value})`;
|
||||
element.style.fontFamily = fontsById[config.fontId.value];
|
||||
element.style.fontSize = fontSize + 'px';
|
||||
if (renderCommand.userData.value !== 0) {
|
||||
let customData = readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition);
|
||||
element.style.pointerEvents = customData.disablePointerEvents.value ? 'none' : 'all';
|
||||
let linkContents = customData.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(customData.link.chars.value, customData.link.chars.value + customData.link.length.value))) : 0;
|
||||
memoryDataView.setUint32(0, renderCommand.id.value, true);
|
||||
if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
|
||||
window.location.href = linkContents;
|
||||
}
|
||||
if (linkContents.length > 0) {
|
||||
element.href = linkContents;
|
||||
}
|
||||
|
||||
if (linkContents.length > 0 || customData.cursorPointer.value) {
|
||||
element.style.pointerEvents = 'all';
|
||||
element.style.cursor = 'pointer';
|
||||
}
|
||||
}
|
||||
elementData.previousMemoryConfig = configMemory;
|
||||
}
|
||||
if (stringContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(stringContents, elementData.previousMemoryText, stringContents.length)) {
|
||||
|
@ -570,7 +589,7 @@
|
|||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
|
||||
scissorStack.push({ nextAllocation: { x: renderCommand.boundingBox.x.value, y: renderCommand.boundingBox.y.value }, element, nextElementIndex: 0 });
|
||||
let config = renderCommand.renderData.scroll;
|
||||
let config = renderCommand.renderData.clip;
|
||||
let configMemory = JSON.stringify(config);
|
||||
if (configMemory === elementData.previousMemoryConfig) {
|
||||
break;
|
||||
|
|
Binary file not shown.
|
@ -97,6 +97,7 @@
|
|||
{name: 'a', type: 'float' },
|
||||
]};
|
||||
let stringDefinition = { type: 'struct', members: [
|
||||
{name: 'isStaticallyAllocated', type: 'uint32_t'},
|
||||
{name: 'length', type: 'uint32_t' },
|
||||
{name: 'chars', type: 'uint32_t' },
|
||||
]};
|
||||
|
@ -144,7 +145,6 @@
|
|||
let imageRenderDataDefinition = { type: 'struct', members: [
|
||||
{ name: 'backgroundColor', ...colorDefinition },
|
||||
{ name: 'cornerRadius', ...cornerRadiusDefinition },
|
||||
{ name: 'sourceDimensions', ...dimensionsDefinition },
|
||||
{ name: 'imageData', type: 'uint32_t' },
|
||||
]};
|
||||
let customRenderDataDefinition = { type: 'struct', members: [
|
||||
|
@ -158,7 +158,7 @@
|
|||
{ name: 'width', ...borderWidthDefinition },
|
||||
{ name: 'padding', type: 'uint16_t'}
|
||||
]};
|
||||
let scrollRenderDataDefinition = { type: 'struct', members: [
|
||||
let clipRenderDataDefinition = { type: 'struct', members: [
|
||||
{ name: 'horizontal', type: 'bool' },
|
||||
{ name: 'vertical', type: 'bool' },
|
||||
]};
|
||||
|
@ -166,9 +166,10 @@
|
|||
{ name: 'link', ...stringDefinition },
|
||||
{ name: 'cursorPointer', type: 'uint8_t' },
|
||||
{ name: 'disablePointerEvents', type: 'uint8_t' },
|
||||
{ name: 'padding', type: 'uint16_t'}
|
||||
]};
|
||||
let renderCommandDefinition = {
|
||||
name: 'CLay_RenderCommand',
|
||||
name: 'Clay_RenderCommand',
|
||||
type: 'struct',
|
||||
members: [
|
||||
{ name: 'boundingBox', type: 'struct', members: [
|
||||
|
@ -183,7 +184,7 @@
|
|||
{ name: 'image', ...imageRenderDataDefinition },
|
||||
{ name: 'custom', ...customRenderDataDefinition },
|
||||
{ name: 'border', ...borderRenderDataDefinition },
|
||||
{ name: 'scroll', ...scrollRenderDataDefinition },
|
||||
{ name: 'clip', ...clipRenderDataDefinition },
|
||||
]},
|
||||
{ name: 'userData', type: 'uint32_t'},
|
||||
{ name: 'id', type: 'uint32_t' },
|
||||
|
@ -380,7 +381,7 @@
|
|||
memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
|
||||
memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
|
||||
instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
|
||||
instance.exports.SetScratchMemory(arenaAddress, clayScratchSpaceAddress);
|
||||
instance.exports.SetScratchMemory(clayScratchSpaceAddress);
|
||||
renderCommandSize = getStructTotalSize(renderCommandDefinition);
|
||||
renderLoop();
|
||||
}
|
||||
|
@ -425,10 +426,13 @@
|
|||
if (!elementCache[renderCommand.id.value]) {
|
||||
let elementType = 'div';
|
||||
switch (renderCommand.commandType.value & 0xff) {
|
||||
case CLAY_RENDER_COMMAND_TYPE_TEXT:
|
||||
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
|
||||
// if (readStructAtAddress(renderCommand.renderData.rectangle.value, rectangleRenderDataDefinition).link.length.value > 0) { TODO reimplement links
|
||||
// elementType = 'a';
|
||||
// }
|
||||
if (renderCommand.userData.value !== 0) {
|
||||
if (readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition).link.length.value > 0) {
|
||||
elementType = 'a';
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
|
||||
|
@ -549,7 +553,6 @@
|
|||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_TEXT): {
|
||||
let config = renderCommand.renderData.text;
|
||||
let customData = readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition);
|
||||
let configMemory = JSON.stringify(config);
|
||||
let stringContents = new Uint8Array(memoryDataView.buffer.slice(config.stringContents.chars.value, config.stringContents.chars.value + config.stringContents.length.value));
|
||||
if (configMemory !== elementData.previousMemoryConfig) {
|
||||
|
@ -559,7 +562,23 @@
|
|||
element.style.color = `rgba(${textColor.r.value}, ${textColor.g.value}, ${textColor.b.value}, ${textColor.a.value})`;
|
||||
element.style.fontFamily = fontsById[config.fontId.value];
|
||||
element.style.fontSize = fontSize + 'px';
|
||||
if (renderCommand.userData.value !== 0) {
|
||||
let customData = readStructAtAddress(renderCommand.userData.value, customHTMLDataDefinition);
|
||||
element.style.pointerEvents = customData.disablePointerEvents.value ? 'none' : 'all';
|
||||
let linkContents = customData.link.length.value > 0 ? textDecoder.decode(new Uint8Array(memoryDataView.buffer.slice(customData.link.chars.value, customData.link.chars.value + customData.link.length.value))) : 0;
|
||||
memoryDataView.setUint32(0, renderCommand.id.value, true);
|
||||
if (linkContents.length > 0 && (window.mouseDownThisFrame || window.touchDown) && instance.exports.Clay_PointerOver(0)) {
|
||||
window.location.href = linkContents;
|
||||
}
|
||||
if (linkContents.length > 0) {
|
||||
element.href = linkContents;
|
||||
}
|
||||
|
||||
if (linkContents.length > 0 || customData.cursorPointer.value) {
|
||||
element.style.pointerEvents = 'all';
|
||||
element.style.cursor = 'pointer';
|
||||
}
|
||||
}
|
||||
elementData.previousMemoryConfig = configMemory;
|
||||
}
|
||||
if (stringContents.length !== elementData.previousMemoryText.length || MemoryIsDifferent(stringContents, elementData.previousMemoryText, stringContents.length)) {
|
||||
|
@ -570,7 +589,7 @@
|
|||
}
|
||||
case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
|
||||
scissorStack.push({ nextAllocation: { x: renderCommand.boundingBox.x.value, y: renderCommand.boundingBox.y.value }, element, nextElementIndex: 0 });
|
||||
let config = renderCommand.renderData.scroll;
|
||||
let config = renderCommand.renderData.clip;
|
||||
let configMemory = JSON.stringify(config);
|
||||
if (configMemory === elementData.previousMemoryConfig) {
|
||||
break;
|
||||
|
|
|
@ -44,7 +44,7 @@ typedef struct {
|
|||
|
||||
Arena frameArena = {};
|
||||
|
||||
typedef struct {
|
||||
typedef struct d {
|
||||
Clay_String link;
|
||||
bool cursorPointer;
|
||||
bool disablePointerEvents;
|
||||
|
@ -66,7 +66,7 @@ Clay_String* FrameAllocateString(Clay_String string) {
|
|||
|
||||
void LandingPageBlob(int index, int fontSize, Clay_Color color, Clay_String text, Clay_String imageURL) {
|
||||
CLAY({ .id = CLAY_IDI("HeroBlob", index), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 480) }, .padding = CLAY_PADDING_ALL(16), .childGap = 16, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} }, .border = { .color = color, .width = { 2, 2, 2, 2 }}, .cornerRadius = CLAY_CORNER_RADIUS(10) }) {
|
||||
CLAY({ .id = CLAY_IDI("CheckImage", index), .layout = { .sizing = { CLAY_SIZING_FIXED(32) } }, .image = { .sourceDimensions = { 128, 128 }, .imageData = FrameAllocateString(imageURL) } }) {}
|
||||
CLAY({ .id = CLAY_IDI("CheckImage", index), .layout = { .sizing = { CLAY_SIZING_FIXED(32) } }, .aspectRatio = { 1 }, .image = { .imageData = FrameAllocateString(imageURL) } }) {}
|
||||
CLAY_TEXT(text, CLAY_TEXT_CONFIG({ .fontSize = fontSize, .fontId = FONT_ID_BODY_24, .textColor = color }));
|
||||
}
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ void DeclarativeSyntaxPageDesktop() {
|
|||
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({ .id = CLAY_ID("SyntaxPageRightImage"), .layout = { .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} } }) {
|
||||
CLAY({ .id = CLAY_ID("SyntaxPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 568) } }, .image = { .sourceDimensions = {1136, 1194}, .imageData = FrameAllocateString(CLAY_STRING("/clay/images/declarative.png")) } }) {}
|
||||
CLAY({ .id = CLAY_ID("SyntaxPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 568) } }, .aspectRatio = { 1136.0 / 1194.0 }, .image = { .imageData = FrameAllocateString(CLAY_STRING("/clay/images/declarative.png")) } }) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ void DeclarativeSyntaxPageMobile() {
|
|||
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({ .id = CLAY_ID("SyntaxPageRightImage"), .layout = { .sizing = { CLAY_SIZING_GROW(0) }, .childAlignment = {.x = CLAY_ALIGN_X_CENTER} } }) {
|
||||
CLAY({ .id = CLAY_ID("SyntaxPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 568) } }, .image = { .sourceDimensions = {1136, 1194}, .imageData = FrameAllocateString(CLAY_STRING("/clay/images/declarative.png")) } }) {}
|
||||
CLAY({ .id = CLAY_ID("SyntaxPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 568) } }, .aspectRatio = { 1136.0 / 1194.0 }, .image = { .imageData = FrameAllocateString(CLAY_STRING("/clay/images/declarative.png")) } }) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -323,7 +323,7 @@ void DebuggerPageDesktop() {
|
|||
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({ .id = CLAY_ID("DebuggerRightImageOuter"), .layout = { .sizing = { CLAY_SIZING_PERCENT(0.50) }, .childAlignment = {CLAY_ALIGN_X_CENTER} } }) {
|
||||
CLAY({ .id = CLAY_ID("DebuggerPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 558) } }, .image = { .sourceDimensions = {1620, 1474}, .imageData = FrameAllocateString(CLAY_STRING("/clay/images/debugger.png")) } }) {}
|
||||
CLAY({ .id = CLAY_ID("DebuggerPageRightImageInner"), .layout = { .sizing = { CLAY_SIZING_GROW(.max = 558) } }, .aspectRatio = { 1620.0 / 1474.0 }, .image = {.imageData = FrameAllocateString(CLAY_STRING("/clay/images/debugger.png")) } }) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -345,11 +345,18 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
|
|||
CLAY_TEXT(CLAY_STRING("Clay"), &headerTextConfig);
|
||||
CLAY({ .id = CLAY_ID("Spacer"), .layout = { .sizing = { .width = CLAY_SIZING_GROW(0) } } }) {}
|
||||
if (!mobileScreen) {
|
||||
CLAY({ .id = CLAY_ID("LinkExamplesOuter"), .layout = { .padding = {8, 8} }, .userData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples") }) }) {
|
||||
CLAY_TEXT(CLAY_STRING("Examples"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
|
||||
CLAY({ .id = CLAY_ID("LinkExamplesOuter"), .layout = { .padding = {8, 8} } }) {
|
||||
CLAY_TEXT(CLAY_STRING("Examples"), CLAY_TEXT_CONFIG({
|
||||
.userData = FrameAllocateCustomData((CustomHTMLData) {
|
||||
.link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples")
|
||||
}),
|
||||
.fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
|
||||
}
|
||||
CLAY({ .id = CLAY_ID("LinkDocsOuter"), .layout = { .padding = {8, 8} }, .userData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay/blob/main/README.md") }) }) {
|
||||
CLAY_TEXT(CLAY_STRING("Docs"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
|
||||
CLAY({ .id = CLAY_ID("LinkDocsOuter"), .layout = { .padding = {8, 8} } }) {
|
||||
CLAY_TEXT(CLAY_STRING("Docs"), CLAY_TEXT_CONFIG({
|
||||
.userData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay/blob/main/README.md") }),
|
||||
.fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} })
|
||||
);
|
||||
}
|
||||
}
|
||||
CLAY({
|
||||
|
@ -357,9 +364,11 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
|
|||
.backgroundColor = Clay_Hovered() ? COLOR_LIGHT_HOVER : COLOR_LIGHT,
|
||||
.border = { .width = {2, 2, 2, 2}, .color = COLOR_RED },
|
||||
.cornerRadius = CLAY_CORNER_RADIUS(10),
|
||||
.userData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay/tree/main/examples") }),
|
||||
.userData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://discord.gg/b4FTWkxdvT") }),
|
||||
}) {
|
||||
CLAY_TEXT(CLAY_STRING("Discord"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
|
||||
CLAY_TEXT(CLAY_STRING("Discord"), CLAY_TEXT_CONFIG({
|
||||
.userData = FrameAllocateCustomData((CustomHTMLData) { .disablePointerEvents = true }),
|
||||
.fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
|
||||
}
|
||||
CLAY({
|
||||
.layout = { .padding = {16, 16, 6, 6} },
|
||||
|
@ -368,7 +377,9 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) {
|
|||
.cornerRadius = CLAY_CORNER_RADIUS(10),
|
||||
.userData = FrameAllocateCustomData((CustomHTMLData) { .link = CLAY_STRING("https://github.com/nicbarker/clay") }),
|
||||
}) {
|
||||
CLAY_TEXT(CLAY_STRING("Github"), CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
|
||||
CLAY_TEXT(CLAY_STRING("Github"), CLAY_TEXT_CONFIG({
|
||||
.userData = FrameAllocateCustomData((CustomHTMLData) { .disablePointerEvents = true }),
|
||||
.fontId = FONT_ID_BODY_24, .fontSize = 24, .textColor = {61, 26, 5, 255} }));
|
||||
}
|
||||
}
|
||||
Clay_LayoutConfig topBorderConfig = (Clay_LayoutConfig) { .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(4) }};
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -23,6 +23,7 @@ static Clay_Dimensions SDL2_MeasureText(Clay_StringSlice text, Clay_TextElementC
|
|||
SDL2_Font *fonts = (SDL2_Font*)userData;
|
||||
|
||||
TTF_Font *font = fonts[config->fontId].font;
|
||||
TTF_SetFontSize(font, config->fontSize);
|
||||
char *chars = (char *)calloc(text.length + 1, 1);
|
||||
memcpy(chars, text.chars, text.length);
|
||||
int width = 0;
|
||||
|
@ -294,6 +295,7 @@ static void Clay_SDL2_Render(SDL_Renderer *renderer, Clay_RenderCommandArray ren
|
|||
char *cloned = (char *)calloc(config->stringContents.length + 1, 1);
|
||||
memcpy(cloned, config->stringContents.chars, config->stringContents.length);
|
||||
TTF_Font* font = fonts[config->fontId].font;
|
||||
TTF_SetFontSize(font, config->fontSize);
|
||||
SDL_Surface *surface = TTF_RenderUTF8_Blended(font, cloned, (SDL_Color) {
|
||||
.r = (Uint8)config->textColor.r,
|
||||
.g = (Uint8)config->textColor.g,
|
||||
|
|
|
@ -164,6 +164,7 @@ static void SDL_Clay_RenderClayCommands(Clay_SDL3RendererData *rendererData, Cla
|
|||
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
|
||||
Clay_TextRenderData *config = &rcmd->renderData.text;
|
||||
TTF_Font *font = rendererData->fonts[config->fontId];
|
||||
TTF_SetFontSize(font, config->fontSize);
|
||||
TTF_Text *text = TTF_CreateText(rendererData->textEngine, font, config->stringContents.chars, config->stringContents.length);
|
||||
TTF_SetTextColor(text, config->textColor.r, config->textColor.g, config->textColor.b, config->textColor.a);
|
||||
TTF_DrawRendererText(text, rect.x, rect.y);
|
||||
|
@ -184,11 +185,11 @@ static void SDL_Clay_RenderClayCommands(Clay_SDL3RendererData *rendererData, Cla
|
|||
if (config->width.left > 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->width.left, length };
|
||||
SDL_FRect line = { rect.x - 1, starting_y, config->width.left, length };
|
||||
SDL_RenderFillRect(rendererData->renderer, &line);
|
||||
}
|
||||
if (config->width.right > 0) {
|
||||
const float starting_x = rect.x + rect.w - (float)config->width.right;
|
||||
const float starting_x = rect.x + rect.w - (float)config->width.right + 1;
|
||||
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->width.right, length };
|
||||
|
@ -197,12 +198,12 @@ static void SDL_Clay_RenderClayCommands(Clay_SDL3RendererData *rendererData, Cla
|
|||
if (config->width.top > 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->width.top };
|
||||
SDL_FRect line = { starting_x, rect.y - 1, length, config->width.top };
|
||||
SDL_RenderFillRect(rendererData->renderer, &line);
|
||||
}
|
||||
if (config->width.bottom > 0) {
|
||||
const float starting_x = rect.x + clampedRadii.bottomLeft;
|
||||
const float starting_y = rect.y + rect.h - (float)config->width.bottom;
|
||||
const float starting_y = rect.y + rect.h - (float)config->width.bottom + 1;
|
||||
const float length = rect.w - clampedRadii.bottomLeft - clampedRadii.bottomRight;
|
||||
SDL_FRect line = { starting_x, starting_y, length, config->width.bottom };
|
||||
SDL_SetRenderDrawColor(rendererData->renderer, config->color.r, config->color.g, config->color.b, config->color.a);
|
||||
|
@ -211,25 +212,25 @@ static void SDL_Clay_RenderClayCommands(Clay_SDL3RendererData *rendererData, Cla
|
|||
//corners
|
||||
if (config->cornerRadius.topLeft > 0) {
|
||||
const float centerX = rect.x + clampedRadii.topLeft -1;
|
||||
const float centerY = rect.y + clampedRadii.topLeft;
|
||||
const float centerY = rect.y + clampedRadii.topLeft - 1;
|
||||
SDL_Clay_RenderArc(rendererData, (SDL_FPoint){centerX, centerY}, clampedRadii.topLeft,
|
||||
180.0f, 270.0f, config->width.top, config->color);
|
||||
}
|
||||
if (config->cornerRadius.topRight > 0) {
|
||||
const float centerX = rect.x + rect.w - clampedRadii.topRight -1;
|
||||
const float centerY = rect.y + clampedRadii.topRight;
|
||||
const float centerX = rect.x + rect.w - clampedRadii.topRight;
|
||||
const float centerY = rect.y + clampedRadii.topRight - 1;
|
||||
SDL_Clay_RenderArc(rendererData, (SDL_FPoint){centerX, centerY}, clampedRadii.topRight,
|
||||
270.0f, 360.0f, config->width.top, config->color);
|
||||
}
|
||||
if (config->cornerRadius.bottomLeft > 0) {
|
||||
const float centerX = rect.x + clampedRadii.bottomLeft -1;
|
||||
const float centerY = rect.y + rect.h - clampedRadii.bottomLeft -1;
|
||||
const float centerY = rect.y + rect.h - clampedRadii.bottomLeft;
|
||||
SDL_Clay_RenderArc(rendererData, (SDL_FPoint){centerX, centerY}, clampedRadii.bottomLeft,
|
||||
90.0f, 180.0f, config->width.bottom, config->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;
|
||||
const float centerX = rect.x + rect.w - clampedRadii.bottomRight;
|
||||
const float centerY = rect.y + rect.h - clampedRadii.bottomRight;
|
||||
SDL_Clay_RenderArc(rendererData, (SDL_FPoint){centerX, centerY}, clampedRadii.bottomRight,
|
||||
0.0f, 90.0f, config->width.bottom, config->color);
|
||||
}
|
||||
|
|
|
@ -87,6 +87,8 @@ static inline Clay_Dimensions Raylib_MeasureText(Clay_StringSlice text, Clay_Tex
|
|||
|
||||
float maxTextWidth = 0.0f;
|
||||
float lineTextWidth = 0;
|
||||
int maxLineCharCount = 0;
|
||||
int lineCharCount = 0;
|
||||
|
||||
float textHeight = config->fontSize;
|
||||
Font* fonts = (Font*)userData;
|
||||
|
@ -99,11 +101,13 @@ static inline Clay_Dimensions Raylib_MeasureText(Clay_StringSlice text, Clay_Tex
|
|||
|
||||
float scaleFactor = config->fontSize/(float)fontToUse.baseSize;
|
||||
|
||||
for (int i = 0; i < text.length; ++i)
|
||||
for (int i = 0; i < text.length; ++i, lineCharCount++)
|
||||
{
|
||||
if (text.chars[i] == '\n') {
|
||||
maxTextWidth = fmax(maxTextWidth, lineTextWidth);
|
||||
maxLineCharCount = CLAY__MAX(maxLineCharCount, lineCharCount);
|
||||
lineTextWidth = 0;
|
||||
lineCharCount = 0;
|
||||
continue;
|
||||
}
|
||||
int index = text.chars[i] - 32;
|
||||
|
@ -112,8 +116,9 @@ static inline Clay_Dimensions Raylib_MeasureText(Clay_StringSlice text, Clay_Tex
|
|||
}
|
||||
|
||||
maxTextWidth = fmax(maxTextWidth, lineTextWidth);
|
||||
maxLineCharCount = CLAY__MAX(maxLineCharCount, lineCharCount);
|
||||
|
||||
textSize.width = maxTextWidth * scaleFactor;
|
||||
textSize.width = maxTextWidth * scaleFactor + (lineCharCount * config->letterSpacing);
|
||||
textSize.height = textHeight;
|
||||
|
||||
return textSize;
|
||||
|
@ -145,7 +150,7 @@ void Clay_Raylib_Render(Clay_RenderCommandArray renderCommands, Font* fonts)
|
|||
for (int j = 0; j < renderCommands.length; j++)
|
||||
{
|
||||
Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, j);
|
||||
Clay_BoundingBox boundingBox = renderCommand->boundingBox;
|
||||
Clay_BoundingBox boundingBox = {roundf(renderCommand->boundingBox.x), roundf(renderCommand->boundingBox.y), roundf(renderCommand->boundingBox.width), roundf(renderCommand->boundingBox.height)};
|
||||
switch (renderCommand->commandType)
|
||||
{
|
||||
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
|
||||
|
@ -174,11 +179,12 @@ void Clay_Raylib_Render(Clay_RenderCommandArray renderCommands, Font* fonts)
|
|||
if (tintColor.r == 0 && tintColor.g == 0 && tintColor.b == 0 && tintColor.a == 0) {
|
||||
tintColor = (Clay_Color) { 255, 255, 255, 255 };
|
||||
}
|
||||
DrawTextureEx(
|
||||
DrawTexturePro(
|
||||
imageTexture,
|
||||
(Vector2){boundingBox.x, boundingBox.y},
|
||||
(Rectangle) { 0, 0, imageTexture.width, imageTexture.height },
|
||||
(Rectangle){boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height},
|
||||
(Vector2) {},
|
||||
0,
|
||||
boundingBox.width / (float)imageTexture.width,
|
||||
CLAY_COLOR_TO_RAYLIB_COLOR(tintColor));
|
||||
break;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue