mirror of
https://github.com/nicbarker/clay.git
synced 2025-09-18 12:36:17 +00:00
Merge branch 'main' into pull1
This commit is contained in:
commit
838bfae80a
|
@ -11,6 +11,7 @@ option(CLAY_INCLUDE_SDL2_EXAMPLES "Build SDL 2 examples" OFF)
|
||||||
option(CLAY_INCLUDE_SDL3_EXAMPLES "Build SDL 3 examples" OFF)
|
option(CLAY_INCLUDE_SDL3_EXAMPLES "Build SDL 3 examples" OFF)
|
||||||
option(CLAY_INCLUDE_WIN32_GDI_EXAMPLES "Build Win32 GDI examples" OFF)
|
option(CLAY_INCLUDE_WIN32_GDI_EXAMPLES "Build Win32 GDI examples" OFF)
|
||||||
option(CLAY_INCLUDE_SOKOL_EXAMPLES "Build Sokol examples" OFF)
|
option(CLAY_INCLUDE_SOKOL_EXAMPLES "Build Sokol examples" OFF)
|
||||||
|
option(CLAY_INCLUDE_PLAYDATE_EXAMPLES "Build Playdate examples" OFF)
|
||||||
|
|
||||||
message(STATUS "CLAY_INCLUDE_DEMOS: ${CLAY_INCLUDE_DEMOS}")
|
message(STATUS "CLAY_INCLUDE_DEMOS: ${CLAY_INCLUDE_DEMOS}")
|
||||||
|
|
||||||
|
@ -24,6 +25,7 @@ endif()
|
||||||
if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_DEMOS)
|
if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_DEMOS)
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
add_subdirectory("examples/clay-official-website")
|
add_subdirectory("examples/clay-official-website")
|
||||||
|
add_subdirectory("examples/terminal-example")
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory("examples/introducing-clay-video-demo")
|
add_subdirectory("examples/introducing-clay-video-demo")
|
||||||
endif ()
|
endif ()
|
||||||
|
@ -43,6 +45,11 @@ if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_SOKOL_EXAMPLES)
|
||||||
add_subdirectory("examples/sokol-corner-radius")
|
add_subdirectory("examples/sokol-corner-radius")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# Playdate example not included in ALL because users need to install the playdate SDK first which requires a license agreement
|
||||||
|
if(CLAY_INCLUDE_PLAYDATE_EXAMPLES)
|
||||||
|
add_subdirectory("examples/playdate-project-example")
|
||||||
|
endif()
|
||||||
|
|
||||||
if(WIN32) # Build only for Win or Wine
|
if(WIN32) # Build only for Win or Wine
|
||||||
if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_WIN32_GDI_EXAMPLES)
|
if(CLAY_INCLUDE_ALL_EXAMPLES OR CLAY_INCLUDE_WIN32_GDI_EXAMPLES)
|
||||||
add_subdirectory("examples/win32_gdi")
|
add_subdirectory("examples/win32_gdi")
|
||||||
|
|
145
README.md
145
README.md
|
@ -92,7 +92,7 @@ int main() {
|
||||||
.backgroundColor = COLOR_LIGHT
|
.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("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} }));
|
CLAY_TEXT(CLAY_STRING("Clay - UI Library"), CLAY_TEXT_CONFIG({ .fontSize = 24, .textColor = {255, 255, 255, 255} }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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 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
|
// Scrolling contents
|
||||||
}
|
}
|
||||||
// .childOffset can be provided directly if you would prefer to manage scrolling outside of clay
|
// .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
|
// Scrolling contents
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -489,6 +489,13 @@ There are also supported bindings for other languages, including:
|
||||||
- [Odin Bindings](https://github.com/nicbarker/clay/tree/main/bindings/odin)
|
- [Odin Bindings](https://github.com/nicbarker/clay/tree/main/bindings/odin)
|
||||||
- [Rust Bindings](https://github.com/clay-ui-rs/clay)
|
- [Rust Bindings](https://github.com/clay-ui-rs/clay)
|
||||||
|
|
||||||
|
### Other implementations
|
||||||
|
Clay has also been implemented in other languages:
|
||||||
|
|
||||||
|
- [`glay`](https://github.com/soypat/glay) - Go line-by-line rewrite with readability as main goal.
|
||||||
|
- [`totallygamerjet/clay`](https://github.com/totallygamerjet/clay) - Port using `cxgo`, a C to Go transpiler.
|
||||||
|
- [`goclay`](https://github.com/igadmg/goclay) - Go line-by-line rewrite closely matching the reference.
|
||||||
|
|
||||||
### Debug Tools
|
### Debug Tools
|
||||||
|
|
||||||
Clay includes built-in UI debugging tools, similar to the "inspector" in browsers such as Chrome or Firefox. These tools are included in `clay.h`, and work by injecting additional render commands into the output [Clay_RenderCommandArray](#clay_rendercommandarray).
|
Clay includes built-in UI debugging tools, similar to the "inspector" in browsers such as Chrome or Firefox. These tools are included in `clay.h`, and work by injecting additional render commands into the output [Clay_RenderCommandArray](#clay_rendercommandarray).
|
||||||
|
@ -832,7 +839,6 @@ Clay_TextElementConfig {
|
||||||
CLAY_TEXT_WRAP_NEWLINES,
|
CLAY_TEXT_WRAP_NEWLINES,
|
||||||
CLAY_TEXT_WRAP_NONE,
|
CLAY_TEXT_WRAP_NONE,
|
||||||
};
|
};
|
||||||
bool hashStringContents
|
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -892,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**
|
**Examples**
|
||||||
|
|
||||||
```C
|
```C
|
||||||
|
@ -1055,6 +1053,7 @@ typedef struct {
|
||||||
Clay_LayoutConfig layout;
|
Clay_LayoutConfig layout;
|
||||||
Clay_Color backgroundColor;
|
Clay_Color backgroundColor;
|
||||||
Clay_CornerRadius cornerRadius;
|
Clay_CornerRadius cornerRadius;
|
||||||
|
Clay_AspectRatioElementConfig aspectRatio;
|
||||||
Clay_ImageElementConfig image;
|
Clay_ImageElementConfig image;
|
||||||
Clay_FloatingElementConfig floating;
|
Clay_FloatingElementConfig floating;
|
||||||
Clay_CustomElementConfig custom;
|
Clay_CustomElementConfig custom;
|
||||||
|
@ -1101,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`
|
**`.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.
|
Uses [Clay_ImageElementConfig](#clay_imageelementconfig). Configures the element as an image element. Causes a render command with type `IMAGE` to be emitted.
|
||||||
|
|
||||||
|
@ -1287,23 +1294,12 @@ CLAY({ .id = CLAY_ID("Button"), .layout = { .layoutDirection = CLAY_TOP_TO_BOTTO
|
||||||
|
|
||||||
```C
|
```C
|
||||||
Clay_ImageElementConfig {
|
Clay_ImageElementConfig {
|
||||||
Clay_Dimensions sourceDimensions {
|
|
||||||
float width; float height;
|
|
||||||
};
|
|
||||||
void * imageData;
|
void * imageData;
|
||||||
};
|
};
|
||||||
```
|
```
|
||||||
|
|
||||||
**Fields**
|
**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 *`
|
**`.imageData`** - `void *`
|
||||||
|
|
||||||
`CLAY({ .image = { .imageData = &myImage } }) {}`
|
`CLAY({ .image = { .imageData = &myImage } }) {}`
|
||||||
|
@ -1314,7 +1310,7 @@ Used to perform **aspect ratio scaling** on the image element. As of this versio
|
||||||
// Load an image somewhere in your code
|
// Load an image somewhere in your code
|
||||||
YourImage profilePicture = LoadYourImage("profilePicture.png");
|
YourImage profilePicture = LoadYourImage("profilePicture.png");
|
||||||
// Note that when rendering, .imageData will be void* type.
|
// Note that when rendering, .imageData will be void* type.
|
||||||
CLAY({ .image = { .imageData = &profilePicture, .sourceDimensions = { 60, 60 } } }) {}
|
CLAY({ .image = { .imageData = &profilePicture } }) {}
|
||||||
```
|
```
|
||||||
|
|
||||||
**Examples**
|
**Examples**
|
||||||
|
@ -1323,11 +1319,105 @@ CLAY({ .image = { .imageData = &profilePicture, .sourceDimensions = { 60, 60 } }
|
||||||
// Load an image somewhere in your code
|
// Load an image somewhere in your code
|
||||||
YourImage profilePicture = LoadYourImage("profilePicture.png");
|
YourImage profilePicture = LoadYourImage("profilePicture.png");
|
||||||
// Declare a reusable image config
|
// 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
|
// Declare an image element using a reusable config
|
||||||
CLAY({ .image = imageConfig }) {}
|
CLAY({ .image = imageConfig }) {}
|
||||||
// Declare an image element using an inline config
|
// 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
|
// Rendering example
|
||||||
YourImage *imageToRender = renderCommand->elementConfig.imageElementConfig->imageData;
|
YourImage *imageToRender = renderCommand->elementConfig.imageElementConfig->imageData;
|
||||||
```
|
```
|
||||||
|
@ -2013,7 +2103,6 @@ typedef struct {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Clay_Color backgroundColor;
|
Clay_Color backgroundColor;
|
||||||
Clay_CornerRadius cornerRadius;
|
Clay_CornerRadius cornerRadius;
|
||||||
Clay_Dimensions sourceDimensions;
|
|
||||||
void* imageData;
|
void* imageData;
|
||||||
} Clay_ImageRenderData;
|
} Clay_ImageRenderData;
|
||||||
```
|
```
|
||||||
|
|
|
@ -41,10 +41,10 @@ error_handler :: proc "c" (errorData: clay.ErrorData) {
|
||||||
// Do something with the error data.
|
// Do something with the error data.
|
||||||
}
|
}
|
||||||
|
|
||||||
min_memory_size: u32 = clay.MinMemorySize()
|
min_memory_size := clay.MinMemorySize()
|
||||||
memory := make([^]u8, min_memory_size)
|
memory := make([^]u8, min_memory_size)
|
||||||
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(min_memory_size, memory)
|
arena: clay.Arena = clay.CreateArenaWithCapacityAndMemory(uint(min_memory_size), memory)
|
||||||
clay.Initialize(arena, { width = 1080, height = 720 }, { handler = error_handler })
|
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.
|
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
|
```Odin
|
||||||
// Update internal pointer position for handling mouseover / click / touch events
|
// Update internal pointer position for handling mouseover / click / touch events
|
||||||
clay.SetPointerState(
|
clay.SetPointerState(
|
||||||
clay.Vector2 { mouse_pos_x, mouse_pos_y },
|
{ mouse_pos_x, mouse_pos_y },
|
||||||
is_mouse_down,
|
is_mouse_down,
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
@ -148,6 +148,7 @@ create_layout :: proc() -> clay.ClayArray(clay.RenderCommand) {
|
||||||
sizing = { width = clay.SizingFixed(60), height = clay.SizingFixed(60) },
|
sizing = { width = clay.SizingFixed(60), height = clay.SizingFixed(60) },
|
||||||
},
|
},
|
||||||
image = {
|
image = {
|
||||||
|
// How you define `profile_picture` depends on your renderer.
|
||||||
imageData = &profile_picture,
|
imageData = &profile_picture,
|
||||||
sourceDimensions = {
|
sourceDimensions = {
|
||||||
width = 60,
|
width = 60,
|
||||||
|
@ -179,8 +180,7 @@ create_layout :: proc() -> clay.ClayArray(clay.RenderCommand) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns a list of render commands
|
// Returns a list of render commands
|
||||||
render_commands: clay.ClayArray(clay.RenderCommand) = clay.EndLayout()
|
return clay.EndLayout()
|
||||||
return render_commands
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
@ -113,9 +113,12 @@ TextElementConfig :: struct {
|
||||||
textAlignment: TextAlignment,
|
textAlignment: TextAlignment,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AspectRatioElementConfig :: struct {
|
||||||
|
aspectRatio: f32,
|
||||||
|
}
|
||||||
|
|
||||||
ImageElementConfig :: struct {
|
ImageElementConfig :: struct {
|
||||||
imageData: rawptr,
|
imageData: rawptr,
|
||||||
sourceDimensions: Dimensions,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomElementConfig :: struct {
|
CustomElementConfig :: struct {
|
||||||
|
@ -170,6 +173,11 @@ FloatingAttachToElement :: enum EnumBackingType {
|
||||||
Root,
|
Root,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FloatingClipToElement :: enum EnumBackingType {
|
||||||
|
None,
|
||||||
|
AttachedParent,
|
||||||
|
}
|
||||||
|
|
||||||
FloatingElementConfig :: struct {
|
FloatingElementConfig :: struct {
|
||||||
offset: Vector2,
|
offset: Vector2,
|
||||||
expand: Dimensions,
|
expand: Dimensions,
|
||||||
|
@ -178,6 +186,7 @@ FloatingElementConfig :: struct {
|
||||||
attachment: FloatingAttachPoints,
|
attachment: FloatingAttachPoints,
|
||||||
pointerCaptureMode: PointerCaptureMode,
|
pointerCaptureMode: PointerCaptureMode,
|
||||||
attachTo: FloatingAttachToElement,
|
attachTo: FloatingAttachToElement,
|
||||||
|
clipTo: FloatingClipToElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
TextRenderData :: struct {
|
TextRenderData :: struct {
|
||||||
|
@ -197,7 +206,6 @@ RectangleRenderData :: struct {
|
||||||
ImageRenderData :: struct {
|
ImageRenderData :: struct {
|
||||||
backgroundColor: Color,
|
backgroundColor: Color,
|
||||||
cornerRadius: CornerRadius,
|
cornerRadius: CornerRadius,
|
||||||
sourceDimensions: Dimensions,
|
|
||||||
imageData: rawptr,
|
imageData: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -334,6 +342,7 @@ ElementDeclaration :: struct {
|
||||||
layout: LayoutConfig,
|
layout: LayoutConfig,
|
||||||
backgroundColor: Color,
|
backgroundColor: Color,
|
||||||
cornerRadius: CornerRadius,
|
cornerRadius: CornerRadius,
|
||||||
|
aspectRatio: AspectRatioElementConfig,
|
||||||
image: ImageElementConfig,
|
image: ImageElementConfig,
|
||||||
floating: FloatingElementConfig,
|
floating: FloatingElementConfig,
|
||||||
custom: CustomElementConfig,
|
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()({
|
if clay.UI()({
|
||||||
id = clay.ID("CheckImage", index),
|
id = clay.ID("CheckImage", index),
|
||||||
layout = { sizing = { width = clay.SizingFixed(32) } },
|
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}))
|
clay.Text(text, clay.TextConfig({fontSize = fontSize, fontId = fontId, textColor = color}))
|
||||||
}
|
}
|
||||||
|
@ -213,7 +214,8 @@ DeclarativeSyntaxPage :: proc(titleTextConfig: clay.TextElementConfig, widthSizi
|
||||||
if clay.UI()({
|
if clay.UI()({
|
||||||
id = clay.ID("SyntaxPageRightImageInner"),
|
id = clay.ID("SyntaxPageRightImageInner"),
|
||||||
layout = { sizing = { width = clay.SizingGrow({ max = 568 }) } },
|
layout = { sizing = { width = clay.SizingGrow({ max = 568 }) } },
|
||||||
image = { imageData = &syntaxImage, sourceDimensions = { 1136, 1194 } },
|
aspectRatio = { 1136.0 / 1194.0 },
|
||||||
|
image = { imageData = &syntaxImage },
|
||||||
}) {}
|
}) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
183
clay.h
183
clay.h
|
@ -1,4 +1,4 @@
|
||||||
// VERSION: 0.13
|
// VERSION: 0.14
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NOTE: In order to use this library you must define
|
NOTE: In order to use this library you must define
|
||||||
|
@ -184,7 +184,7 @@ extern "C" {
|
||||||
|
|
||||||
// Note: Clay_String is not guaranteed to be null terminated. It may be if created from a literal C string,
|
// 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.
|
// 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.
|
// 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.
|
// This will automatically be set for strings created with CLAY_STRING, as the macro requires a string literal.
|
||||||
bool isStaticallyAllocated;
|
bool isStaticallyAllocated;
|
||||||
|
@ -195,7 +195,7 @@ typedef struct {
|
||||||
|
|
||||||
// Clay_StringSlice is used to represent non owning string slices, and includes
|
// 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.
|
// a baseChars field which points to the string this slice is derived from.
|
||||||
typedef struct {
|
typedef struct Clay_StringSlice {
|
||||||
int32_t length;
|
int32_t length;
|
||||||
const char *chars;
|
const char *chars;
|
||||||
const char *baseChars; // The source string / char* that this slice was derived from
|
const char *baseChars; // The source string / char* that this slice was derived from
|
||||||
|
@ -205,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.
|
// 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()
|
// Rather than creating it by hand, it's easier to use Clay_CreateArenaWithCapacityAndMemory()
|
||||||
typedef struct {
|
typedef struct Clay_Arena {
|
||||||
uintptr_t nextAllocation;
|
uintptr_t nextAllocation;
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
char *memory;
|
char *memory;
|
||||||
} Clay_Arena;
|
} Clay_Arena;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct Clay_Dimensions {
|
||||||
float width, height;
|
float width, height;
|
||||||
} Clay_Dimensions;
|
} Clay_Dimensions;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct Clay_Vector2 {
|
||||||
float x, y;
|
float x, y;
|
||||||
} Clay_Vector2;
|
} Clay_Vector2;
|
||||||
|
|
||||||
// Internally clay conventionally represents colors as 0-255, but interpretation is up to the renderer.
|
// 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;
|
float r, g, b, a;
|
||||||
} Clay_Color;
|
} Clay_Color;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct Clay_BoundingBox {
|
||||||
float x, y, width, height;
|
float x, y, width, height;
|
||||||
} Clay_BoundingBox;
|
} Clay_BoundingBox;
|
||||||
|
|
||||||
// Primarily created via the CLAY_ID(), CLAY_IDI(), CLAY_ID_LOCAL() and CLAY_IDI_LOCAL() macros.
|
// 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
|
// Represents a hashed string ID used for identifying and finding specific clay UI elements, required
|
||||||
// by functions such as Clay_PointerOver() and Clay_GetElementData().
|
// 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 id; // The resulting hash generated from the other fields.
|
||||||
uint32_t offset; // A numerical offset applied after computing the hash from stringId.
|
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().
|
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 +248,7 @@ typedef struct
|
||||||
|
|
||||||
// Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
|
// 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.
|
// 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 topLeft;
|
||||||
float topRight;
|
float topRight;
|
||||||
float bottomLeft;
|
float bottomLeft;
|
||||||
|
@ -298,20 +298,20 @@ typedef CLAY_PACKED_ENUM {
|
||||||
} Clay__SizingType;
|
} Clay__SizingType;
|
||||||
|
|
||||||
// Controls how child elements are aligned on each axis.
|
// 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_LayoutAlignmentX x; // Controls alignment of children along the x axis.
|
||||||
Clay_LayoutAlignmentY y; // Controls alignment of children along the y axis.
|
Clay_LayoutAlignmentY y; // Controls alignment of children along the y axis.
|
||||||
} Clay_ChildAlignment;
|
} Clay_ChildAlignment;
|
||||||
|
|
||||||
// Controls the minimum and maximum size in pixels that this element is allowed to grow or shrink to,
|
// 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.
|
// 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 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.
|
float max; // The largest final size of the element on this axis will be this value in pixels.
|
||||||
} Clay_SizingMinMax;
|
} Clay_SizingMinMax;
|
||||||
|
|
||||||
// Controls the sizing of this element along one axis inside its parent container.
|
// Controls the sizing of this element along one axis inside its parent container.
|
||||||
typedef struct {
|
typedef struct Clay_SizingAxis {
|
||||||
union {
|
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.
|
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.
|
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 +320,14 @@ typedef struct {
|
||||||
} Clay_SizingAxis;
|
} Clay_SizingAxis;
|
||||||
|
|
||||||
// Controls the sizing of this element along one axis inside its parent container.
|
// 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 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_SizingAxis height; // Controls the height sizing of the element, along the y axis.
|
||||||
} Clay_Sizing;
|
} Clay_Sizing;
|
||||||
|
|
||||||
// Controls "padding" in pixels, which is a gap between the bounding box of this element and where its children
|
// Controls "padding" in pixels, which is a gap between the bounding box of this element and where its children
|
||||||
// will be placed.
|
// will be placed.
|
||||||
typedef struct {
|
typedef struct Clay_Padding {
|
||||||
uint16_t left;
|
uint16_t left;
|
||||||
uint16_t right;
|
uint16_t right;
|
||||||
uint16_t top;
|
uint16_t top;
|
||||||
|
@ -338,7 +338,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
|
// Controls various settings that affect the size and position of an element, as well as the sizes and positions
|
||||||
// of any child elements.
|
// 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_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.
|
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).
|
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 +371,7 @@ typedef CLAY_PACKED_ENUM {
|
||||||
} Clay_TextAlignment;
|
} Clay_TextAlignment;
|
||||||
|
|
||||||
// Controls various functionality related to text elements.
|
// 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.
|
// A pointer that will be transparently passed through to the resulting render command.
|
||||||
void *userData;
|
void *userData;
|
||||||
// The RGBA color of the font to render, conventionally specified as 0-255.
|
// The RGBA color of the font to render, conventionally specified as 0-255.
|
||||||
|
@ -399,12 +399,20 @@ typedef struct {
|
||||||
|
|
||||||
CLAY__WRAPPER_STRUCT(Clay_TextElementConfig);
|
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 --------------------------------
|
// Image --------------------------------
|
||||||
|
|
||||||
// Controls various settings related to image elements.
|
// 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.
|
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_ImageElementConfig;
|
||||||
|
|
||||||
CLAY__WRAPPER_STRUCT(Clay_ImageElementConfig);
|
CLAY__WRAPPER_STRUCT(Clay_ImageElementConfig);
|
||||||
|
@ -426,7 +434,7 @@ typedef CLAY_PACKED_ENUM {
|
||||||
} Clay_FloatingAttachPointType;
|
} Clay_FloatingAttachPointType;
|
||||||
|
|
||||||
// Controls where a floating element is offset relative to its parent element.
|
// 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 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_FloatingAttachPointType parent; // Controls the origin point on the parent element that the floating element attaches to.
|
||||||
} Clay_FloatingAttachPoints;
|
} Clay_FloatingAttachPoints;
|
||||||
|
@ -463,7 +471,7 @@ typedef CLAY_PACKED_ENUM {
|
||||||
|
|
||||||
// Controls various settings related to "floating" elements, which are elements that "float" above other elements, potentially overlapping their boundaries,
|
// 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.
|
// 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.
|
// Offsets this floating element by the provided x,y coordinates from its attachPoints.
|
||||||
Clay_Vector2 offset;
|
Clay_Vector2 offset;
|
||||||
// Expands the boundaries of the outer floating element without affecting its children.
|
// Expands the boundaries of the outer floating element without affecting its children.
|
||||||
|
@ -500,7 +508,7 @@ CLAY__WRAPPER_STRUCT(Clay_FloatingElementConfig);
|
||||||
// Custom -----------------------------
|
// Custom -----------------------------
|
||||||
|
|
||||||
// Controls various settings related to custom elements.
|
// 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.
|
// A transparent pointer through which you can pass custom data to the renderer.
|
||||||
// Generates CUSTOM render commands.
|
// Generates CUSTOM render commands.
|
||||||
void* customData;
|
void* customData;
|
||||||
|
@ -511,7 +519,7 @@ CLAY__WRAPPER_STRUCT(Clay_CustomElementConfig);
|
||||||
// Scroll -----------------------------
|
// Scroll -----------------------------
|
||||||
|
|
||||||
// Controls the axis on which an element switches to "scrolling", which clips the contents and allows scrolling in that direction.
|
// 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 horizontal; // Clip overflowing elements on the X axis.
|
||||||
bool vertical; // Clip overflowing elements on the Y 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.
|
Clay_Vector2 childOffset; // Offsets the x,y positions of all child elements. Used primarily for scrolling containers.
|
||||||
|
@ -522,7 +530,7 @@ CLAY__WRAPPER_STRUCT(Clay_ClipElementConfig);
|
||||||
// Border -----------------------------
|
// Border -----------------------------
|
||||||
|
|
||||||
// Controls the widths of individual element borders.
|
// Controls the widths of individual element borders.
|
||||||
typedef struct {
|
typedef struct Clay_BorderWidth {
|
||||||
uint16_t left;
|
uint16_t left;
|
||||||
uint16_t right;
|
uint16_t right;
|
||||||
uint16_t top;
|
uint16_t top;
|
||||||
|
@ -534,7 +542,7 @@ typedef struct {
|
||||||
} Clay_BorderWidth;
|
} Clay_BorderWidth;
|
||||||
|
|
||||||
// Controls settings related to element borders.
|
// 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_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_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;
|
} Clay_BorderElementConfig;
|
||||||
|
@ -544,7 +552,7 @@ CLAY__WRAPPER_STRUCT(Clay_BorderElementConfig);
|
||||||
// Render Command Data -----------------------------
|
// Render Command Data -----------------------------
|
||||||
|
|
||||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT
|
// 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.
|
// A string slice containing the text to be rendered.
|
||||||
// Note: this is not guaranteed to be null terminated.
|
// Note: this is not guaranteed to be null terminated.
|
||||||
Clay_StringSlice stringContents;
|
Clay_StringSlice stringContents;
|
||||||
|
@ -560,7 +568,7 @@ typedef struct {
|
||||||
} Clay_TextRenderData;
|
} Clay_TextRenderData;
|
||||||
|
|
||||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_RECTANGLE
|
// 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.
|
// 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;
|
Clay_Color backgroundColor;
|
||||||
// Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
|
// Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
|
||||||
|
@ -569,7 +577,7 @@ typedef struct {
|
||||||
} Clay_RectangleRenderData;
|
} Clay_RectangleRenderData;
|
||||||
|
|
||||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_IMAGE
|
// 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
|
// The tint color for this image. Note that the default value is 0,0,0,0 and should likely be interpreted
|
||||||
// as "untinted".
|
// as "untinted".
|
||||||
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
|
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
|
||||||
|
@ -577,14 +585,12 @@ typedef struct {
|
||||||
// Controls the "radius", or corner rounding of this image.
|
// 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.
|
// The rounding is determined by drawing a circle inset into the element corner by (radius, radius) pixels.
|
||||||
Clay_CornerRadius cornerRadius;
|
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.
|
// A pointer transparently passed through from the original element definition, typically used to represent image data.
|
||||||
void* imageData;
|
void* imageData;
|
||||||
} Clay_ImageRenderData;
|
} Clay_ImageRenderData;
|
||||||
|
|
||||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_CUSTOM
|
// 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.
|
// Passed through from .backgroundColor in the original element declaration.
|
||||||
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
|
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
|
||||||
Clay_Color backgroundColor;
|
Clay_Color backgroundColor;
|
||||||
|
@ -596,13 +602,13 @@ typedef struct {
|
||||||
} Clay_CustomRenderData;
|
} Clay_CustomRenderData;
|
||||||
|
|
||||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_START || commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_END
|
// 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 horizontal;
|
||||||
bool vertical;
|
bool vertical;
|
||||||
} Clay_ClipRenderData;
|
} Clay_ClipRenderData;
|
||||||
|
|
||||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_BORDER
|
// 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.
|
// 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.
|
// Conventionally represented as 0-255 for each channel, but interpretation is up to the renderer.
|
||||||
Clay_Color color;
|
Clay_Color color;
|
||||||
|
@ -614,7 +620,7 @@ typedef struct {
|
||||||
} Clay_BorderRenderData;
|
} Clay_BorderRenderData;
|
||||||
|
|
||||||
// A struct union containing data specific to this command's .commandType
|
// 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
|
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_RECTANGLE
|
||||||
Clay_RectangleRenderData rectangle;
|
Clay_RectangleRenderData rectangle;
|
||||||
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT
|
// Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_TEXT
|
||||||
|
@ -632,7 +638,7 @@ typedef union {
|
||||||
// Miscellaneous Structs & Enums ---------------------------------
|
// Miscellaneous Structs & Enums ---------------------------------
|
||||||
|
|
||||||
// Data representing the current internal state of a scrolling element.
|
// 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.
|
// 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.
|
// Intended for use with external functionality that modifies scroll position, such as scroll bars or auto scrolling.
|
||||||
Clay_Vector2 *scrollPosition;
|
Clay_Vector2 *scrollPosition;
|
||||||
|
@ -647,7 +653,7 @@ typedef struct {
|
||||||
} Clay_ScrollContainerData;
|
} Clay_ScrollContainerData;
|
||||||
|
|
||||||
// Bounding box and other data for a specific UI element.
|
// 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.
|
// The rectangle that encloses this UI element, with the position relative to the root of the layout.
|
||||||
Clay_BoundingBox boundingBox;
|
Clay_BoundingBox boundingBox;
|
||||||
// Indicates whether an actual Element matched the provided ID or if the default struct was returned.
|
// Indicates whether an actual Element matched the provided ID or if the default struct was returned.
|
||||||
|
@ -674,7 +680,7 @@ typedef CLAY_PACKED_ENUM {
|
||||||
CLAY_RENDER_COMMAND_TYPE_CUSTOM,
|
CLAY_RENDER_COMMAND_TYPE_CUSTOM,
|
||||||
} Clay_RenderCommandType;
|
} 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.
|
// A rectangular box that fully encloses this UI element, with the position relative to the root of the layout.
|
||||||
Clay_BoundingBox boundingBox;
|
Clay_BoundingBox boundingBox;
|
||||||
// A struct union containing data specific to this command's commandType.
|
// A struct union containing data specific to this command's commandType.
|
||||||
|
@ -699,7 +705,7 @@ typedef struct {
|
||||||
} Clay_RenderCommand;
|
} Clay_RenderCommand;
|
||||||
|
|
||||||
// A sized array of render commands.
|
// A sized array of render commands.
|
||||||
typedef struct {
|
typedef struct Clay_RenderCommandArray {
|
||||||
// The underlying max capacity of the array, not necessarily all initialized.
|
// The underlying max capacity of the array, not necessarily all initialized.
|
||||||
int32_t capacity;
|
int32_t capacity;
|
||||||
// The number of initialized elements in this array. Used for loops and iteration.
|
// The number of initialized elements in this array. Used for loops and iteration.
|
||||||
|
@ -721,7 +727,7 @@ typedef CLAY_PACKED_ENUM {
|
||||||
} Clay_PointerDataInteractionState;
|
} Clay_PointerDataInteractionState;
|
||||||
|
|
||||||
// Information on the current state of pointer interactions this frame.
|
// 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.
|
// The position of the mouse / touch / pointer relative to the root of the layout.
|
||||||
Clay_Vector2 position;
|
Clay_Vector2 position;
|
||||||
// Represents the current state of interaction with clay this frame.
|
// Represents the current state of interaction with clay this frame.
|
||||||
|
@ -732,7 +738,7 @@ typedef struct {
|
||||||
Clay_PointerDataInteractionState state;
|
Clay_PointerDataInteractionState state;
|
||||||
} Clay_PointerData;
|
} Clay_PointerData;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct Clay_ElementDeclaration {
|
||||||
// Primarily created via the CLAY_ID(), CLAY_IDI(), CLAY_ID_LOCAL() and CLAY_IDI_LOCAL() macros.
|
// 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().
|
// 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;
|
Clay_ElementId id;
|
||||||
|
@ -744,6 +750,8 @@ typedef struct {
|
||||||
Clay_Color backgroundColor;
|
Clay_Color backgroundColor;
|
||||||
// Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
|
// Controls the "radius", or corner rounding of elements, including rectangles, borders and images.
|
||||||
Clay_CornerRadius cornerRadius;
|
Clay_CornerRadius cornerRadius;
|
||||||
|
// Controls settings related to aspect ratio scaling.
|
||||||
|
Clay_AspectRatioElementConfig aspectRatio;
|
||||||
// Controls settings related to image elements.
|
// Controls settings related to image elements.
|
||||||
Clay_ImageElementConfig image;
|
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.
|
// 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 +791,7 @@ typedef CLAY_PACKED_ENUM {
|
||||||
} Clay_ErrorType;
|
} Clay_ErrorType;
|
||||||
|
|
||||||
// Data to identify the error that clay has encountered.
|
// 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.
|
// 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_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().
|
// 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 +1066,7 @@ CLAY__ARRAY_DEFINE(char, Clay__charArray)
|
||||||
CLAY__ARRAY_DEFINE_FUNCTIONS(Clay_ElementId, Clay_ElementIdArray)
|
CLAY__ARRAY_DEFINE_FUNCTIONS(Clay_ElementId, Clay_ElementIdArray)
|
||||||
CLAY__ARRAY_DEFINE(Clay_LayoutConfig, Clay__LayoutConfigArray)
|
CLAY__ARRAY_DEFINE(Clay_LayoutConfig, Clay__LayoutConfigArray)
|
||||||
CLAY__ARRAY_DEFINE(Clay_TextElementConfig, Clay__TextElementConfigArray)
|
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_ImageElementConfig, Clay__ImageElementConfigArray)
|
||||||
CLAY__ARRAY_DEFINE(Clay_FloatingElementConfig, Clay__FloatingElementConfigArray)
|
CLAY__ARRAY_DEFINE(Clay_FloatingElementConfig, Clay__FloatingElementConfigArray)
|
||||||
CLAY__ARRAY_DEFINE(Clay_CustomElementConfig, Clay__CustomElementConfigArray)
|
CLAY__ARRAY_DEFINE(Clay_CustomElementConfig, Clay__CustomElementConfigArray)
|
||||||
|
@ -1072,6 +1081,7 @@ typedef CLAY_PACKED_ENUM {
|
||||||
CLAY__ELEMENT_CONFIG_TYPE_BORDER,
|
CLAY__ELEMENT_CONFIG_TYPE_BORDER,
|
||||||
CLAY__ELEMENT_CONFIG_TYPE_FLOATING,
|
CLAY__ELEMENT_CONFIG_TYPE_FLOATING,
|
||||||
CLAY__ELEMENT_CONFIG_TYPE_CLIP,
|
CLAY__ELEMENT_CONFIG_TYPE_CLIP,
|
||||||
|
CLAY__ELEMENT_CONFIG_TYPE_ASPECT,
|
||||||
CLAY__ELEMENT_CONFIG_TYPE_IMAGE,
|
CLAY__ELEMENT_CONFIG_TYPE_IMAGE,
|
||||||
CLAY__ELEMENT_CONFIG_TYPE_TEXT,
|
CLAY__ELEMENT_CONFIG_TYPE_TEXT,
|
||||||
CLAY__ELEMENT_CONFIG_TYPE_CUSTOM,
|
CLAY__ELEMENT_CONFIG_TYPE_CUSTOM,
|
||||||
|
@ -1080,6 +1090,7 @@ typedef CLAY_PACKED_ENUM {
|
||||||
|
|
||||||
typedef union {
|
typedef union {
|
||||||
Clay_TextElementConfig *textElementConfig;
|
Clay_TextElementConfig *textElementConfig;
|
||||||
|
Clay_AspectRatioElementConfig *aspectRatioElementConfig;
|
||||||
Clay_ImageElementConfig *imageElementConfig;
|
Clay_ImageElementConfig *imageElementConfig;
|
||||||
Clay_FloatingElementConfig *floatingElementConfig;
|
Clay_FloatingElementConfig *floatingElementConfig;
|
||||||
Clay_CustomElementConfig *customElementConfig;
|
Clay_CustomElementConfig *customElementConfig;
|
||||||
|
@ -1236,13 +1247,14 @@ struct Clay_Context {
|
||||||
Clay__int32_tArray layoutElementChildren;
|
Clay__int32_tArray layoutElementChildren;
|
||||||
Clay__int32_tArray layoutElementChildrenBuffer;
|
Clay__int32_tArray layoutElementChildrenBuffer;
|
||||||
Clay__TextElementDataArray textElementData;
|
Clay__TextElementDataArray textElementData;
|
||||||
Clay__int32_tArray imageElementPointers;
|
Clay__int32_tArray aspectRatioElementIndexes;
|
||||||
Clay__int32_tArray reusableElementIndexBuffer;
|
Clay__int32_tArray reusableElementIndexBuffer;
|
||||||
Clay__int32_tArray layoutElementClipElementIds;
|
Clay__int32_tArray layoutElementClipElementIds;
|
||||||
// Configs
|
// Configs
|
||||||
Clay__LayoutConfigArray layoutConfigs;
|
Clay__LayoutConfigArray layoutConfigs;
|
||||||
Clay__ElementConfigArray elementConfigs;
|
Clay__ElementConfigArray elementConfigs;
|
||||||
Clay__TextElementConfigArray textElementConfigs;
|
Clay__TextElementConfigArray textElementConfigs;
|
||||||
|
Clay__AspectRatioElementConfigArray aspectRatioElementConfigs;
|
||||||
Clay__ImageElementConfigArray imageElementConfigs;
|
Clay__ImageElementConfigArray imageElementConfigs;
|
||||||
Clay__FloatingElementConfigArray floatingElementConfigs;
|
Clay__FloatingElementConfigArray floatingElementConfigs;
|
||||||
Clay__ClipElementConfigArray clipElementConfigs;
|
Clay__ClipElementConfigArray clipElementConfigs;
|
||||||
|
@ -1310,6 +1322,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_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_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_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_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); }
|
Clay_CustomElementConfig * Clay__StoreCustomElementConfig(Clay_CustomElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_CustomElementConfig_DEFAULT : Clay__CustomElementConfigArray_Add(&Clay_GetCurrentContext()->customElementConfigs, config); }
|
||||||
|
@ -1483,7 +1496,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 Clay__HashData(const uint8_t* data, size_t length) {
|
||||||
uint64_t hash = 0;
|
uint64_t hash = 0;
|
||||||
|
|
||||||
for (int32_t i = 0; i < length; i++) {
|
for (size_t i = 0; i < length; i++) {
|
||||||
hash += data[i];
|
hash += data[i];
|
||||||
hash += (hash << 10);
|
hash += (hash << 10);
|
||||||
hash ^= (hash >> 6);
|
hash ^= (hash >> 6);
|
||||||
|
@ -1661,7 +1674,7 @@ Clay__MeasureTextCacheItem *Clay__MeasureTextCached(Clay_String *text, Clay_Text
|
||||||
measuredHeight = CLAY__MAX(measuredHeight, dimensions.height);
|
measuredHeight = CLAY__MAX(measuredHeight, dimensions.height);
|
||||||
measured->minWidth = CLAY__MAX(dimensions.width, measured->minWidth);
|
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->measuredWordsStartIndex = tempWord.next;
|
||||||
measured->unwrappedDimensions.width = measuredWidth;
|
measured->unwrappedDimensions.width = measuredWidth;
|
||||||
|
@ -1760,16 +1773,15 @@ bool Clay__ElementHasConfig(Clay_LayoutElement *layoutElement, Clay__ElementConf
|
||||||
void Clay__UpdateAspectRatioBox(Clay_LayoutElement *layoutElement) {
|
void Clay__UpdateAspectRatioBox(Clay_LayoutElement *layoutElement) {
|
||||||
for (int32_t j = 0; j < layoutElement->elementConfigs.length; j++) {
|
for (int32_t j = 0; j < layoutElement->elementConfigs.length; j++) {
|
||||||
Clay_ElementConfig *config = Clay__ElementConfigArraySlice_Get(&layoutElement->elementConfigs, j);
|
Clay_ElementConfig *config = Clay__ElementConfigArraySlice_Get(&layoutElement->elementConfigs, j);
|
||||||
if (config->type == CLAY__ELEMENT_CONFIG_TYPE_IMAGE) {
|
if (config->type == CLAY__ELEMENT_CONFIG_TYPE_ASPECT) {
|
||||||
Clay_ImageElementConfig *imageConfig = config->config.imageElementConfig;
|
Clay_AspectRatioElementConfig *aspectConfig = config->config.aspectRatioElementConfig;
|
||||||
if (imageConfig->sourceDimensions.width == 0 || imageConfig->sourceDimensions.height == 0) {
|
if (aspectConfig->aspectRatio == 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
float aspect = imageConfig->sourceDimensions.width / imageConfig->sourceDimensions.height;
|
|
||||||
if (layoutElement->dimensions.width == 0 && layoutElement->dimensions.height != 0) {
|
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) {
|
} 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;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2048,7 +2060,10 @@ void Clay__ConfigureOpenElementPtr(const Clay_ElementDeclaration *declaration) {
|
||||||
}
|
}
|
||||||
if (declaration->image.imageData) {
|
if (declaration->image.imageData) {
|
||||||
Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .imageElementConfig = Clay__StoreImageElementConfig(declaration->image) }, CLAY__ELEMENT_CONFIG_TYPE_IMAGE);
|
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) {
|
if (declaration->floating.attachTo != CLAY_ATTACH_TO_NONE) {
|
||||||
Clay_FloatingElementConfig floatingConfig = declaration->floating;
|
Clay_FloatingElementConfig floatingConfig = declaration->floating;
|
||||||
|
@ -2145,6 +2160,7 @@ void Clay__InitializeEphemeralMemory(Clay_Context* context) {
|
||||||
context->layoutConfigs = Clay__LayoutConfigArray_Allocate_Arena(maxElementCount, arena);
|
context->layoutConfigs = Clay__LayoutConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||||
context->elementConfigs = Clay__ElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
context->elementConfigs = Clay__ElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||||
context->textElementConfigs = Clay__TextElementConfigArray_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->imageElementConfigs = Clay__ImageElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||||
context->floatingElementConfigs = Clay__FloatingElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
context->floatingElementConfigs = Clay__FloatingElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||||
context->clipElementConfigs = Clay__ClipElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
context->clipElementConfigs = Clay__ClipElementConfigArray_Allocate_Arena(maxElementCount, arena);
|
||||||
|
@ -2159,7 +2175,7 @@ void Clay__InitializeEphemeralMemory(Clay_Context* context) {
|
||||||
context->layoutElementChildren = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
|
context->layoutElementChildren = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
|
||||||
context->openLayoutElementStack = 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->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->renderCommands = Clay_RenderCommandArray_Allocate_Arena(maxElementCount, arena);
|
||||||
context->treeNodeVisited = Clay__boolArray_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
|
context->treeNodeVisited.length = context->treeNodeVisited.capacity; // This array is accessed directly rather than behaving as a list
|
||||||
|
@ -2248,7 +2264,7 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||||
if (childSizing.type != CLAY__SIZING_TYPE_PERCENT
|
if (childSizing.type != CLAY__SIZING_TYPE_PERCENT
|
||||||
&& childSizing.type != CLAY__SIZING_TYPE_FIXED
|
&& 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
|
&& (!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);
|
Clay__int32_tArray_Add(&resizableContainerBuffer, childElementIndex);
|
||||||
}
|
}
|
||||||
|
@ -2287,9 +2303,9 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||||
// The content is too large, compress the children as much as possible
|
// The content is too large, compress the children as much as possible
|
||||||
if (sizeToDistribute < 0) {
|
if (sizeToDistribute < 0) {
|
||||||
// If the parent clips content in this axis direction, don't compress children, just leave them alone
|
// 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;
|
Clay_ClipElementConfig *clipElementConfig = Clay__FindElementConfigWithType(parent, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig;
|
||||||
if (scrollElementConfig) {
|
if (clipElementConfig) {
|
||||||
if (((xAxis && scrollElementConfig->horizontal) || (!xAxis && scrollElementConfig->vertical))) {
|
if (((xAxis && clipElementConfig->horizontal) || (!xAxis && clipElementConfig->vertical))) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2382,10 +2398,6 @@ void Clay__SizeContainersAlongAxis(bool xAxis) {
|
||||||
float minSize = xAxis ? childElement->minDimensions.width : childElement->minDimensions.height;
|
float minSize = xAxis ? childElement->minDimensions.width : childElement->minDimensions.height;
|
||||||
float *childSize = xAxis ? &childElement->dimensions.width : &childElement->dimensions.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;
|
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 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)) {
|
if (Clay__ElementHasConfig(parent, CLAY__ELEMENT_CONFIG_TYPE_CLIP)) {
|
||||||
|
@ -2510,26 +2522,27 @@ void Clay__CalculateFinalLayout(void) {
|
||||||
lineLengthChars = 0;
|
lineLengthChars = 0;
|
||||||
lineStartOffset = measuredWord->startOffset;
|
lineStartOffset = measuredWord->startOffset;
|
||||||
} else {
|
} else {
|
||||||
lineWidth += measuredWord->width;
|
lineWidth += measuredWord->width + textConfig->letterSpacing;
|
||||||
lineLengthChars += measuredWord->length;
|
lineLengthChars += measuredWord->length;
|
||||||
wordIndex = measuredWord->next;
|
wordIndex = measuredWord->next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (lineLengthChars > 0) {
|
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++;
|
textElementData->wrappedLines.length++;
|
||||||
}
|
}
|
||||||
containerElement->dimensions.height = lineHeight * (float)textElementData->wrappedLines.length;
|
containerElement->dimensions.height = lineHeight * (float)textElementData->wrappedLines.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scale vertical image heights according to aspect ratio
|
// Scale vertical heights according to aspect ratio
|
||||||
for (int32_t i = 0; i < context->imageElementPointers.length; ++i) {
|
for (int32_t i = 0; i < context->aspectRatioElementIndexes.length; ++i) {
|
||||||
Clay_LayoutElement* imageElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&context->imageElementPointers, i));
|
Clay_LayoutElement* aspectElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&context->aspectRatioElementIndexes, i));
|
||||||
Clay_ImageElementConfig *config = Clay__FindElementConfigWithType(imageElement, CLAY__ELEMENT_CONFIG_TYPE_IMAGE).imageElementConfig;
|
Clay_AspectRatioElementConfig *config = Clay__FindElementConfigWithType(aspectElement, CLAY__ELEMENT_CONFIG_TYPE_ASPECT).aspectRatioElementConfig;
|
||||||
imageElement->dimensions.height = (config->sourceDimensions.height / CLAY__MAX(config->sourceDimensions.width, 1)) * imageElement->dimensions.width;
|
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;
|
Clay__LayoutElementTreeNodeArray dfsBuffer = context->layoutElementTreeNodeArray1;
|
||||||
dfsBuffer.length = 0;
|
dfsBuffer.length = 0;
|
||||||
for (int32_t i = 0; i < context->layoutElementTreeRoots.length; ++i) {
|
for (int32_t i = 0; i < context->layoutElementTreeRoots.length; ++i) {
|
||||||
|
@ -2580,6 +2593,13 @@ void Clay__CalculateFinalLayout(void) {
|
||||||
// Calculate sizing along the Y axis
|
// Calculate sizing along the Y axis
|
||||||
Clay__SizeContainersAlongAxis(false);
|
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
|
// Sort tree roots by z-index
|
||||||
int32_t sortMax = context->layoutElementTreeRoots.length - 1;
|
int32_t sortMax = context->layoutElementTreeRoots.length - 1;
|
||||||
while (sortMax > 0) { // todo dumb bubble sort
|
while (sortMax > 0) { // todo dumb bubble sort
|
||||||
|
@ -2776,6 +2796,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
|
// 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;
|
bool shouldRender = !offscreen;
|
||||||
switch (elementConfig->type) {
|
switch (elementConfig->type) {
|
||||||
|
case CLAY__ELEMENT_CONFIG_TYPE_ASPECT:
|
||||||
case CLAY__ELEMENT_CONFIG_TYPE_FLOATING:
|
case CLAY__ELEMENT_CONFIG_TYPE_FLOATING:
|
||||||
case CLAY__ELEMENT_CONFIG_TYPE_SHARED:
|
case CLAY__ELEMENT_CONFIG_TYPE_SHARED:
|
||||||
case CLAY__ELEMENT_CONFIG_TYPE_BORDER: {
|
case CLAY__ELEMENT_CONFIG_TYPE_BORDER: {
|
||||||
|
@ -2798,7 +2819,6 @@ void Clay__CalculateFinalLayout(void) {
|
||||||
.image = {
|
.image = {
|
||||||
.backgroundColor = sharedConfig->backgroundColor,
|
.backgroundColor = sharedConfig->backgroundColor,
|
||||||
.cornerRadius = sharedConfig->cornerRadius,
|
.cornerRadius = sharedConfig->cornerRadius,
|
||||||
.sourceDimensions = elementConfig->config.imageElementConfig->sourceDimensions,
|
|
||||||
.imageData = elementConfig->config.imageElementConfig->imageData,
|
.imageData = elementConfig->config.imageElementConfig->imageData,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -3097,6 +3117,7 @@ Clay__DebugElementConfigTypeLabelConfig Clay__DebugGetElementConfigTypeLabel(Cla
|
||||||
switch (type) {
|
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_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_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_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_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} };
|
case CLAY__ELEMENT_CONFIG_TYPE_CLIP: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) {CLAY_STRING("Scroll"), {242, 196, 90, 255} };
|
||||||
|
@ -3581,21 +3602,25 @@ void Clay__RenderDebugView(void) {
|
||||||
}
|
}
|
||||||
break;
|
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: {
|
case CLAY__ELEMENT_CONFIG_TYPE_IMAGE: {
|
||||||
Clay_ImageElementConfig *imageConfig = elementConfig->config.imageElementConfig;
|
Clay_ImageElementConfig *imageConfig = elementConfig->config.imageElementConfig;
|
||||||
|
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 } }) {
|
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);
|
|
||||||
}
|
|
||||||
// Image Preview
|
// Image Preview
|
||||||
CLAY_TEXT(CLAY_STRING("Preview"), infoTitleConfig);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,14 +45,15 @@ target_link_libraries(SDL2_video_demo PUBLIC
|
||||||
)
|
)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
||||||
else()
|
else()
|
||||||
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}")
|
||||||
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_custom_command(
|
add_custom_command(
|
||||||
TARGET SDL2_video_demo POST_BUILD
|
TARGET SDL2_video_demo POST_BUILD
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/resources
|
${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(
|
FetchContent_Declare(
|
||||||
SDL_ttf
|
SDL_ttf
|
||||||
GIT_REPOSITORY https://github.com/libsdl-org/SDL_ttf.git
|
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_SHALLOW TRUE
|
||||||
GIT_PROGRESS TRUE
|
GIT_PROGRESS TRUE
|
||||||
)
|
)
|
||||||
|
@ -38,7 +38,7 @@ set_property(DIRECTORY "${sdl_ttf_SOURCE_DIR}" PROPERTY EXCLUDE_FROM_ALL TRUE)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
SDL_image
|
SDL_image
|
||||||
GIT_REPOSITORY "https://github.com/libsdl-org/SDL_image.git"
|
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_SHALLOW TRUE
|
||||||
GIT_PROGRESS TRUE
|
GIT_PROGRESS TRUE
|
||||||
)
|
)
|
||||||
|
|
|
@ -145,7 +145,7 @@ int main(void) {
|
||||||
"Quicksand Semibold"
|
"Quicksand Semibold"
|
||||||
};
|
};
|
||||||
|
|
||||||
Clay_SetMeasureTextFunction(Clay_Cairo_MeasureText, (uintptr_t)fonts);
|
Clay_SetMeasureTextFunction(Clay_Cairo_MeasureText, fonts);
|
||||||
|
|
||||||
Clay_BeginLayout();
|
Clay_BeginLayout();
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,7 @@
|
||||||
{name: 'a', type: 'float' },
|
{name: 'a', type: 'float' },
|
||||||
]};
|
]};
|
||||||
let stringDefinition = { type: 'struct', members: [
|
let stringDefinition = { type: 'struct', members: [
|
||||||
|
{name: 'isStaticallyAllocated', type: 'uint32_t'},
|
||||||
{name: 'length', type: 'uint32_t' },
|
{name: 'length', type: 'uint32_t' },
|
||||||
{name: 'chars', type: 'uint32_t' },
|
{name: 'chars', type: 'uint32_t' },
|
||||||
]};
|
]};
|
||||||
|
@ -144,7 +145,6 @@
|
||||||
let imageRenderDataDefinition = { type: 'struct', members: [
|
let imageRenderDataDefinition = { type: 'struct', members: [
|
||||||
{ name: 'backgroundColor', ...colorDefinition },
|
{ name: 'backgroundColor', ...colorDefinition },
|
||||||
{ name: 'cornerRadius', ...cornerRadiusDefinition },
|
{ name: 'cornerRadius', ...cornerRadiusDefinition },
|
||||||
{ name: 'sourceDimensions', ...dimensionsDefinition },
|
|
||||||
{ name: 'imageData', type: 'uint32_t' },
|
{ name: 'imageData', type: 'uint32_t' },
|
||||||
]};
|
]};
|
||||||
let customRenderDataDefinition = { type: 'struct', members: [
|
let customRenderDataDefinition = { type: 'struct', members: [
|
||||||
|
@ -158,7 +158,7 @@
|
||||||
{ name: 'width', ...borderWidthDefinition },
|
{ name: 'width', ...borderWidthDefinition },
|
||||||
{ name: 'padding', type: 'uint16_t'}
|
{ name: 'padding', type: 'uint16_t'}
|
||||||
]};
|
]};
|
||||||
let scrollRenderDataDefinition = { type: 'struct', members: [
|
let clipRenderDataDefinition = { type: 'struct', members: [
|
||||||
{ name: 'horizontal', type: 'bool' },
|
{ name: 'horizontal', type: 'bool' },
|
||||||
{ name: 'vertical', type: 'bool' },
|
{ name: 'vertical', type: 'bool' },
|
||||||
]};
|
]};
|
||||||
|
@ -168,7 +168,7 @@
|
||||||
{ name: 'disablePointerEvents', type: 'uint8_t' },
|
{ name: 'disablePointerEvents', type: 'uint8_t' },
|
||||||
]};
|
]};
|
||||||
let renderCommandDefinition = {
|
let renderCommandDefinition = {
|
||||||
name: 'CLay_RenderCommand',
|
name: 'Clay_RenderCommand',
|
||||||
type: 'struct',
|
type: 'struct',
|
||||||
members: [
|
members: [
|
||||||
{ name: 'boundingBox', type: 'struct', members: [
|
{ name: 'boundingBox', type: 'struct', members: [
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
{ name: 'image', ...imageRenderDataDefinition },
|
{ name: 'image', ...imageRenderDataDefinition },
|
||||||
{ name: 'custom', ...customRenderDataDefinition },
|
{ name: 'custom', ...customRenderDataDefinition },
|
||||||
{ name: 'border', ...borderRenderDataDefinition },
|
{ name: 'border', ...borderRenderDataDefinition },
|
||||||
{ name: 'scroll', ...scrollRenderDataDefinition },
|
{ name: 'clip', ...clipRenderDataDefinition },
|
||||||
]},
|
]},
|
||||||
{ name: 'userData', type: 'uint32_t'},
|
{ name: 'userData', type: 'uint32_t'},
|
||||||
{ name: 'id', type: 'uint32_t' },
|
{ name: 'id', type: 'uint32_t' },
|
||||||
|
@ -380,7 +380,7 @@
|
||||||
memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
|
memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
|
||||||
memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
|
memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
|
||||||
instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
|
instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
|
||||||
instance.exports.SetScratchMemory(arenaAddress, clayScratchSpaceAddress);
|
instance.exports.SetScratchMemory(clayScratchSpaceAddress);
|
||||||
renderCommandSize = getStructTotalSize(renderCommandDefinition);
|
renderCommandSize = getStructTotalSize(renderCommandDefinition);
|
||||||
renderLoop();
|
renderLoop();
|
||||||
}
|
}
|
||||||
|
@ -570,7 +570,7 @@
|
||||||
}
|
}
|
||||||
case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
|
case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
|
||||||
scissorStack.push({ nextAllocation: { x: renderCommand.boundingBox.x.value, y: renderCommand.boundingBox.y.value }, element, nextElementIndex: 0 });
|
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);
|
let configMemory = JSON.stringify(config);
|
||||||
if (configMemory === elementData.previousMemoryConfig) {
|
if (configMemory === elementData.previousMemoryConfig) {
|
||||||
break;
|
break;
|
||||||
|
|
Binary file not shown.
|
@ -97,6 +97,7 @@
|
||||||
{name: 'a', type: 'float' },
|
{name: 'a', type: 'float' },
|
||||||
]};
|
]};
|
||||||
let stringDefinition = { type: 'struct', members: [
|
let stringDefinition = { type: 'struct', members: [
|
||||||
|
{name: 'isStaticallyAllocated', type: 'uint32_t'},
|
||||||
{name: 'length', type: 'uint32_t' },
|
{name: 'length', type: 'uint32_t' },
|
||||||
{name: 'chars', type: 'uint32_t' },
|
{name: 'chars', type: 'uint32_t' },
|
||||||
]};
|
]};
|
||||||
|
@ -144,7 +145,6 @@
|
||||||
let imageRenderDataDefinition = { type: 'struct', members: [
|
let imageRenderDataDefinition = { type: 'struct', members: [
|
||||||
{ name: 'backgroundColor', ...colorDefinition },
|
{ name: 'backgroundColor', ...colorDefinition },
|
||||||
{ name: 'cornerRadius', ...cornerRadiusDefinition },
|
{ name: 'cornerRadius', ...cornerRadiusDefinition },
|
||||||
{ name: 'sourceDimensions', ...dimensionsDefinition },
|
|
||||||
{ name: 'imageData', type: 'uint32_t' },
|
{ name: 'imageData', type: 'uint32_t' },
|
||||||
]};
|
]};
|
||||||
let customRenderDataDefinition = { type: 'struct', members: [
|
let customRenderDataDefinition = { type: 'struct', members: [
|
||||||
|
@ -158,7 +158,7 @@
|
||||||
{ name: 'width', ...borderWidthDefinition },
|
{ name: 'width', ...borderWidthDefinition },
|
||||||
{ name: 'padding', type: 'uint16_t'}
|
{ name: 'padding', type: 'uint16_t'}
|
||||||
]};
|
]};
|
||||||
let scrollRenderDataDefinition = { type: 'struct', members: [
|
let clipRenderDataDefinition = { type: 'struct', members: [
|
||||||
{ name: 'horizontal', type: 'bool' },
|
{ name: 'horizontal', type: 'bool' },
|
||||||
{ name: 'vertical', type: 'bool' },
|
{ name: 'vertical', type: 'bool' },
|
||||||
]};
|
]};
|
||||||
|
@ -168,7 +168,7 @@
|
||||||
{ name: 'disablePointerEvents', type: 'uint8_t' },
|
{ name: 'disablePointerEvents', type: 'uint8_t' },
|
||||||
]};
|
]};
|
||||||
let renderCommandDefinition = {
|
let renderCommandDefinition = {
|
||||||
name: 'CLay_RenderCommand',
|
name: 'Clay_RenderCommand',
|
||||||
type: 'struct',
|
type: 'struct',
|
||||||
members: [
|
members: [
|
||||||
{ name: 'boundingBox', type: 'struct', members: [
|
{ name: 'boundingBox', type: 'struct', members: [
|
||||||
|
@ -183,7 +183,7 @@
|
||||||
{ name: 'image', ...imageRenderDataDefinition },
|
{ name: 'image', ...imageRenderDataDefinition },
|
||||||
{ name: 'custom', ...customRenderDataDefinition },
|
{ name: 'custom', ...customRenderDataDefinition },
|
||||||
{ name: 'border', ...borderRenderDataDefinition },
|
{ name: 'border', ...borderRenderDataDefinition },
|
||||||
{ name: 'scroll', ...scrollRenderDataDefinition },
|
{ name: 'clip', ...clipRenderDataDefinition },
|
||||||
]},
|
]},
|
||||||
{ name: 'userData', type: 'uint32_t'},
|
{ name: 'userData', type: 'uint32_t'},
|
||||||
{ name: 'id', type: 'uint32_t' },
|
{ name: 'id', type: 'uint32_t' },
|
||||||
|
@ -380,7 +380,7 @@
|
||||||
memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
|
memoryDataView.setFloat32(instance.exports.__heap_base.value, window.innerWidth, true);
|
||||||
memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
|
memoryDataView.setFloat32(instance.exports.__heap_base.value + 4, window.innerHeight, true);
|
||||||
instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
|
instance.exports.Clay_Initialize(arenaAddress, instance.exports.__heap_base.value);
|
||||||
instance.exports.SetScratchMemory(arenaAddress, clayScratchSpaceAddress);
|
instance.exports.SetScratchMemory(clayScratchSpaceAddress);
|
||||||
renderCommandSize = getStructTotalSize(renderCommandDefinition);
|
renderCommandSize = getStructTotalSize(renderCommandDefinition);
|
||||||
renderLoop();
|
renderLoop();
|
||||||
}
|
}
|
||||||
|
@ -570,7 +570,7 @@
|
||||||
}
|
}
|
||||||
case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
|
case (CLAY_RENDER_COMMAND_TYPE_SCISSOR_START): {
|
||||||
scissorStack.push({ nextAllocation: { x: renderCommand.boundingBox.x.value, y: renderCommand.boundingBox.y.value }, element, nextElementIndex: 0 });
|
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);
|
let configMemory = JSON.stringify(config);
|
||||||
if (configMemory === elementData.previousMemoryConfig) {
|
if (configMemory === elementData.previousMemoryConfig) {
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -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) {
|
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("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 }));
|
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_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("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_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("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_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("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")) } }) {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3
examples/playdate-project-example/.gitignore
vendored
Normal file
3
examples/playdate-project-example/.gitignore
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
clay_playdate_example.pdx
|
||||||
|
Source/pdex.dylib
|
||||||
|
Source/pdex.elf
|
40
examples/playdate-project-example/CmakeLists.txt
Normal file
40
examples/playdate-project-example/CmakeLists.txt
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
cmake_minimum_required(VERSION 3.27)
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
|
||||||
|
set(ENVSDK $ENV{PLAYDATE_SDK_PATH})
|
||||||
|
|
||||||
|
if (NOT ${ENVSDK} STREQUAL "")
|
||||||
|
# Convert path from Windows
|
||||||
|
file(TO_CMAKE_PATH ${ENVSDK} SDK)
|
||||||
|
else()
|
||||||
|
execute_process(
|
||||||
|
COMMAND bash -c "egrep '^\\s*SDKRoot' $HOME/.Playdate/config"
|
||||||
|
COMMAND head -n 1
|
||||||
|
COMMAND cut -c9-
|
||||||
|
OUTPUT_VARIABLE SDK
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT EXISTS ${SDK})
|
||||||
|
message(FATAL_ERROR "SDK Path not found; set ENV value PLAYDATE_SDK_PATH")
|
||||||
|
return()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_CONFIGURATION_TYPES "Debug;Release")
|
||||||
|
set(CMAKE_XCODE_GENERATE_SCHEME TRUE)
|
||||||
|
|
||||||
|
# Game Name Customization
|
||||||
|
set(PLAYDATE_GAME_NAME clay_playdate_example)
|
||||||
|
set(PLAYDATE_GAME_DEVICE clay_playdate_example_DEVICE)
|
||||||
|
|
||||||
|
project(${PLAYDATE_GAME_NAME} C ASM)
|
||||||
|
|
||||||
|
if (TOOLCHAIN STREQUAL "armgcc")
|
||||||
|
add_executable(${PLAYDATE_GAME_DEVICE} main.c)
|
||||||
|
else()
|
||||||
|
add_library(${PLAYDATE_GAME_NAME} SHARED main.c)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(${SDK}/C_API/buildsupport/playdate_game.cmake)
|
||||||
|
|
37
examples/playdate-project-example/README.md
Normal file
37
examples/playdate-project-example/README.md
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
# Playdate console example
|
||||||
|
|
||||||
|
This example uses a modified version of the document viewer application from the Clay video demo. The Playdate console has a very small black and white screen, so some of the fixed sizes and styles needed to be modified to make the application usable on the console. The selected document can be changed using up/down on the D-pad, and the selected document can be scrolled with the crank.
|
||||||
|
|
||||||
|
## Building
|
||||||
|
|
||||||
|
You need to have the (Playdate SDK)[https://play.date/dev/] installed to be able to build this example. Once it's installed you can build it by adding -DCLAY_INCLUDE_PLAYDATE_EXAMPLES=ON when initialising a directory with cmake.
|
||||||
|
|
||||||
|
e.g.
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -DCLAY_INCLUDE_PLAYDATE_EXAMPLES=ON cmake-build-debug
|
||||||
|
```
|
||||||
|
|
||||||
|
And then build it:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake --build cmake-build-debug
|
||||||
|
```
|
||||||
|
|
||||||
|
The pdx file will be located at examples/playdate-project-example/clay_playdate_example.pdx. You can then open it with the Playdate simulator.
|
||||||
|
|
||||||
|
## Building for the playdate device
|
||||||
|
|
||||||
|
By default building this example will produce a pdx which can only run on the Playdate simulator application. To build a pdx that can run on the Playdate hardware you need to set the toolchain to use armgcc, toolchain file to the arm.cmake provided in the playdate SDK and make sure to disable the other examples. The Playdate hardware requires threads to be disabled which is not compatible with some of the other examples.
|
||||||
|
|
||||||
|
e.g. To setup the cmake-build-release directory for device builds:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake -DTOOLCHAIN=armgcc -DCMAKE_TOOLCHAIN_FILE=/Users/mattahj/Developer/PlaydateSDK/C_API/buildsupport/arm.cmake -DCLAY_INCLUDE_ALL_EXAMPLES=OFF -DCLAY_INCLUDE_PLAYDATE_EXAMPLES=ON -B cmake-build-release
|
||||||
|
```
|
||||||
|
|
||||||
|
And then build it:
|
||||||
|
|
||||||
|
```
|
||||||
|
cmake --build cmake-build-release
|
||||||
|
```
|
5
examples/playdate-project-example/Source/pdxinfo
Normal file
5
examples/playdate-project-example/Source/pdxinfo
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
name=Clay Playdate Example
|
||||||
|
author=Matthew Jennings
|
||||||
|
description=A small demo of Clay running on the Playdate
|
||||||
|
bundleID=dev.mattahj.clay_example
|
||||||
|
imagePath=
|
BIN
examples/playdate-project-example/Source/star.png
Normal file
BIN
examples/playdate-project-example/Source/star.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
366
examples/playdate-project-example/clay-video-demo-playdate.c
Normal file
366
examples/playdate-project-example/clay-video-demo-playdate.c
Normal file
|
@ -0,0 +1,366 @@
|
||||||
|
// This is the video demo with some adjustments so it works on the playdate
|
||||||
|
// console The playdate screen is only 400x240 pixels and it can only display
|
||||||
|
// black and white, so some fixed sizes and colours needed tweaking! The file
|
||||||
|
// menu was also removed as it does not really make sense when there is no
|
||||||
|
// pointer
|
||||||
|
//
|
||||||
|
// Note: The playdate console also does not support dynamic font sizes - fonts must be
|
||||||
|
// created at a specific size with the pdc tool - so any font size set in the clay layout
|
||||||
|
// will have no effect.
|
||||||
|
#include "pd_api.h"
|
||||||
|
#include "../../clay.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
const int FONT_ID_BODY = 0;
|
||||||
|
const int FONT_ID_BUTTON = 1;
|
||||||
|
|
||||||
|
Clay_Color COLOR_WHITE = { 255, 255, 255, 255 };
|
||||||
|
Clay_Color COLOR_BLACK = { 0, 0, 0, 255 };
|
||||||
|
|
||||||
|
void RenderHeaderButton(Clay_String text) {
|
||||||
|
CLAY({
|
||||||
|
.layout = { .padding = { 8, 8, 4, 4 } },
|
||||||
|
.backgroundColor = COLOR_BLACK,
|
||||||
|
.cornerRadius = CLAY_CORNER_RADIUS(4)
|
||||||
|
}) {
|
||||||
|
CLAY_TEXT(
|
||||||
|
text,
|
||||||
|
CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BUTTON, .textColor = COLOR_WHITE })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Clay_String title;
|
||||||
|
Clay_String contents;
|
||||||
|
LCDBitmap* image;
|
||||||
|
} Document;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Document *documents;
|
||||||
|
uint32_t length;
|
||||||
|
} DocumentArray;
|
||||||
|
|
||||||
|
#define MAX_DOCUMENTS 3
|
||||||
|
Document documentsRaw[MAX_DOCUMENTS];
|
||||||
|
|
||||||
|
DocumentArray documents = { .length = MAX_DOCUMENTS, .documents = documentsRaw };
|
||||||
|
|
||||||
|
void ClayVideoDemoPlaydate_Initialize(PlaydateAPI* pd) {
|
||||||
|
documents.documents[0] = (Document){
|
||||||
|
.title = CLAY_STRING("Squirrels"),
|
||||||
|
.image = pd->graphics->loadBitmap("star.png", NULL),
|
||||||
|
.contents = CLAY_STRING(
|
||||||
|
"The Secret Life of Squirrels: Nature's Clever Acrobats\n"
|
||||||
|
"Squirrels are often overlooked creatures, dismissed as mere park "
|
||||||
|
"inhabitants or backyard nuisances. Yet, beneath their fluffy tails "
|
||||||
|
"and twitching noses lies an intricate world of cunning, agility, "
|
||||||
|
"and survival tactics that are nothing short of fascinating. As one "
|
||||||
|
"of the most common mammals in North America, squirrels have adapted "
|
||||||
|
"to a wide range of environments from bustling urban centers to "
|
||||||
|
"tranquil forests and have developed a variety of unique behaviors "
|
||||||
|
"that continue to intrigue scientists and nature enthusiasts alike.\n"
|
||||||
|
"\n"
|
||||||
|
"Master Tree Climbers\n"
|
||||||
|
"At the heart of a squirrel's skill set is its impressive ability to "
|
||||||
|
"navigate trees with ease. Whether they're darting from branch to "
|
||||||
|
"branch or leaping across wide gaps, squirrels possess an innate "
|
||||||
|
"talent for acrobatics. Their powerful hind legs, which are longer "
|
||||||
|
"than their front legs, give them remarkable jumping power. With a "
|
||||||
|
"tail that acts as a counterbalance, squirrels can leap distances of "
|
||||||
|
"up to ten times the length of their body, making them some of the "
|
||||||
|
"best aerial acrobats in the animal kingdom.\n"
|
||||||
|
"But it's not just their agility that makes them exceptional "
|
||||||
|
"climbers. Squirrels' sharp, curved claws allow them to grip tree "
|
||||||
|
"bark with precision, while the soft pads on their feet provide "
|
||||||
|
"traction on slippery surfaces. Their ability to run at high speeds "
|
||||||
|
"and scale vertical trunks with ease is a testament to the "
|
||||||
|
"evolutionary adaptations that have made them so successful in their "
|
||||||
|
"arboreal habitats.\n"
|
||||||
|
"\n"
|
||||||
|
"Food Hoarders Extraordinaire\n"
|
||||||
|
"Squirrels are often seen frantically gathering nuts, seeds, and "
|
||||||
|
"even fungi in preparation for winter. While this behavior may seem "
|
||||||
|
"like instinctual hoarding, it is actually a survival strategy that "
|
||||||
|
"has been honed over millions of years. Known as \"scatter "
|
||||||
|
"hoarding,\" squirrels store their food in a variety of hidden "
|
||||||
|
"locations, often burying it deep in the soil or stashing it in "
|
||||||
|
"hollowed-out tree trunks.\n"
|
||||||
|
"Interestingly, squirrels have an incredible memory for the "
|
||||||
|
"locations of their caches. Research has shown that they can "
|
||||||
|
"remember thousands of hiding spots, often returning to them months "
|
||||||
|
"later when food is scarce. However, they don't always recover every "
|
||||||
|
"stash some forgotten caches eventually sprout into new trees, "
|
||||||
|
"contributing to forest regeneration. This unintentional role as "
|
||||||
|
"forest gardeners highlights the ecological importance of squirrels "
|
||||||
|
"in their ecosystems.\n"
|
||||||
|
"\n"
|
||||||
|
"The Great Squirrel Debate: Urban vs. Wild\n"
|
||||||
|
"While squirrels are most commonly associated with rural or wooded "
|
||||||
|
"areas, their adaptability has allowed them to thrive in urban "
|
||||||
|
"environments as well. In cities, squirrels have become adept at "
|
||||||
|
"finding food sources in places like parks, streets, and even "
|
||||||
|
"garbage cans. However, their urban counterparts face unique "
|
||||||
|
"challenges, including traffic, predators, and the lack of natural "
|
||||||
|
"shelters. Despite these obstacles, squirrels in urban areas are "
|
||||||
|
"often observed using human infrastructure such as buildings, "
|
||||||
|
"bridges, and power lines as highways for their acrobatic "
|
||||||
|
"escapades.\n"
|
||||||
|
"There is, however, a growing concern regarding the impact of urban "
|
||||||
|
"life on squirrel populations. Pollution, deforestation, and the "
|
||||||
|
"loss of natural habitats are making it more difficult for squirrels "
|
||||||
|
"to find adequate food and shelter. As a result, conservationists "
|
||||||
|
"are focusing on creating squirrel-friendly spaces within cities, "
|
||||||
|
"with the goal of ensuring these resourceful creatures continue to "
|
||||||
|
"thrive in both rural and urban landscapes.\n"
|
||||||
|
"\n"
|
||||||
|
"A Symbol of Resilience\n"
|
||||||
|
"In many cultures, squirrels are symbols of resourcefulness, "
|
||||||
|
"adaptability, and preparation. Their ability to thrive in a variety "
|
||||||
|
"of environments while navigating challenges with agility and grace "
|
||||||
|
"serves as a reminder of the resilience inherent in nature. Whether "
|
||||||
|
"you encounter them in a quiet forest, a city park, or your own "
|
||||||
|
"backyard, squirrels are creatures that never fail to amaze with "
|
||||||
|
"their endless energy and ingenuity.\n"
|
||||||
|
"In the end, squirrels may be small, but they are mighty in their "
|
||||||
|
"ability to survive and thrive in a world that is constantly "
|
||||||
|
"changing. So next time you spot one hopping across a branch or "
|
||||||
|
"darting across your lawn, take a moment to appreciate the "
|
||||||
|
"remarkable acrobat at work a true marvel of the natural world.\n"
|
||||||
|
)
|
||||||
|
};
|
||||||
|
documents.documents[1] = (Document){
|
||||||
|
.title = CLAY_STRING("Lorem Ipsum"),
|
||||||
|
.image = pd->graphics->loadBitmap("star.png", NULL),
|
||||||
|
.contents = CLAY_STRING(
|
||||||
|
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do "
|
||||||
|
"eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim "
|
||||||
|
"ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut "
|
||||||
|
"aliquip ex ea commodo consequat. Duis aute irure dolor in "
|
||||||
|
"reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla "
|
||||||
|
"pariatur. Excepteur sint occaecat cupidatat non proident, sunt in "
|
||||||
|
"culpa qui officia deserunt mollit anim id est laborum."
|
||||||
|
)
|
||||||
|
};
|
||||||
|
documents.documents[2] = (Document){
|
||||||
|
.title = CLAY_STRING("Vacuum Instructions"),
|
||||||
|
.image = pd->graphics->loadBitmap("star.png", NULL),
|
||||||
|
.contents = CLAY_STRING(
|
||||||
|
"Chapter 3: Getting Started - Unpacking and Setup\n"
|
||||||
|
"\n"
|
||||||
|
"Congratulations on your new SuperClean Pro 5000 vacuum cleaner! In "
|
||||||
|
"this section, we will guide you through the simple steps to get "
|
||||||
|
"your vacuum up and running. Before you begin, please ensure that "
|
||||||
|
"you have all the components listed in the \"Package Contents\" "
|
||||||
|
"section on page 2.\n"
|
||||||
|
"\n"
|
||||||
|
"1. Unboxing Your Vacuum\n"
|
||||||
|
"Carefully remove the vacuum cleaner from the box. Avoid using sharp "
|
||||||
|
"objects that could damage the product. Once removed, place the unit "
|
||||||
|
"on a flat, stable surface to proceed with the setup. Inside the "
|
||||||
|
"box, you should find:\n"
|
||||||
|
"\n"
|
||||||
|
" The main vacuum unit\n"
|
||||||
|
" A telescoping extension wand\n"
|
||||||
|
" A set of specialized cleaning tools (crevice tool, upholstery "
|
||||||
|
"brush, etc.)\n"
|
||||||
|
" A reusable dust bag (if applicable)\n"
|
||||||
|
" A power cord with a 3-prong plug\n"
|
||||||
|
" A set of quick-start instructions\n"
|
||||||
|
"\n"
|
||||||
|
"2. Assembling Your Vacuum\n"
|
||||||
|
"Begin by attaching the extension wand to the main body of the "
|
||||||
|
"vacuum cleaner. Line up the connectors and twist the wand into "
|
||||||
|
"place until you hear a click. Next, select the desired cleaning "
|
||||||
|
"tool and firmly attach it to the wand's end, ensuring it is "
|
||||||
|
"securely locked in.\n"
|
||||||
|
"\n"
|
||||||
|
"For models that require a dust bag, slide the bag into the "
|
||||||
|
"compartment at the back of the vacuum, making sure it is properly "
|
||||||
|
"aligned with the internal mechanism. If your vacuum uses a bagless "
|
||||||
|
"system, ensure the dust container is correctly seated and locked in "
|
||||||
|
"place before use.\n"
|
||||||
|
"\n"
|
||||||
|
"3. Powering On\n"
|
||||||
|
"To start the vacuum, plug the power cord into a grounded electrical "
|
||||||
|
"outlet. Once plugged in, locate the power switch, usually "
|
||||||
|
"positioned on the side of the handle or body of the unit, depending "
|
||||||
|
"on your model. Press the switch to the \"On\" position, and you "
|
||||||
|
"should hear the motor begin to hum. If the vacuum does not power "
|
||||||
|
"on, check that the power cord is securely plugged in, and ensure "
|
||||||
|
"there are no blockages in the power switch.\n"
|
||||||
|
"\n"
|
||||||
|
"Note: Before first use, ensure that the vacuum filter (if your "
|
||||||
|
"model has one) is properly installed. If unsure, refer to \"Section "
|
||||||
|
"5: Maintenance\" for filter installation instructions."
|
||||||
|
)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Clay_RenderCommandArray ClayVideoDemoPlaydate_CreateLayout(int selectedDocumentIndex) {
|
||||||
|
|
||||||
|
Clay_BeginLayout();
|
||||||
|
|
||||||
|
Clay_Sizing layoutExpand = {
|
||||||
|
.width = CLAY_SIZING_GROW(0),
|
||||||
|
.height = CLAY_SIZING_GROW(0)
|
||||||
|
};
|
||||||
|
|
||||||
|
Clay_BorderElementConfig contentBorders = {
|
||||||
|
.color = COLOR_BLACK,
|
||||||
|
.width = { .top = 1, .left = 1, .right = 1, .bottom = 1 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Build UI here
|
||||||
|
CLAY({
|
||||||
|
.id = CLAY_ID("OuterContainer"),
|
||||||
|
.backgroundColor = COLOR_WHITE,
|
||||||
|
.layout = {
|
||||||
|
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||||
|
.sizing = layoutExpand,
|
||||||
|
.padding = CLAY_PADDING_ALL(8),
|
||||||
|
.childGap = 4
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
// Child elements go inside braces
|
||||||
|
CLAY({
|
||||||
|
.id = CLAY_ID("HeaderBar"),
|
||||||
|
.layout = {
|
||||||
|
.sizing = {
|
||||||
|
.height = CLAY_SIZING_FIXED(30),
|
||||||
|
.width = CLAY_SIZING_GROW(0)
|
||||||
|
},
|
||||||
|
.childGap = 8,
|
||||||
|
.childAlignment = { .y = CLAY_ALIGN_Y_CENTER }
|
||||||
|
},
|
||||||
|
}) {
|
||||||
|
// Header buttons go here
|
||||||
|
CLAY({
|
||||||
|
.id = CLAY_ID("FileButton"),
|
||||||
|
.layout = {
|
||||||
|
.padding = { 8, 8, 4, 4 }
|
||||||
|
},
|
||||||
|
.backgroundColor = COLOR_BLACK,
|
||||||
|
.cornerRadius = CLAY_CORNER_RADIUS(4)
|
||||||
|
}) {
|
||||||
|
CLAY_TEXT(
|
||||||
|
CLAY_STRING("File"),
|
||||||
|
CLAY_TEXT_CONFIG({
|
||||||
|
.fontId = FONT_ID_BUTTON,
|
||||||
|
.textColor = COLOR_WHITE
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
RenderHeaderButton(CLAY_STRING("Edit"));
|
||||||
|
CLAY({ .layout = { .sizing = { CLAY_SIZING_GROW(0) } } }) {}
|
||||||
|
RenderHeaderButton(CLAY_STRING("Upload"));
|
||||||
|
RenderHeaderButton(CLAY_STRING("Media"));
|
||||||
|
RenderHeaderButton(CLAY_STRING("Support"));
|
||||||
|
}
|
||||||
|
|
||||||
|
CLAY({
|
||||||
|
.id = CLAY_ID("LowerContent"),
|
||||||
|
.layout = { .sizing = layoutExpand, .childGap = 8 },
|
||||||
|
}) {
|
||||||
|
CLAY({
|
||||||
|
.id = CLAY_ID("Sidebar"),
|
||||||
|
.border = contentBorders,
|
||||||
|
.cornerRadius = CLAY_CORNER_RADIUS(4),
|
||||||
|
.layout = {
|
||||||
|
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||||
|
.padding = CLAY_PADDING_ALL(8),
|
||||||
|
.childGap = 4,
|
||||||
|
.sizing = {
|
||||||
|
.width = CLAY_SIZING_FIXED(125),
|
||||||
|
.height = CLAY_SIZING_GROW(0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
for (int i = 0; i < documents.length; i++) {
|
||||||
|
Document document = documents.documents[i];
|
||||||
|
Clay_LayoutConfig sidebarButtonLayout = {
|
||||||
|
.sizing = { .width = CLAY_SIZING_GROW(0) },
|
||||||
|
.padding = CLAY_PADDING_ALL(8)
|
||||||
|
};
|
||||||
|
|
||||||
|
if (i == selectedDocumentIndex) {
|
||||||
|
CLAY({
|
||||||
|
.layout = sidebarButtonLayout,
|
||||||
|
.backgroundColor = COLOR_BLACK,
|
||||||
|
.cornerRadius = CLAY_CORNER_RADIUS(4)
|
||||||
|
}) {
|
||||||
|
CLAY_TEXT(
|
||||||
|
document.title,
|
||||||
|
CLAY_TEXT_CONFIG({
|
||||||
|
.fontId = FONT_ID_BUTTON,
|
||||||
|
.textColor = COLOR_WHITE
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CLAY({
|
||||||
|
.layout = sidebarButtonLayout,
|
||||||
|
.backgroundColor = (Clay_Color){ 0, 0, 0, Clay_Hovered() ? 120 : 0 },
|
||||||
|
.cornerRadius = CLAY_CORNER_RADIUS(4),
|
||||||
|
.border = contentBorders
|
||||||
|
}) {
|
||||||
|
CLAY_TEXT(
|
||||||
|
document.title,
|
||||||
|
CLAY_TEXT_CONFIG({
|
||||||
|
.fontId = FONT_ID_BUTTON,
|
||||||
|
.textColor = COLOR_BLACK,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CLAY({
|
||||||
|
.id = CLAY_ID("MainContent"),
|
||||||
|
.border = contentBorders,
|
||||||
|
.cornerRadius = CLAY_CORNER_RADIUS(4),
|
||||||
|
.clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() },
|
||||||
|
.layout = {
|
||||||
|
.layoutDirection = CLAY_TOP_TO_BOTTOM,
|
||||||
|
.childGap = 8,
|
||||||
|
.padding = CLAY_PADDING_ALL(8),
|
||||||
|
.sizing = layoutExpand
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
Document selectedDocument = documents.documents[selectedDocumentIndex];
|
||||||
|
CLAY({
|
||||||
|
.layout = {
|
||||||
|
.layoutDirection = CLAY_LEFT_TO_RIGHT,
|
||||||
|
.childGap = 4,
|
||||||
|
.childAlignment = { .x = CLAY_ALIGN_X_CENTER, .y = CLAY_ALIGN_Y_BOTTOM }
|
||||||
|
}
|
||||||
|
}) {
|
||||||
|
CLAY_TEXT(
|
||||||
|
selectedDocument.title,
|
||||||
|
CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY, .textColor = COLOR_BLACK })
|
||||||
|
);
|
||||||
|
CLAY({
|
||||||
|
.layout = {
|
||||||
|
.sizing = {
|
||||||
|
.width = CLAY_SIZING_FIXED(32),
|
||||||
|
.height = CLAY_SIZING_FIXED(30)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
.image = { .imageData = selectedDocument.image, .sourceDimensions = { 32, 30 } }
|
||||||
|
}) {}
|
||||||
|
}
|
||||||
|
CLAY_TEXT(
|
||||||
|
selectedDocument.contents,
|
||||||
|
CLAY_TEXT_CONFIG({ .fontId = FONT_ID_BODY, .textColor = COLOR_BLACK })
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Clay_RenderCommandArray renderCommands = Clay_EndLayout();
|
||||||
|
for (int32_t i = 0; i < renderCommands.length; i++) {
|
||||||
|
Clay_RenderCommandArray_Get(&renderCommands, i);
|
||||||
|
}
|
||||||
|
return renderCommands;
|
||||||
|
}
|
115
examples/playdate-project-example/main.c
Normal file
115
examples/playdate-project-example/main.c
Normal file
|
@ -0,0 +1,115 @@
|
||||||
|
#include "pd_api.h"
|
||||||
|
#define CLAY_IMPLEMENTATION
|
||||||
|
#include "../../clay.h"
|
||||||
|
|
||||||
|
#include "../../renderers/playdate/clay_renderer_playdate.c"
|
||||||
|
#include "clay-video-demo-playdate.c"
|
||||||
|
|
||||||
|
static int update(void *userdata);
|
||||||
|
|
||||||
|
#define NUM_FONTS 2
|
||||||
|
const char *fontsToLoad[NUM_FONTS] = {
|
||||||
|
"/System/Fonts/Asheville-Sans-14-Bold.pft",
|
||||||
|
"/System/Fonts/Roobert-10-Bold.pft"
|
||||||
|
};
|
||||||
|
|
||||||
|
void HandleClayErrors(Clay_ErrorData errorData) {}
|
||||||
|
|
||||||
|
struct TextUserData {
|
||||||
|
LCDFont *font[NUM_FONTS];
|
||||||
|
PlaydateAPI *pd;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct TextUserData textUserData = { .font = { NULL }, .pd = NULL };
|
||||||
|
|
||||||
|
static Clay_Dimensions PlayDate_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData) {
|
||||||
|
struct TextUserData *textUserData = userData;
|
||||||
|
int width = textUserData->pd->graphics->getTextWidth(
|
||||||
|
textUserData->font[config->fontId],
|
||||||
|
text.chars,
|
||||||
|
Clay_Playdate_CountUtf8Codepoints(text.chars, text.length),
|
||||||
|
kUTF8Encoding,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
int height = textUserData->pd->graphics->getFontHeight(textUserData->font[config->fontId]);
|
||||||
|
return (Clay_Dimensions){
|
||||||
|
.width = (float)width,
|
||||||
|
.height = (float)height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef _WINDLL
|
||||||
|
__declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
int eventHandler(PlaydateAPI* pd, PDSystemEvent event, uint32_t eventArg) {
|
||||||
|
if (event == kEventInit) {
|
||||||
|
const char *err;
|
||||||
|
for (int i = 0; i < NUM_FONTS; ++i) {
|
||||||
|
|
||||||
|
textUserData.font[i] = pd->graphics->loadFont(fontsToLoad[i], &err);
|
||||||
|
if (textUserData.font[i] == NULL) {
|
||||||
|
pd->system->error("%s:%i Couldn't load font %s: %s", __FILE__, __LINE__, fontsToLoad[i], err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
textUserData.pd = pd;
|
||||||
|
pd->system->setUpdateCallback(update, pd);
|
||||||
|
|
||||||
|
uint64_t totalMemorySize = Clay_MinMemorySize();
|
||||||
|
Clay_Arena clayMemory = Clay_CreateArenaWithCapacityAndMemory(
|
||||||
|
totalMemorySize,
|
||||||
|
pd->system->realloc(NULL, totalMemorySize)
|
||||||
|
);
|
||||||
|
Clay_Initialize(
|
||||||
|
clayMemory,
|
||||||
|
(Clay_Dimensions){
|
||||||
|
(float)pd->display->getWidth(),
|
||||||
|
(float)pd->display->getHeight()
|
||||||
|
},
|
||||||
|
(Clay_ErrorHandler){HandleClayErrors}
|
||||||
|
);
|
||||||
|
Clay_SetMeasureTextFunction(PlayDate_MeasureText, &textUserData);
|
||||||
|
ClayVideoDemoPlaydate_Initialize(pd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int selectedDocumentIndex = 0;
|
||||||
|
#define WRAP_RANGE(x, N) ((((x) % (N)) + (N)) % (N))
|
||||||
|
|
||||||
|
static int update(void *userdata) {
|
||||||
|
PlaydateAPI *pd = userdata;
|
||||||
|
PDButtons pushedButtons;
|
||||||
|
pd->system->getButtonState(NULL, &pushedButtons, NULL);
|
||||||
|
|
||||||
|
if (pushedButtons & kButtonDown) {
|
||||||
|
selectedDocumentIndex = WRAP_RANGE(selectedDocumentIndex + 1, MAX_DOCUMENTS);
|
||||||
|
} else if (pushedButtons & kButtonUp) {
|
||||||
|
selectedDocumentIndex = WRAP_RANGE(selectedDocumentIndex - 1, MAX_DOCUMENTS);
|
||||||
|
}
|
||||||
|
|
||||||
|
pd->graphics->clear(kColorWhite);
|
||||||
|
|
||||||
|
// A bit hacky, setting the cursor on to the document view so it can be
|
||||||
|
// scrolled..
|
||||||
|
Clay_SetPointerState(
|
||||||
|
(Clay_Vector2){
|
||||||
|
.x = pd->display->getWidth() / 2.0f,
|
||||||
|
.y = pd->display->getHeight() / 2.0f
|
||||||
|
},
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
float crankDelta = pd->system->getCrankChange();
|
||||||
|
Clay_UpdateScrollContainers(
|
||||||
|
false,
|
||||||
|
(Clay_Vector2){ 0, -crankDelta * 0.25f },
|
||||||
|
pd->system->getElapsedTime()
|
||||||
|
);
|
||||||
|
|
||||||
|
Clay_RenderCommandArray renderCommands = ClayVideoDemoPlaydate_CreateLayout(selectedDocumentIndex);
|
||||||
|
Clay_Playdate_Render(pd, renderCommands, textUserData.font);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
File diff suppressed because one or more lines are too long
15
examples/terminal-example/CMakeLists.txt
Normal file
15
examples/terminal-example/CMakeLists.txt
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
cmake_minimum_required(VERSION 3.27)
|
||||||
|
project(clay_examples_terminal C)
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
|
||||||
|
add_executable(clay_examples_terminal main.c)
|
||||||
|
|
||||||
|
target_compile_options(clay_examples_terminal PUBLIC)
|
||||||
|
target_include_directories(clay_examples_terminal PUBLIC .)
|
||||||
|
if (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||||
|
target_link_libraries(clay_examples_terminal INTERFACE m)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_link_libraries(clay_examples_terminal PUBLIC ${CURSES_LIBRARY})
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-Wall -Werror -DCLAY_DEBUG")
|
||||||
|
set(CMAKE_CXX_FLAGS_RELEASE "-O3")
|
39
examples/terminal-example/main.c
Normal file
39
examples/terminal-example/main.c
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
// Must be defined in one file, _before_ #include "clay.h"
|
||||||
|
#define CLAY_IMPLEMENTATION
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include "../../clay.h"
|
||||||
|
#include "../../renderers/terminal/clay_renderer_terminal_ansi.c"
|
||||||
|
#include "../shared-layouts/clay-video-demo.c"
|
||||||
|
|
||||||
|
const Clay_Color COLOR_LIGHT = (Clay_Color) {224, 215, 210, 255};
|
||||||
|
const Clay_Color COLOR_RED = (Clay_Color) {168, 66, 28, 255};
|
||||||
|
const Clay_Color COLOR_ORANGE = (Clay_Color) {225, 138, 50, 255};
|
||||||
|
|
||||||
|
void HandleClayErrors(Clay_ErrorData errorData) {
|
||||||
|
printf("%s", errorData.errorText.chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
const int width = 145;
|
||||||
|
const int height = 41;
|
||||||
|
int columnWidth = 16;
|
||||||
|
|
||||||
|
uint64_t totalMemorySize = Clay_MinMemorySize();
|
||||||
|
Clay_Arena arena = Clay_CreateArenaWithCapacityAndMemory(totalMemorySize, malloc(totalMemorySize));
|
||||||
|
Clay_Initialize(arena,
|
||||||
|
(Clay_Dimensions) {.width = (float) width * columnWidth, .height = (float) height * columnWidth},
|
||||||
|
(Clay_ErrorHandler) {HandleClayErrors});
|
||||||
|
// Tell clay how to measure text
|
||||||
|
Clay_SetMeasureTextFunction(Console_MeasureText, &columnWidth);
|
||||||
|
ClayVideoDemo_Data demoData = ClayVideoDemo_Initialize();
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
Clay_RenderCommandArray renderCommands = ClayVideoDemo_CreateLayout(&demoData);
|
||||||
|
|
||||||
|
Clay_Terminal_Render(renderCommands, width, height, columnWidth);
|
||||||
|
|
||||||
|
fflush(stdout);
|
||||||
|
sleep(1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -75,7 +75,7 @@ static inline char *Clay_Cairo__NullTerminate(Clay_String *str) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Measure text using cairo's *toy* text API.
|
// Measure text using cairo's *toy* text API.
|
||||||
static inline Clay_Dimensions Clay_Cairo_MeasureText(Clay_StringSlice str, Clay_TextElementConfig *config, uintptr_t userData) {
|
static inline Clay_Dimensions Clay_Cairo_MeasureText(Clay_StringSlice str, Clay_TextElementConfig *config, void *userData) {
|
||||||
// Edge case: Clay computes the width of a whitespace character
|
// Edge case: Clay computes the width of a whitespace character
|
||||||
// once. Cairo does not factor in whitespaces when computing text
|
// once. Cairo does not factor in whitespaces when computing text
|
||||||
// extents, this edge-case serves as a short-circuit to introduce
|
// extents, this edge-case serves as a short-circuit to introduce
|
||||||
|
@ -95,7 +95,7 @@ static inline Clay_Dimensions Clay_Cairo_MeasureText(Clay_StringSlice str, Clay_
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure string is null-terminated for Cairo
|
// Ensure string is null-terminated for Cairo
|
||||||
Clay_String toTerminate = (Clay_String){ str.length, str.chars };
|
Clay_String toTerminate = (Clay_String){ .chars = str.chars, .length = str.length, .isStaticallyAllocated = false };
|
||||||
char *text = Clay_Cairo__NullTerminate(&toTerminate);
|
char *text = Clay_Cairo__NullTerminate(&toTerminate);
|
||||||
char *font_family = fonts[config->fontId];
|
char *font_family = fonts[config->fontId];
|
||||||
|
|
||||||
|
@ -220,7 +220,7 @@ void Clay_Cairo_Render(Clay_RenderCommandArray commands, char** fonts) {
|
||||||
// Cairo expects null terminated strings, we need to clone
|
// Cairo expects null terminated strings, we need to clone
|
||||||
// to temporarily introduce one.
|
// to temporarily introduce one.
|
||||||
Clay_TextRenderData *config = &command->renderData.text;
|
Clay_TextRenderData *config = &command->renderData.text;
|
||||||
Clay_String toTerminate = (Clay_String){ config->stringContents.length, config->stringContents.chars };
|
Clay_String toTerminate = (Clay_String){ .chars = config->stringContents.chars, .length = config->stringContents.length, .isStaticallyAllocated = false };
|
||||||
char *text = Clay_Cairo__NullTerminate(&toTerminate);
|
char *text = Clay_Cairo__NullTerminate(&toTerminate);
|
||||||
char *font_family = fonts[config->fontId];
|
char *font_family = fonts[config->fontId];
|
||||||
|
|
||||||
|
|
273
renderers/playdate/clay_renderer_playdate.c
Normal file
273
renderers/playdate/clay_renderer_playdate.c
Normal file
|
@ -0,0 +1,273 @@
|
||||||
|
#include "pd_api.h"
|
||||||
|
#include "../../clay.h"
|
||||||
|
|
||||||
|
// Playdate drawText function expects the number of codepoints to draw, not byte length
|
||||||
|
static size_t Clay_Playdate_CountUtf8Codepoints(const char *str, size_t byteLen) {
|
||||||
|
size_t count = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < byteLen) {
|
||||||
|
uint8_t c = (uint8_t)str[i];
|
||||||
|
if ((c & 0xC0) != 0x80) {
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
// As the playdate can only display black and white, we need to resolve Clay_color to either black or white
|
||||||
|
// for both color and draw mode.
|
||||||
|
static LCDColor clayColorToLCDColor(Clay_Color color) {
|
||||||
|
if (color.r > 0 || color.g > 0 || color.b > 0) {
|
||||||
|
return kColorWhite;
|
||||||
|
}
|
||||||
|
return kColorBlack;
|
||||||
|
}
|
||||||
|
|
||||||
|
static LCDBitmapDrawMode clayColorToDrawMode(Clay_Color color) {
|
||||||
|
if (color.r > 0 || color.g > 0 || color.b > 0) {
|
||||||
|
return kDrawModeFillWhite;
|
||||||
|
}
|
||||||
|
return kDrawModeCopy;
|
||||||
|
}
|
||||||
|
|
||||||
|
static float clampCornerRadius(float yAxisSize, float radius) {
|
||||||
|
if (radius < 1.0f) {
|
||||||
|
return 0.0f;
|
||||||
|
}
|
||||||
|
if (radius > yAxisSize / 2) {
|
||||||
|
return yAxisSize / 2;
|
||||||
|
}
|
||||||
|
// Trying to draw a 2x2 ellipse seems to result in just a dot, so if
|
||||||
|
// there is a corner radius at minimum it must be 2
|
||||||
|
return CLAY__MAX(2, radius);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Clay_Playdate_Render(PlaydateAPI *pd, Clay_RenderCommandArray renderCommands, LCDFont **fonts) {
|
||||||
|
for (uint32_t i = 0; i < renderCommands.length; i++) {
|
||||||
|
Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, i);
|
||||||
|
Clay_BoundingBox boundingBox = renderCommand->boundingBox;
|
||||||
|
|
||||||
|
switch (renderCommand->commandType) {
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
|
||||||
|
Clay_RectangleRenderData *config = &renderCommand->renderData.rectangle;
|
||||||
|
|
||||||
|
float radiusTl = clampCornerRadius(boundingBox.height, config->cornerRadius.topLeft);
|
||||||
|
float radiusTr = clampCornerRadius(boundingBox.height, config->cornerRadius.topRight);
|
||||||
|
float radiusBl = clampCornerRadius(boundingBox.height, config->cornerRadius.bottomLeft);
|
||||||
|
float radiusBr = clampCornerRadius(boundingBox.height, config->cornerRadius.bottomRight);
|
||||||
|
|
||||||
|
pd->graphics->fillEllipse(
|
||||||
|
boundingBox.x, boundingBox.y,
|
||||||
|
radiusTl * 2, radiusTl * 2,
|
||||||
|
-90.0f, 0.0f,
|
||||||
|
clayColorToLCDColor(config->backgroundColor)
|
||||||
|
);
|
||||||
|
|
||||||
|
pd->graphics->fillEllipse(
|
||||||
|
boundingBox.x + boundingBox.width - radiusTr * 2, boundingBox.y,
|
||||||
|
radiusTr * 2, radiusTr * 2,
|
||||||
|
0.0f, 90.0f,
|
||||||
|
clayColorToLCDColor(config->backgroundColor)
|
||||||
|
);
|
||||||
|
|
||||||
|
pd->graphics->fillEllipse(
|
||||||
|
boundingBox.x + boundingBox.width - radiusBr * 2,
|
||||||
|
boundingBox.y + boundingBox.height - radiusBr * 2,
|
||||||
|
radiusBr * 2, radiusBr * 2,
|
||||||
|
90.0f, 180.0f,
|
||||||
|
clayColorToLCDColor(config->backgroundColor)
|
||||||
|
);
|
||||||
|
|
||||||
|
pd->graphics->fillEllipse(
|
||||||
|
boundingBox.x,
|
||||||
|
boundingBox.y + boundingBox.height - radiusBl * 2,
|
||||||
|
radiusBl * 2, radiusBl * 2,
|
||||||
|
180.0f, 270.0f,
|
||||||
|
clayColorToLCDColor(config->backgroundColor)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Top chunk
|
||||||
|
pd->graphics->fillRect(
|
||||||
|
boundingBox.x + radiusTl, boundingBox.y,
|
||||||
|
boundingBox.width - radiusTl - radiusTr,
|
||||||
|
CLAY__MAX(radiusTl, radiusTr),
|
||||||
|
clayColorToLCDColor(config->backgroundColor)
|
||||||
|
);
|
||||||
|
|
||||||
|
// bottom chunk
|
||||||
|
int bottomChunkHeight = CLAY__MAX(radiusBl, radiusBr);
|
||||||
|
pd->graphics->fillRect(
|
||||||
|
boundingBox.x + radiusBl, boundingBox.y + boundingBox.height - bottomChunkHeight,
|
||||||
|
boundingBox.width - radiusBl - radiusBr,
|
||||||
|
bottomChunkHeight,
|
||||||
|
clayColorToLCDColor(config->backgroundColor)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Middle chunk
|
||||||
|
int middleChunkHeight = boundingBox.height - CLAY__MIN(radiusBr, radiusBl) - CLAY__MIN(radiusTr, radiusTl);
|
||||||
|
pd->graphics->fillRect(
|
||||||
|
boundingBox.x + CLAY__MIN(radiusTl, radiusBl), boundingBox.y + CLAY__MIN(radiusTr, radiusTl),
|
||||||
|
boundingBox.width - radiusBl - radiusBr,
|
||||||
|
middleChunkHeight,
|
||||||
|
clayColorToLCDColor(config->backgroundColor)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Left chunk
|
||||||
|
int leftChunkHeight = boundingBox.height - radiusTl - radiusBl;
|
||||||
|
int leftChunkWidth = CLAY__MAX(radiusTl, radiusBl);
|
||||||
|
pd->graphics->fillRect(
|
||||||
|
boundingBox.x, boundingBox.y + radiusTl,
|
||||||
|
leftChunkWidth,
|
||||||
|
leftChunkHeight,
|
||||||
|
clayColorToLCDColor(config->backgroundColor)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Right chunk
|
||||||
|
int rightChunkHeight = boundingBox.height - radiusTr - radiusBr;
|
||||||
|
int rightChunkWidth = CLAY__MAX(radiusTr, radiusBr);
|
||||||
|
pd->graphics->fillRect(
|
||||||
|
boundingBox.x + boundingBox.width - rightChunkWidth, boundingBox.y + radiusTr,
|
||||||
|
rightChunkWidth,
|
||||||
|
rightChunkHeight,
|
||||||
|
clayColorToLCDColor(config->backgroundColor)
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
|
||||||
|
Clay_TextRenderData *config = &renderCommand->renderData.text;
|
||||||
|
LCDFont *font = fonts[config->fontId];
|
||||||
|
pd->graphics->setFont(font);
|
||||||
|
pd->graphics->setDrawMode(clayColorToDrawMode(config->textColor));
|
||||||
|
pd->graphics->drawText(
|
||||||
|
renderCommand->renderData.text.stringContents.chars,
|
||||||
|
Clay_Playdate_CountUtf8Codepoints(
|
||||||
|
renderCommand->renderData.text.stringContents.chars,
|
||||||
|
renderCommand->renderData.text.stringContents.length
|
||||||
|
),
|
||||||
|
kUTF8Encoding,
|
||||||
|
boundingBox.x,
|
||||||
|
boundingBox.y
|
||||||
|
);
|
||||||
|
pd->graphics->setDrawMode(kDrawModeCopy);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: {
|
||||||
|
pd->graphics->setClipRect(
|
||||||
|
boundingBox.x,boundingBox.y,
|
||||||
|
boundingBox.width, boundingBox.height
|
||||||
|
);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
|
||||||
|
pd->graphics->clearClipRect();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_IMAGE: {
|
||||||
|
Clay_ImageRenderData *config = &renderCommand->renderData.image;
|
||||||
|
LCDBitmap *texture = config->imageData;
|
||||||
|
int texWidth;
|
||||||
|
int texHeight;
|
||||||
|
pd->graphics->getBitmapData(texture, &texWidth, &texHeight, NULL, NULL, NULL);
|
||||||
|
if (texWidth != boundingBox.width || texHeight != boundingBox.height) {
|
||||||
|
pd->graphics->drawScaledBitmap(
|
||||||
|
texture,
|
||||||
|
boundingBox.x, boundingBox.y,
|
||||||
|
boundingBox.width / texWidth,
|
||||||
|
boundingBox.height / texHeight
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
pd->graphics->drawBitmap(texture, boundingBox.x, boundingBox.y, kBitmapUnflipped);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_BORDER: {
|
||||||
|
Clay_BorderRenderData *config = &renderCommand->renderData.border;
|
||||||
|
|
||||||
|
float radiusTl = clampCornerRadius(boundingBox.height, config->cornerRadius.topLeft);
|
||||||
|
float radiusTr = clampCornerRadius(boundingBox.height, config->cornerRadius.topRight);
|
||||||
|
float radiusBl = clampCornerRadius(boundingBox.height, config->cornerRadius.bottomLeft);
|
||||||
|
float radiusBr = clampCornerRadius(boundingBox.height, config->cornerRadius.bottomRight);
|
||||||
|
|
||||||
|
if (config->width.top > 0) {
|
||||||
|
pd->graphics->drawEllipse(
|
||||||
|
boundingBox.x, boundingBox.y,
|
||||||
|
radiusTl * 2, radiusTl * 2,
|
||||||
|
config->width.top,
|
||||||
|
-90.0f, 0.0f,
|
||||||
|
clayColorToLCDColor(config->color)
|
||||||
|
);
|
||||||
|
|
||||||
|
pd->graphics->drawLine(
|
||||||
|
boundingBox.x + radiusTl, boundingBox.y,
|
||||||
|
boundingBox.x + boundingBox.width - radiusTr - config->width.right, boundingBox.y,
|
||||||
|
config->width.top,
|
||||||
|
clayColorToLCDColor(config->color)
|
||||||
|
);
|
||||||
|
|
||||||
|
pd->graphics->drawEllipse(
|
||||||
|
boundingBox.x + boundingBox.width - radiusTr * 2, boundingBox.y,
|
||||||
|
radiusTr * 2, radiusTr * 2,
|
||||||
|
config->width.top,
|
||||||
|
0.0f, 90.0f,
|
||||||
|
clayColorToLCDColor(config->color)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->width.right > 0 && radiusTr + radiusBr <= boundingBox.height) {
|
||||||
|
pd->graphics->drawLine(
|
||||||
|
boundingBox.x + boundingBox.width - config->width.right,
|
||||||
|
boundingBox.y + radiusTr,
|
||||||
|
boundingBox.x + boundingBox.width - config->width.right,
|
||||||
|
boundingBox.y + boundingBox.height - radiusBr - config->width.bottom,
|
||||||
|
config->width.right,
|
||||||
|
clayColorToLCDColor(config->color)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->width.bottom > 0) {
|
||||||
|
pd->graphics->drawEllipse(
|
||||||
|
boundingBox.x + boundingBox.width - radiusBr * 2,
|
||||||
|
boundingBox.y + boundingBox.height - radiusBr * 2,
|
||||||
|
radiusBr * 2, radiusBr * 2,
|
||||||
|
config->width.bottom,
|
||||||
|
90.0f, 180.0f,
|
||||||
|
clayColorToLCDColor(config->color)
|
||||||
|
);
|
||||||
|
|
||||||
|
pd->graphics->drawLine(
|
||||||
|
boundingBox.x + boundingBox.width - radiusBr - config->width.right,
|
||||||
|
boundingBox.y + boundingBox.height - config->width.bottom,
|
||||||
|
boundingBox.x + radiusBl,
|
||||||
|
boundingBox.y + boundingBox.height - config->width.bottom,
|
||||||
|
config->width.bottom,
|
||||||
|
clayColorToLCDColor(config->color)
|
||||||
|
);
|
||||||
|
|
||||||
|
pd->graphics->drawEllipse(
|
||||||
|
boundingBox.x,
|
||||||
|
boundingBox.y + boundingBox.height - radiusBl * 2,
|
||||||
|
radiusBl * 2, radiusBl * 2,
|
||||||
|
config->width.bottom,
|
||||||
|
180.0f, 270.0f,
|
||||||
|
clayColorToLCDColor(config->color)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config->width.left > 0 && radiusBl + radiusTl < boundingBox.height) {
|
||||||
|
pd->graphics->drawLine(
|
||||||
|
boundingBox.x, boundingBox.y + boundingBox.height - radiusBl - config->width.bottom,
|
||||||
|
boundingBox.x, boundingBox.y + radiusTl,
|
||||||
|
config->width.left,
|
||||||
|
clayColorToLCDColor(config->color)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
pd->system->logToConsole("Error: unhandled render command: %d\n", renderCommand->commandType);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -87,6 +87,8 @@ static inline Clay_Dimensions Raylib_MeasureText(Clay_StringSlice text, Clay_Tex
|
||||||
|
|
||||||
float maxTextWidth = 0.0f;
|
float maxTextWidth = 0.0f;
|
||||||
float lineTextWidth = 0;
|
float lineTextWidth = 0;
|
||||||
|
int maxLineCharCount = 0;
|
||||||
|
int lineCharCount = 0;
|
||||||
|
|
||||||
float textHeight = config->fontSize;
|
float textHeight = config->fontSize;
|
||||||
Font* fonts = (Font*)userData;
|
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;
|
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') {
|
if (text.chars[i] == '\n') {
|
||||||
maxTextWidth = fmax(maxTextWidth, lineTextWidth);
|
maxTextWidth = fmax(maxTextWidth, lineTextWidth);
|
||||||
|
maxLineCharCount = CLAY__MAX(maxLineCharCount, lineCharCount);
|
||||||
lineTextWidth = 0;
|
lineTextWidth = 0;
|
||||||
|
lineCharCount = 0;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
int index = text.chars[i] - 32;
|
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);
|
maxTextWidth = fmax(maxTextWidth, lineTextWidth);
|
||||||
|
maxLineCharCount = CLAY__MAX(maxLineCharCount, lineCharCount);
|
||||||
|
|
||||||
textSize.width = maxTextWidth * scaleFactor;
|
textSize.width = maxTextWidth * scaleFactor + (lineCharCount * config->letterSpacing);
|
||||||
textSize.height = textHeight;
|
textSize.height = textHeight;
|
||||||
|
|
||||||
return textSize;
|
return textSize;
|
||||||
|
@ -145,7 +150,7 @@ void Clay_Raylib_Render(Clay_RenderCommandArray renderCommands, Font* fonts)
|
||||||
for (int j = 0; j < renderCommands.length; j++)
|
for (int j = 0; j < renderCommands.length; j++)
|
||||||
{
|
{
|
||||||
Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, 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)
|
switch (renderCommand->commandType)
|
||||||
{
|
{
|
||||||
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
|
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) {
|
if (tintColor.r == 0 && tintColor.g == 0 && tintColor.b == 0 && tintColor.a == 0) {
|
||||||
tintColor = (Clay_Color) { 255, 255, 255, 255 };
|
tintColor = (Clay_Color) { 255, 255, 255, 255 };
|
||||||
}
|
}
|
||||||
DrawTextureEx(
|
DrawTexturePro(
|
||||||
imageTexture,
|
imageTexture,
|
||||||
(Vector2){boundingBox.x, boundingBox.y},
|
(Rectangle) { 0, 0, imageTexture.width, imageTexture.height },
|
||||||
|
(Rectangle){boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height},
|
||||||
|
(Vector2) {},
|
||||||
0,
|
0,
|
||||||
boundingBox.width / (float)imageTexture.width,
|
|
||||||
CLAY_COLOR_TO_RAYLIB_COLOR(tintColor));
|
CLAY_COLOR_TO_RAYLIB_COLOR(tintColor));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
194
renderers/terminal/clay_renderer_terminal_ansi.c
Normal file
194
renderers/terminal/clay_renderer_terminal_ansi.c
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "string.h"
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "stdlib.h"
|
||||||
|
|
||||||
|
#ifdef CLAY_OVERFLOW_TRAP
|
||||||
|
#include "signal.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static inline void Console_MoveCursor(int x, int y) {
|
||||||
|
printf("\033[%d;%dH", y + 1, x + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Clay_PointIsInsideRect(Clay_Vector2 point, Clay_BoundingBox rect) {
|
||||||
|
// TODO this function is a copy of Clay__PointIsInsideRect but that one is internal, I don't know if we want
|
||||||
|
// TODO to expose Clay__PointIsInsideRect
|
||||||
|
return point.x >= rect.x && point.x < rect.x + rect.width && point.y >= rect.y && point.y < rect.y + rect.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void Console_DrawRectangle(int x0, int y0, int width, int height, Clay_Color color,
|
||||||
|
Clay_BoundingBox scissorBox) {
|
||||||
|
float average = (color.r + color.g + color.b + color.a) / 4 / 255;
|
||||||
|
|
||||||
|
for (int y = y0; y < height + y0; y++) {
|
||||||
|
for (int x = x0; x < width + x0; x++) {
|
||||||
|
if (!Clay_PointIsInsideRect((Clay_Vector2) {.x = x, .y = y}, scissorBox)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console_MoveCursor(x, y);
|
||||||
|
// TODO this should be replaced by a better logarithmic scale if we're doing black and white
|
||||||
|
if (average > 0.75) {
|
||||||
|
printf("█");
|
||||||
|
} else if (average > 0.5) {
|
||||||
|
printf("▓");
|
||||||
|
} else if (average > 0.25) {
|
||||||
|
printf("▒");
|
||||||
|
} else {
|
||||||
|
printf("░");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline Clay_Dimensions
|
||||||
|
Console_MeasureText(Clay_StringSlice text, Clay_TextElementConfig *config, void *userData) {
|
||||||
|
Clay_Dimensions textSize = {0};
|
||||||
|
int columnWidth = *(int *) userData;
|
||||||
|
|
||||||
|
// TODO this function is very wrong, it measures in characters, I have no idea what is the size in pixels
|
||||||
|
|
||||||
|
float maxTextWidth = 0.0f;
|
||||||
|
float lineTextWidth = 0;
|
||||||
|
|
||||||
|
float textHeight = 1;
|
||||||
|
|
||||||
|
for (int i = 0; i < text.length; ++i) {
|
||||||
|
if (text.chars[i] == '\n') {
|
||||||
|
maxTextWidth = maxTextWidth > lineTextWidth ? maxTextWidth : lineTextWidth;
|
||||||
|
lineTextWidth = 0;
|
||||||
|
textHeight++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lineTextWidth++;
|
||||||
|
}
|
||||||
|
|
||||||
|
maxTextWidth = maxTextWidth > lineTextWidth ? maxTextWidth : lineTextWidth;
|
||||||
|
|
||||||
|
textSize.width = maxTextWidth * columnWidth;
|
||||||
|
textSize.height = textHeight * columnWidth;
|
||||||
|
|
||||||
|
return textSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Clay_Terminal_Render(Clay_RenderCommandArray renderCommands, int width, int height, int columnWidth) {
|
||||||
|
printf("\033[H\033[J"); // Clear
|
||||||
|
|
||||||
|
const Clay_BoundingBox fullWindow = {
|
||||||
|
.x = 0,
|
||||||
|
.y = 0,
|
||||||
|
.width = (float) width,
|
||||||
|
.height = (float) height,
|
||||||
|
};
|
||||||
|
|
||||||
|
Clay_BoundingBox scissorBox = fullWindow;
|
||||||
|
|
||||||
|
for (int j = 0; j < renderCommands.length; j++) {
|
||||||
|
Clay_RenderCommand *renderCommand = Clay_RenderCommandArray_Get(&renderCommands, j);
|
||||||
|
Clay_BoundingBox boundingBox = (Clay_BoundingBox) {
|
||||||
|
.x = (int)((renderCommand->boundingBox.x / columnWidth) + 0.5),
|
||||||
|
.y = (int)((renderCommand->boundingBox.y / columnWidth) + 0.5),
|
||||||
|
.width = (int)((renderCommand->boundingBox.width / columnWidth) + 0.5),
|
||||||
|
.height = (int)((renderCommand->boundingBox.height / columnWidth) + 0.5),
|
||||||
|
};
|
||||||
|
switch (renderCommand->commandType) {
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_TEXT: {
|
||||||
|
Clay_TextRenderData data = renderCommand->renderData.text;
|
||||||
|
Clay_StringSlice text = data.stringContents;
|
||||||
|
int y = 0;
|
||||||
|
for (int x = 0; x < text.length; x++) {
|
||||||
|
if (text.chars[x] == '\n') {
|
||||||
|
y++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cursorX = (int) boundingBox.x + x;
|
||||||
|
int cursorY = (int) boundingBox.y + y;
|
||||||
|
if (cursorY > scissorBox.y + scissorBox.height) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!Clay_PointIsInsideRect((Clay_Vector2) {.x = cursorX, .y = cursorY}, scissorBox)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Console_MoveCursor(cursorX, cursorY);
|
||||||
|
printf("%c", text.chars[x]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_START: {
|
||||||
|
scissorBox = boundingBox;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_SCISSOR_END: {
|
||||||
|
scissorBox = fullWindow;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_RECTANGLE: {
|
||||||
|
Clay_RectangleRenderData data = renderCommand->renderData.rectangle;
|
||||||
|
Console_DrawRectangle(
|
||||||
|
(int) boundingBox.x,
|
||||||
|
(int) boundingBox.y,
|
||||||
|
(int) boundingBox.width,
|
||||||
|
(int) boundingBox.height,
|
||||||
|
data.backgroundColor,
|
||||||
|
scissorBox);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CLAY_RENDER_COMMAND_TYPE_BORDER: {
|
||||||
|
Clay_BorderRenderData data = renderCommand->renderData.border;
|
||||||
|
// Left border
|
||||||
|
if (data.width.left > 0) {
|
||||||
|
Console_DrawRectangle(
|
||||||
|
(int) (boundingBox.x),
|
||||||
|
(int) (boundingBox.y + data.cornerRadius.topLeft),
|
||||||
|
(int) data.width.left,
|
||||||
|
(int) (boundingBox.height - data.cornerRadius.topLeft - data.cornerRadius.bottomLeft),
|
||||||
|
data.color,
|
||||||
|
scissorBox);
|
||||||
|
}
|
||||||
|
// Right border
|
||||||
|
if (data.width.right > 0) {
|
||||||
|
Console_DrawRectangle(
|
||||||
|
(int) (boundingBox.x + boundingBox.width - data.width.right),
|
||||||
|
(int) (boundingBox.y + data.cornerRadius.topRight),
|
||||||
|
(int) data.width.right,
|
||||||
|
(int) (boundingBox.height - data.cornerRadius.topRight - data.cornerRadius.bottomRight),
|
||||||
|
data.color,
|
||||||
|
scissorBox);
|
||||||
|
}
|
||||||
|
// Top border
|
||||||
|
if (data.width.top > 0) {
|
||||||
|
Console_DrawRectangle(
|
||||||
|
(int) (boundingBox.x + data.cornerRadius.topLeft),
|
||||||
|
(int) (boundingBox.y),
|
||||||
|
(int) (boundingBox.width - data.cornerRadius.topLeft - data.cornerRadius.topRight),
|
||||||
|
(int) data.width.top,
|
||||||
|
data.color,
|
||||||
|
scissorBox);
|
||||||
|
}
|
||||||
|
// Bottom border
|
||||||
|
if (data.width.bottom > 0) {
|
||||||
|
Console_DrawRectangle(
|
||||||
|
(int) (boundingBox.x + data.cornerRadius.bottomLeft),
|
||||||
|
(int) (boundingBox.y + boundingBox.height - data.width.bottom),
|
||||||
|
(int) (boundingBox.width - data.cornerRadius.bottomLeft - data.cornerRadius.bottomRight),
|
||||||
|
(int) data.width.bottom,
|
||||||
|
data.color,
|
||||||
|
scissorBox);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
printf("Error: unhandled render command.");
|
||||||
|
#ifdef CLAY_OVERFLOW_TRAP
|
||||||
|
raise(SIGTRAP);
|
||||||
|
#endif
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Console_MoveCursor(-1, -1); // TODO make the user not be able to write
|
||||||
|
}
|
Loading…
Reference in a new issue