diff --git a/README.md b/README.md index a7c8467..20965bb 100644 --- a/README.md +++ b/README.md @@ -178,18 +178,10 @@ For help starting out or to discuss clay, considering joining [the discord serve - [Clay_GetScrollContainerData](#clay_getscrollcontainerdata) - [Clay_GetElementId](#clay_getelementid) - [Element Macros](#element-macros) - - [CLAY](#clay-1) + - [CLAY](#clay) - [CLAY_ID](#clay_id) - [CLAY_IDI](#clay_idi) - - [CLAY_LAYOUT](#clay_layout) - - [CLAY_RECTANGLE](#clay_rectangle) - - [CLAY_TEXT](#clay_text) - - [CLAY_IMAGE](#clay_image) - - [CLAY_SCROLL](#clay_scroll) - - [CLAY_BORDER](#clay_border) - - [CLAY_FLOATING](#clay_floating) - - [CLAY_CUSTOM_ELEMENT](#clay_custom_element) - - [Data Structures & Defs](data-structures--definitions) + - [Data Structures & Defs](#data-structures--definitions) - [Clay_String](#clay_string) - [Clay_ElementId](#clay_elementid) - [Clay_RenderCommandArray](#clay_rendercommandarray) @@ -350,7 +342,11 @@ If this is an issue for you, performing layout twice per frame with the same dat ### Scrolling Elements -Elements are configured as scrollable with the `CLAY_SCROLL` macro. To make scroll containers respond to mouse wheel and scroll events, two functions need to be called before `BeginLayout()`: +Elements are configured as scrollable with the `.clip` configuration. Clipping instructs the renderer to not draw any pixels outside the clipped element's boundaries, and by specifying the `.childOffset` field, the clipped element's contents can be shifted around to provide "scrolling" behaviour. + +You can either calculate scrolling yourself and simply provide the current offset each frame to `.childOffset`, or alternatively, Clay provides a built in mechanism for tracking and updating scroll container offsets, detailed below. + +To make scroll containers respond to mouse wheel and scroll events, two functions need to be called before `BeginLayout()`: ```C Clay_Vector2 mousePosition = { x, y }; // Reminder: Clay_SetPointerState must be called before Clay_UpdateScrollContainers otherwise it will have no effect @@ -362,9 +358,17 @@ Clay_UpdateScrollContainers( float deltaTime, // Time since last frame in seconds as a float e.g. 8ms is 0.008f ); // ... +// 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() }) { + // Scrolling contents +} +// .childOffset can be provided directly if you would prefer to manage scrolling outside of clay +CLAY({ .clip = vertical, .childOffset = myData.scrollContainer.offset }) { + // Scrolling contents +} ``` -More specific details can be found in the full [Scroll API](#clay_scroll). +More specific details can be found in the docs for [Clay_UpdateScrollContainers](#clay_updatescrollcontainers), [Clay_SetPointerState](#clay_setpointerstate), [Clay_ClipElementConfig](#clay_clipelementconfig) and [Clay_GetScrollOffset](#clay_getscrolloffset). ### Floating Elements ("Absolute" Positioning) @@ -658,6 +662,25 @@ Touch / drag scrolling only occurs if the `enableDragScrolling` parameter is `tr --- +### Clay_GetScrollOffset + +`Clay_Vector2 Clay_GetScrollOffset()` + +Returns the internally stored scroll offset for the currently open element. + +Generally intended for use with [clip elements](#clay_clipelementconfig) and the `.childOffset` field to create scrolling containers. + +See [Scrolling Elements](#scrolling-elements) for more details. + +```C +// Create a horizontally scrolling container +CLAY({ + .clip = { .horizontal = true, .childOffset = Clay_GetScrollOffset() } +}) +``` + +--- + ### Clay_BeginLayout `void Clay_BeginLayout()` @@ -767,7 +790,7 @@ CLAY({ .id = CLAY_ID("Outer"), .layout = { .padding = CLAY_PADDING_ALL(16) } }) .layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 16 }, .backgroundColor = { 200, 200, 100, 255 }, .cornerRadius = CLAY_CORNER_RADIUS(10), - .scroll = { .vertical = true } + .clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() } }) { // child elements } @@ -1034,7 +1057,7 @@ typedef struct { Clay_ImageElementConfig image; Clay_FloatingElementConfig floating; Clay_CustomElementConfig custom; - Clay_ScrollElementConfig scroll; + Clay_ClipElementConfig clip; Clay_BorderElementConfig border; void *userData; } Clay_ElementDeclaration; @@ -1101,11 +1124,13 @@ Uses [Clay_CustomElementConfig](#clay_customelementconfig). Configures the eleme --- -**`.scroll`** - `Clay_ScrollElementConfig` +**`.clip`** - `Clay_ClipElementConfig` -`CLAY({ .scroll = { .vertical = true } })` +`CLAY({ .clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() } })` -Uses [Clay_ScrollElementConfig](#clay_scrollelementconfig). Configures the element as a scroll element, which causes child elements to be clipped / masked if they overflow, and together with [Clay_UpdateScrollContainer](#clay_updatescrollcontainers) enables scrolling of child contents. +Uses [Clay_ClipElementConfig](#clay_scrollelementconfig). Configures the element as a clip element, which causes child elements to be clipped / masked if they overflow, and together with the functions listed in [Scrolling Elements](#scrolling-elements) enables scrolling of child contents. + +An image demonstrating the concept of clipping which prevents rendering of a child elements pixels if they fall outside the bounds of the parent element. --- @@ -1140,7 +1165,7 @@ CLAY({ .color = { 200, 200, 100, 255 }, .cornerRadius = CLAY_CORNER_RADIUS(10) } CLAY({ .backgroundColor = { 200, 200, 100, 255 }, .cornerRadius = CLAY_CORNER_RADIUS(10) - CLAY_SCROLL({ .vertical = true }) + .clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() } ) { // child elements } @@ -1312,22 +1337,22 @@ Element is subject to [culling](#visibility-culling). Otherwise, a single `Clay_ --- -### Clay_ScrollElementConfig +### Clay_ClipElementConfig **Usage** -`CLAY({ .scroll = { ...scroll config } }) {}` +`CLAY({ .clip = { ...clip config } }) {}` **Notes** -`Clay_ScrollElementConfig` configures the element as a scrolling container, enabling masking of children that extend beyond its boundaries. +`Clay_ClipElementConfig` configures the element as a clipping container, enabling masking of children that extend beyond its boundaries. Note: In order to process scrolling based on pointer position and mouse wheel or touch interactions, you must call `Clay_SetPointerState()` and `Clay_UpdateScrollContainers()` _before_ calling `BeginLayout`. **Struct Definition (Pseudocode)** ```C -Clay_ScrollElementConfig { +Clay_ClipElementConfig { bool horizontal; bool vertical; }; @@ -1337,30 +1362,30 @@ Clay_ScrollElementConfig { **`.horizontal`** - `bool` -`CLAY({ .scroll = { .horizontal = true } })` +`CLAY({ .clip = { .horizontal = true } })` -Enables or disables horizontal scrolling for this container element. +Enables or disables horizontal clipping for this container element. --- **`.vertical`** - `bool` -`CLAY({ .scroll = { .vertical = true } })` +`CLAY({ .clip = { .vertical = true } })` -Enables or disables vertical scrolling for this container element. +Enables or disables vertical clipping for this container element. --- **Rendering** -Enabling scroll for an element will result in two additional render commands: +Enabling clip for an element will result in two additional render commands: - `commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_START`, which should create a rectangle mask with its `boundingBox` and is **not** subject to [culling](#visibility-culling) - `commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_END`, which disables the previous rectangle mask and is **not** subject to [culling](#visibility-culling) **Examples** ```C -CLAY({ .scroll = { .vertical = true } }) { +CLAY({ .clip = { .vertical = true } }) { // Create child content with a fixed height of 5000 CLAY({ .id = CLAY_ID("ScrollInner"), .layout = { .sizing = { .height = CLAY_SIZING_FIXED(5000) } } }) {} } @@ -2031,7 +2056,7 @@ typedef struct { // The outer dimensions of the inner scroll container content, including the padding of the parent scroll container. Clay_Dimensions contentDimensions; // The config that was originally passed to the scroll element. - Clay_ScrollElementConfig config; + Clay_ClipElementConfig config; // Indicates whether an actual scroll container matched the provided ID or if the default struct was returned. bool found; } Clay_ScrollContainerData; @@ -2081,9 +2106,9 @@ Dimensions representing the inner width and height of the content _inside_ the s --- -**`.config`** - `Clay_ScrollElementConfig` +**`.config`** - `Clay_ClipElementConfig` -The [Clay_ScrollElementConfig](#clay_scroll) for the matching scroll container element. +The [Clay_ClipElementConfig](#clay_scroll) for the matching scroll container element. --- diff --git a/examples/clay-official-website/main.c b/examples/clay-official-website/main.c index 0c5d632..cb2b522 100644 --- a/examples/clay-official-website/main.c +++ b/examples/clay-official-website/main.c @@ -379,7 +379,7 @@ Clay_RenderCommandArray CreateLayout(bool mobileScreen, float lerpValue) { CLAY({ .id = CLAY_ID("TopBorder5"), .layout = topBorderConfig, .backgroundColor = COLOR_TOP_BORDER_1 }) {} CLAY({ .id = CLAY_ID("OuterScrollContainer"), .layout = { .sizing = { CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0) }, .layoutDirection = CLAY_TOP_TO_BOTTOM }, - .scroll = { .vertical = true }, + .clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() }, .border = { .width = { .betweenChildren = 2 }, .color = COLOR_RED } }) { if (mobileScreen) { diff --git a/examples/raylib-sidebar-scrolling-container/main.c b/examples/raylib-sidebar-scrolling-container/main.c index 52797a8..8265eef 100644 --- a/examples/raylib-sidebar-scrolling-container/main.c +++ b/examples/raylib-sidebar-scrolling-container/main.c @@ -127,7 +127,7 @@ Clay_RenderCommandArray CreateLayout(void) { .attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID, .offset = { .y = -(scrollData.scrollPosition->y / scrollData.contentDimensions.height) * scrollData.scrollContainerDimensions.height }, .zIndex = 1, - .parentId = Clay_GetElementId(CLAY_STRING("MainContent")).id, + .parentId = 55, .attachPoints = { .element = CLAY_ATTACH_POINT_RIGHT_TOP, .parent = CLAY_ATTACH_POINT_RIGHT_TOP } } }) { diff --git a/examples/shared-layouts/clay-video-demo.c b/examples/shared-layouts/clay-video-demo.c index e7400a3..02a6a3b 100644 --- a/examples/shared-layouts/clay-video-demo.c +++ b/examples/shared-layouts/clay-video-demo.c @@ -235,7 +235,7 @@ Clay_RenderCommandArray ClayVideoDemo_CreateLayout(ClayVideoDemo_Data *data) { CLAY({ .id = CLAY_ID("MainContent"), .backgroundColor = contentBackgroundColor, - .scroll = { .vertical = true }, + .clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() }, .layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM, .childGap = 16,