mirror of
https://github.com/nicbarker/clay.git
synced 2025-04-23 14:48:06 +00:00
Compare commits
7 Commits
7209bbf0d0
...
517442381c
Author | SHA1 | Date | |
---|---|---|---|
|
517442381c | ||
|
08e4c5b198 | ||
|
b1c72a0647 | ||
|
aee4baee1c | ||
|
47d1d84bc8 | ||
|
ad49977f1b | ||
|
61490e4557 |
@ -17,6 +17,7 @@ when ODIN_OS == .Windows {
|
||||
}
|
||||
|
||||
String :: struct {
|
||||
isStaticallyAllocated: c.bool,
|
||||
length: c.int32_t,
|
||||
chars: [^]c.char,
|
||||
}
|
||||
@ -110,7 +111,6 @@ TextElementConfig :: struct {
|
||||
lineHeight: u16,
|
||||
wrapMode: TextWrapMode,
|
||||
textAlignment: TextAlignment,
|
||||
hashStringContents: bool,
|
||||
}
|
||||
|
||||
ImageElementConfig :: struct {
|
||||
@ -367,6 +367,8 @@ Context :: struct {} // opaque structure, only use as a pointer
|
||||
|
||||
@(link_prefix = "Clay_", default_calling_convention = "c")
|
||||
foreign Clay {
|
||||
_OpenElement :: proc() ---
|
||||
_CloseElement :: proc() ---
|
||||
MinMemorySize :: proc() -> u32 ---
|
||||
CreateArenaWithCapacityAndMemory :: proc(capacity: c.size_t, offset: [^]u8) -> Arena ---
|
||||
SetPointerState :: proc(position: Vector2, pointerDown: bool) ---
|
||||
@ -399,9 +401,7 @@ foreign Clay {
|
||||
|
||||
@(link_prefix = "Clay_", default_calling_convention = "c", private)
|
||||
foreign Clay {
|
||||
_OpenElement :: proc() ---
|
||||
_ConfigureOpenElement :: proc(config: ElementDeclaration) ---
|
||||
_CloseElement :: proc() ---
|
||||
_HashString :: proc(key: String, offset: u32, seed: u32) -> ElementId ---
|
||||
_OpenTextElement :: proc(text: String, textConfig: ^TextElementConfig) ---
|
||||
_StoreTextElementConfig :: proc(config: TextElementConfig) -> ^TextElementConfig ---
|
||||
@ -419,7 +419,13 @@ UI :: proc() -> proc (config: ElementDeclaration) -> bool {
|
||||
return ConfigureOpenElement
|
||||
}
|
||||
|
||||
Text :: proc(text: string, config: ^TextElementConfig) {
|
||||
Text :: proc($text: string, config: ^TextElementConfig) {
|
||||
wrapped := MakeString(text)
|
||||
wrapped.isStaticallyAllocated = true
|
||||
_OpenTextElement(wrapped, config)
|
||||
}
|
||||
|
||||
TextDynamic :: proc(text: string, config: ^TextElementConfig) {
|
||||
_OpenTextElement(MakeString(text), config)
|
||||
}
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -62,7 +62,7 @@ border2pxRed := clay.BorderElementConfig {
|
||||
color = COLOR_RED
|
||||
}
|
||||
|
||||
LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Color, text: string, image: ^raylib.Texture2D) {
|
||||
LandingPageBlob :: proc(index: u32, fontSize: u16, fontId: u16, color: clay.Color, $text: string, image: ^raylib.Texture2D) {
|
||||
if clay.UI()({
|
||||
id = clay.ID("HeroBlob", index),
|
||||
layout = { sizing = { width = clay.SizingGrow({ max = 480 }) }, padding = clay.PaddingAll(16), childGap = 16, childAlignment = clay.ChildAlignment{ y = .Center } },
|
||||
@ -252,7 +252,7 @@ ColorLerp :: proc(a: clay.Color, b: clay.Color, amount: f32) -> clay.Color {
|
||||
return clay.Color{a.r + (b.r - a.r) * amount, a.g + (b.g - a.g) * amount, a.b + (b.b - a.b) * amount, a.a + (b.a - a.a) * amount}
|
||||
}
|
||||
|
||||
LOREM_IPSUM_TEXT := "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
||||
LOREM_IPSUM_TEXT :: "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."
|
||||
|
||||
HighPerformancePage :: proc(lerpValue: f32, titleTextConfig: clay.TextElementConfig, widthSizing: clay.SizingAxis) {
|
||||
if clay.UI()({ id = clay.ID("PerformanceLeftText"), layout = { sizing = { width = widthSizing }, layoutDirection = .TopToBottom, childGap = 8 } }) {
|
||||
@ -321,7 +321,7 @@ HighPerformancePageMobile :: proc(lerpValue: f32) {
|
||||
}
|
||||
}
|
||||
|
||||
RendererButtonActive :: proc(index: i32, text: string) {
|
||||
RendererButtonActive :: proc(index: i32, $text: string) {
|
||||
if clay.UI()({
|
||||
layout = { sizing = { width = clay.SizingFixed(300) }, padding = clay.PaddingAll(16) },
|
||||
backgroundColor = COLOR_RED,
|
||||
@ -331,7 +331,7 @@ RendererButtonActive :: proc(index: i32, text: string) {
|
||||
}
|
||||
}
|
||||
|
||||
RendererButtonInactive :: proc(index: u32, text: string) {
|
||||
RendererButtonInactive :: proc(index: u32, $text: string) {
|
||||
if clay.UI()({ border = border2pxRed }) {
|
||||
if clay.UI()({
|
||||
id = clay.ID("RendererButtonInactiveInner", index),
|
||||
|
271
clay.h
271
clay.h
@ -96,9 +96,9 @@
|
||||
#define CLAY__ENSURE_STRING_LITERAL(x) ("" x "")
|
||||
|
||||
// Note: If an error led you here, it's because CLAY_STRING can only be used with string literals, i.e. CLAY_STRING("SomeString") and not CLAY_STRING(yourString)
|
||||
#define CLAY_STRING(string) (CLAY__INIT(Clay_String) { .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) })
|
||||
#define CLAY_STRING(string) (CLAY__INIT(Clay_String) { .isStaticallyAllocated = true, .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) })
|
||||
|
||||
#define CLAY_STRING_CONST(string) { .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) }
|
||||
#define CLAY_STRING_CONST(string) { .isStaticallyAllocated = true, .length = CLAY__STRING_LENGTH(CLAY__ENSURE_STRING_LITERAL(string)), .chars = (string) }
|
||||
|
||||
static uint8_t CLAY__ELEMENT_DEFINITION_LATCH;
|
||||
|
||||
@ -184,7 +184,10 @@ 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;
|
||||
int32_t length;
|
||||
// The underlying character memory. Note: this will not be copied and will not extend the lifetime of the underlying memory.
|
||||
const char *chars;
|
||||
@ -192,7 +195,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
|
||||
@ -202,33 +205,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().
|
||||
@ -237,7 +240,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;
|
||||
@ -287,20 +290,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.
|
||||
@ -309,14 +312,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;
|
||||
@ -327,7 +330,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).
|
||||
@ -360,7 +363,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.
|
||||
@ -384,10 +387,6 @@ typedef struct {
|
||||
// CLAY_TEXT_ALIGN_CENTER - Horizontally aligns wrapped lines of text to the center of their bounding box.
|
||||
// CLAY_TEXT_ALIGN_RIGHT - Horizontally aligns wrapped lines of text to the right hand side of their bounding box.
|
||||
Clay_TextAlignment textAlignment;
|
||||
// When set to true, clay will hash the entire text contents of this string as an identifier for its internal
|
||||
// text measurement cache, rather than just the pointer and length. This will incur significant performance cost for
|
||||
// long bodies of text.
|
||||
bool hashStringContents;
|
||||
} Clay_TextElementConfig;
|
||||
|
||||
CLAY__WRAPPER_STRUCT(Clay_TextElementConfig);
|
||||
@ -419,7 +418,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;
|
||||
@ -448,7 +447,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.
|
||||
@ -481,7 +480,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;
|
||||
@ -492,7 +491,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_ScrollElementConfig {
|
||||
bool horizontal; // Clip overflowing elements on the X axis and allow scrolling left and right.
|
||||
bool vertical; // Clip overflowing elements on the YU axis and allow scrolling up and down.
|
||||
} Clay_ScrollElementConfig;
|
||||
@ -502,7 +501,7 @@ CLAY__WRAPPER_STRUCT(Clay_ScrollElementConfig);
|
||||
// Border -----------------------------
|
||||
|
||||
// Controls the widths of individual element borders.
|
||||
typedef struct {
|
||||
typedef struct Clay_BorderWidth {
|
||||
uint16_t left;
|
||||
uint16_t right;
|
||||
uint16_t top;
|
||||
@ -514,7 +513,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;
|
||||
@ -524,7 +523,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;
|
||||
@ -540,7 +539,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.
|
||||
@ -549,7 +548,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.
|
||||
@ -564,7 +563,7 @@ typedef struct {
|
||||
} 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;
|
||||
@ -576,13 +575,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_ScrollRenderData;
|
||||
|
||||
// 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;
|
||||
@ -594,7 +593,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
|
||||
@ -612,7 +611,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;
|
||||
@ -627,7 +626,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.
|
||||
@ -654,7 +653,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.
|
||||
@ -679,7 +678,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.
|
||||
@ -701,7 +700,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.
|
||||
@ -712,7 +711,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;
|
||||
@ -763,7 +762,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().
|
||||
@ -876,8 +875,7 @@ CLAY_DLL_EXPORT int32_t Clay_GetMaxMeasureTextCacheWordCount(void);
|
||||
// Modifies the maximum number of measured "words" (whitespace seperated runs of characters) that Clay can store in its internal text measurement cache.
|
||||
// This may require reallocating additional memory, and re-calling Clay_Initialize();
|
||||
CLAY_DLL_EXPORT void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount);
|
||||
// Resets Clay's internal text measurement cache, useful if memory to represent strings is being re-used.
|
||||
// Similar behaviour can be achieved on an individual text element level by using Clay_TextElementConfig.hashStringContents
|
||||
// Resets Clay's internal text measurement cache. Useful if font mappings have changed or fonts have been reloaded.
|
||||
CLAY_DLL_EXPORT void Clay_ResetMeasureTextCache(void);
|
||||
|
||||
// Internal API functions required by macros ----------------------
|
||||
@ -1156,6 +1154,7 @@ CLAY__ARRAY_DEFINE(Clay__MeasuredWord, Clay__MeasuredWordArray)
|
||||
typedef struct {
|
||||
Clay_Dimensions unwrappedDimensions;
|
||||
int32_t measuredWordsStartIndex;
|
||||
float minWidth;
|
||||
bool containsNewlines;
|
||||
// Hash map data
|
||||
uint32_t id;
|
||||
@ -1347,26 +1346,140 @@ Clay_ElementId Clay__HashString(Clay_String key, const uint32_t offset, const ui
|
||||
return CLAY__INIT(Clay_ElementId) { .id = hash + 1, .offset = offset, .baseId = base + 1, .stringId = key }; // Reserve the hash result of zero as "null id"
|
||||
}
|
||||
|
||||
uint32_t Clay__HashTextWithConfig(Clay_String *text, Clay_TextElementConfig *config) {
|
||||
#if !defined(CLAY_DISABLE_SIMD) && (defined(__x86_64__) || defined(_M_X64) || defined(_M_AMD64))
|
||||
static inline __m128i Clay__SIMDRotateLeft(__m128i x, int r) {
|
||||
return _mm_or_si128(_mm_slli_epi64(x, r), _mm_srli_epi64(x, 64 - r));
|
||||
}
|
||||
|
||||
static inline void Clay__SIMDARXMix(__m128i* a, __m128i* b) {
|
||||
*a = _mm_add_epi64(*a, *b);
|
||||
*b = _mm_xor_si128(Clay__SIMDRotateLeft(*b, 17), *a);
|
||||
}
|
||||
|
||||
uint64_t Clay__HashData(const uint8_t* data, size_t length) {
|
||||
// Pinched these constants from the BLAKE implementation
|
||||
__m128i v0 = _mm_set1_epi64x(0x6a09e667f3bcc908ULL);
|
||||
__m128i v1 = _mm_set1_epi64x(0xbb67ae8584caa73bULL);
|
||||
__m128i v2 = _mm_set1_epi64x(0x3c6ef372fe94f82bULL);
|
||||
__m128i v3 = _mm_set1_epi64x(0xa54ff53a5f1d36f1ULL);
|
||||
|
||||
uint8_t overflowBuffer[16] = { 0 }; // Temporary buffer for small inputs
|
||||
|
||||
while (length > 0) {
|
||||
__m128i msg;
|
||||
if (length >= 16) {
|
||||
msg = _mm_loadu_si128((const __m128i*)data);
|
||||
data += 16;
|
||||
length -= 16;
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < length; i++) {
|
||||
overflowBuffer[i] = data[i];
|
||||
}
|
||||
msg = _mm_loadu_si128((const __m128i*)overflowBuffer);
|
||||
length = 0;
|
||||
}
|
||||
|
||||
v0 = _mm_xor_si128(v0, msg);
|
||||
Clay__SIMDARXMix(&v0, &v1);
|
||||
Clay__SIMDARXMix(&v2, &v3);
|
||||
|
||||
v0 = _mm_add_epi64(v0, v2);
|
||||
v1 = _mm_add_epi64(v1, v3);
|
||||
}
|
||||
|
||||
Clay__SIMDARXMix(&v0, &v1);
|
||||
Clay__SIMDARXMix(&v2, &v3);
|
||||
v0 = _mm_add_epi64(v0, v2);
|
||||
v1 = _mm_add_epi64(v1, v3);
|
||||
|
||||
uint64_t result[2];
|
||||
_mm_storeu_si128((__m128i*)result, v0);
|
||||
|
||||
return result[0] ^ result[1];
|
||||
}
|
||||
#elif !defined(CLAY_DISABLE_SIMD) && defined(__aarch64__)
|
||||
static inline uint64x2_t Clay__SIMDRotateLeft(uint64x2_t x, int r) {
|
||||
return vorrq_u64(vshlq_n_u64(x, 17), vshrq_n_u64(x, 64 - 17));
|
||||
}
|
||||
|
||||
static inline void Clay__SIMDARXMix(uint64x2_t* a, uint64x2_t* b) {
|
||||
*a = vaddq_u64(*a, *b);
|
||||
*b = veorq_u64(Clay__SIMDRotateLeft(*b, 17), *a);
|
||||
}
|
||||
|
||||
uint64_t Clay__HashData(const uint8_t* data, size_t length) {
|
||||
// Pinched these constants from the BLAKE implementation
|
||||
uint64x2_t v0 = vdupq_n_u64(0x6a09e667f3bcc908ULL);
|
||||
uint64x2_t v1 = vdupq_n_u64(0xbb67ae8584caa73bULL);
|
||||
uint64x2_t v2 = vdupq_n_u64(0x3c6ef372fe94f82bULL);
|
||||
uint64x2_t v3 = vdupq_n_u64(0xa54ff53a5f1d36f1ULL);
|
||||
|
||||
uint8_t overflowBuffer[8] = { 0 };
|
||||
|
||||
while (length > 0) {
|
||||
uint64x2_t msg;
|
||||
if (length > 16) {
|
||||
msg = vld1q_u64((const uint64_t*)data);
|
||||
data += 16;
|
||||
length -= 16;
|
||||
}
|
||||
else if (length > 8) {
|
||||
msg = vcombine_u64(vld1_u64((const uint64_t*)data), vdup_n_u64(0));
|
||||
data += 8;
|
||||
length -= 8;
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < length; i++) {
|
||||
overflowBuffer[i] = data[i];
|
||||
}
|
||||
uint8x8_t lower = vld1_u8(overflowBuffer);
|
||||
msg = vcombine_u8(lower, vdup_n_u8(0));
|
||||
length = 0;
|
||||
}
|
||||
v0 = veorq_u64(v0, msg);
|
||||
Clay__SIMDARXMix(&v0, &v1);
|
||||
Clay__SIMDARXMix(&v2, &v3);
|
||||
|
||||
v0 = vaddq_u64(v0, v2);
|
||||
v1 = vaddq_u64(v1, v3);
|
||||
}
|
||||
|
||||
Clay__SIMDARXMix(&v0, &v1);
|
||||
Clay__SIMDARXMix(&v2, &v3);
|
||||
v0 = vaddq_u64(v0, v2);
|
||||
v1 = vaddq_u64(v1, v3);
|
||||
|
||||
uint64_t result[2];
|
||||
vst1q_u64(result, v0);
|
||||
|
||||
return result[0] ^ result[1];
|
||||
}
|
||||
#else
|
||||
uint64_t Clay__HashData(const uint8_t* data, size_t length) {
|
||||
uint64_t hash = 0;
|
||||
|
||||
for (int32_t i = 0; i < length; i++) {
|
||||
hash += data[i];
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t Clay__HashStringContentsWithConfig(Clay_String *text, Clay_TextElementConfig *config) {
|
||||
uint32_t hash = 0;
|
||||
uintptr_t pointerAsNumber = (uintptr_t)text->chars;
|
||||
|
||||
if (config->hashStringContents) {
|
||||
uint32_t maxLengthToHash = CLAY__MIN(text->length, 256);
|
||||
for (uint32_t i = 0; i < maxLengthToHash; i++) {
|
||||
hash += text->chars[i];
|
||||
if (text->isStaticallyAllocated) {
|
||||
hash += (uintptr_t)text->chars;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
} else {
|
||||
hash += pointerAsNumber;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
|
||||
hash += text->length;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
} else {
|
||||
hash = Clay__HashData((const uint8_t *)text->chars, text->length) % UINT32_MAX;
|
||||
}
|
||||
|
||||
hash += config->fontId;
|
||||
hash += (hash << 10);
|
||||
@ -1376,18 +1489,10 @@ uint32_t Clay__HashTextWithConfig(Clay_String *text, Clay_TextElementConfig *con
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
|
||||
hash += config->lineHeight;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
|
||||
hash += config->letterSpacing;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
|
||||
hash += config->wrapMode;
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
|
||||
hash += (hash << 3);
|
||||
hash ^= (hash >> 11);
|
||||
hash += (hash << 15);
|
||||
@ -1422,7 +1527,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
|
||||
return &Clay__MeasureTextCacheItem_DEFAULT;
|
||||
}
|
||||
#endif
|
||||
uint32_t id = Clay__HashTextWithConfig(text, config);
|
||||
uint32_t id = Clay__HashStringContentsWithConfig(text, config);
|
||||
uint32_t hashBucket = id % (context->maxMeasureTextCacheWordCount / 32);
|
||||
int32_t elementIndexPrevious = 0;
|
||||
int32_t elementIndex = context->measureTextHashMap.internalArray[hashBucket];
|
||||
@ -1504,6 +1609,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
|
||||
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);
|
||||
measured->minWidth = CLAY__MAX(dimensions.width, measured->minWidth);
|
||||
measuredHeight = CLAY__MAX(measuredHeight, dimensions.height);
|
||||
if (current == ' ') {
|
||||
dimensions.width += spaceWidth;
|
||||
@ -1529,6 +1635,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
|
||||
Clay__AddMeasuredWord(CLAY__INIT(Clay__MeasuredWord) { .startOffset = start, .length = end - start, .width = dimensions.width, .next = -1 }, previousWord);
|
||||
lineWidth += dimensions.width;
|
||||
measuredHeight = CLAY__MAX(measuredHeight, dimensions.height);
|
||||
measured->minWidth = CLAY__MAX(dimensions.width, measured->minWidth);
|
||||
}
|
||||
measuredWidth = CLAY__MAX(lineWidth, measuredWidth);
|
||||
|
||||
@ -1563,6 +1670,7 @@ Clay_LayoutElementHashMapItem* Clay__AddHashMapItem(Clay_ElementId elementId, Cl
|
||||
item.nextIndex = hashItem->nextIndex;
|
||||
if (hashItem->generation <= context->generation) { // First collision - assume this is the "same" element
|
||||
hashItem->elementId = elementId; // Make sure to copy this across. If the stringId reference has changed, we should update the hash item to use the new one.
|
||||
hashItem->idAlias = idAlias;
|
||||
hashItem->generation = context->generation + 1;
|
||||
hashItem->layoutElement = layoutElement;
|
||||
hashItem->debugData->collision = false;
|
||||
@ -1663,21 +1771,25 @@ void Clay__CloseElement(void) {
|
||||
}
|
||||
}
|
||||
|
||||
float leftRightPadding = (float)(layoutConfig->padding.left + layoutConfig->padding.right);
|
||||
float topBottomPadding = (float)(layoutConfig->padding.top + layoutConfig->padding.bottom);
|
||||
|
||||
// Attach children to the current open element
|
||||
openLayoutElement->childrenOrTextContent.children.elements = &context->layoutElementChildren.internalArray[context->layoutElementChildren.length];
|
||||
if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
|
||||
openLayoutElement->dimensions.width = (float)(layoutConfig->padding.left + layoutConfig->padding.right);
|
||||
openLayoutElement->dimensions.width = leftRightPadding;
|
||||
openLayoutElement->minDimensions.width = leftRightPadding;
|
||||
for (int32_t i = 0; i < openLayoutElement->childrenOrTextContent.children.length; i++) {
|
||||
int32_t childIndex = Clay__int32_tArray_GetValue(&context->layoutElementChildrenBuffer, (int)context->layoutElementChildrenBuffer.length - openLayoutElement->childrenOrTextContent.children.length + i);
|
||||
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 + layoutConfig->padding.top + layoutConfig->padding.bottom);
|
||||
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) {
|
||||
openLayoutElement->minDimensions.width += child->minDimensions.width;
|
||||
}
|
||||
if (!elementHasScrollVertical) {
|
||||
openLayoutElement->minDimensions.height = CLAY__MAX(openLayoutElement->minDimensions.height, child->minDimensions.height + layoutConfig->padding.top + layoutConfig->padding.bottom);
|
||||
openLayoutElement->minDimensions.height = CLAY__MAX(openLayoutElement->minDimensions.height, child->minDimensions.height + topBottomPadding);
|
||||
}
|
||||
Clay__int32_tArray_Add(&context->layoutElementChildren, childIndex);
|
||||
}
|
||||
@ -1686,18 +1798,19 @@ void Clay__CloseElement(void) {
|
||||
openLayoutElement->minDimensions.width += childGap;
|
||||
}
|
||||
else if (layoutConfig->layoutDirection == CLAY_TOP_TO_BOTTOM) {
|
||||
openLayoutElement->dimensions.height = (float)(layoutConfig->padding.top + layoutConfig->padding.bottom);
|
||||
openLayoutElement->dimensions.height = topBottomPadding;
|
||||
openLayoutElement->minDimensions.height = topBottomPadding;
|
||||
for (int32_t i = 0; i < openLayoutElement->childrenOrTextContent.children.length; i++) {
|
||||
int32_t childIndex = Clay__int32_tArray_GetValue(&context->layoutElementChildrenBuffer, (int)context->layoutElementChildrenBuffer.length - openLayoutElement->childrenOrTextContent.children.length + i);
|
||||
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 + layoutConfig->padding.left + layoutConfig->padding.right);
|
||||
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) {
|
||||
openLayoutElement->minDimensions.height += child->minDimensions.height;
|
||||
}
|
||||
if (!elementHasScrollHorizontal) {
|
||||
openLayoutElement->minDimensions.width = CLAY__MAX(openLayoutElement->minDimensions.width, child->minDimensions.width + layoutConfig->padding.left + layoutConfig->padding.right);
|
||||
openLayoutElement->minDimensions.width = CLAY__MAX(openLayoutElement->minDimensions.width, child->minDimensions.width + leftRightPadding);
|
||||
}
|
||||
Clay__int32_tArray_Add(&context->layoutElementChildren, childIndex);
|
||||
}
|
||||
@ -1849,7 +1962,7 @@ void Clay__OpenTextElement(Clay_String text, Clay_TextElementConfig *textConfig)
|
||||
Clay__StringArray_Add(&context->layoutElementIdStrings, elementId.stringId);
|
||||
Clay_Dimensions textDimensions = { .width = textMeasured->unwrappedDimensions.width, .height = textConfig->lineHeight > 0 ? (float)textConfig->lineHeight : textMeasured->unwrappedDimensions.height };
|
||||
textElement->dimensions = textDimensions;
|
||||
textElement->minDimensions = CLAY__INIT(Clay_Dimensions) { .width = textMeasured->unwrappedDimensions.height, .height = textDimensions.height }; // TODO not sure this is the best way to decide min width for text
|
||||
textElement->minDimensions = CLAY__INIT(Clay_Dimensions) { .width = textMeasured->minWidth, .height = textDimensions.height };
|
||||
textElement->childrenOrTextContent.textElementData = Clay__TextElementDataArray_Add(&context->textElementData, CLAY__INIT(Clay__TextElementData) { .text = text, .preferredDimensions = textMeasured->unwrappedDimensions, .elementIndex = context->layoutElements.length - 1 });
|
||||
textElement->elementConfigs = CLAY__INIT(Clay__ElementConfigArraySlice) {
|
||||
.length = 1,
|
||||
@ -2237,25 +2350,25 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||
for (int32_t childOffset = 0; childOffset < resizableContainerBuffer.length; childOffset++) {
|
||||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&resizableContainerBuffer, childOffset));
|
||||
Clay_SizingAxis childSizing = xAxis ? childElement->layoutConfig->sizing.width : childElement->layoutConfig->sizing.height;
|
||||
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
|
||||
}
|
||||
|
||||
// If we're laying out the children of a scroll panel, grow containers expand to the height of the inner content, not the outer container
|
||||
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_SCROLL)) {
|
||||
Clay_ScrollElementConfig *scrollElementConfig = Clay__FindElementConfigWithType(parent, CLAY__ELEMENT_CONFIG_TYPE_SCROLL).scrollElementConfig;
|
||||
if (((xAxis && scrollElementConfig->horizontal) || (!xAxis && scrollElementConfig->vertical))) {
|
||||
maxSize = CLAY__MAX(maxSize, innerContentSize);
|
||||
}
|
||||
}
|
||||
if (childSizing.type == CLAY__SIZING_TYPE_FIT) {
|
||||
*childSize = CLAY__MAX(childSizing.size.minMax.min, CLAY__MIN(*childSize, maxSize));
|
||||
} else if (childSizing.type == CLAY__SIZING_TYPE_GROW) {
|
||||
if (childSizing.type == CLAY__SIZING_TYPE_GROW) {
|
||||
*childSize = CLAY__MIN(maxSize, childSizing.size.minMax.max);
|
||||
}
|
||||
*childSize = CLAY__MAX(minSize, CLAY__MIN(*childSize, maxSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3698,10 +3811,10 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
|
||||
Clay_LayoutElementHashMapItem *mapItem = Clay__GetHashMapItem(currentElement->id); // TODO think of a way around this, maybe the fact that it's essentially a binary tree limits the cost, but the worst case is not great
|
||||
int32_t clipElementId = Clay__int32_tArray_GetValue(&context->layoutElementClipElementIds, (int32_t)(currentElement - context->layoutElements.internalArray));
|
||||
Clay_LayoutElementHashMapItem *clipItem = Clay__GetHashMapItem(clipElementId);
|
||||
if (mapItem) {
|
||||
Clay_BoundingBox elementBox = mapItem->boundingBox;
|
||||
elementBox.x -= root->pointerOffset.x;
|
||||
elementBox.y -= root->pointerOffset.y;
|
||||
if (mapItem) {
|
||||
if ((Clay__PointIsInsideRect(position, elementBox)) && (clipElementId == 0 || (Clay__PointIsInsideRect(position, clipItem->boundingBox)))) {
|
||||
if (mapItem->onHoverFunction) {
|
||||
mapItem->onHoverFunction(mapItem->elementId, context->pointerInfo, mapItem->hoverFunctionUserData);
|
||||
|
Loading…
Reference in New Issue
Block a user