diff --git a/clay.h b/clay.h index fef43b8..37af4d3 100644 --- a/clay.h +++ b/clay.h @@ -492,11 +492,12 @@ CLAY__WRAPPER_STRUCT(Clay_CustomElementConfig); // Controls the axis on which an element switches to "scrolling", which clips the contents and allows scrolling in that direction. typedef struct { - bool horizontal; // Clip overflowing elements on the X axis and allow scrolling left and right. - bool vertical; // Clip overflowing elements on the YU axis and allow scrolling up and down. -} Clay_ScrollElementConfig; + bool horizontal; // Clip overflowing elements on the X axis. + bool vertical; // Clip overflowing elements on the Y axis. + Clay_Vector2 childOffset; // Offsets the x,y positions of all child elements. Used primarily for scrolling containers. +} Clay_ClipElementConfig; -CLAY__WRAPPER_STRUCT(Clay_ScrollElementConfig); +CLAY__WRAPPER_STRUCT(Clay_ClipElementConfig); // Border ----------------------------- @@ -578,7 +579,7 @@ typedef struct { typedef struct { bool horizontal; bool vertical; -} Clay_ScrollRenderData; +} Clay_ClipRenderData; // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_BORDER typedef struct { @@ -604,8 +605,8 @@ typedef union { Clay_CustomRenderData custom; // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_BORDER Clay_BorderRenderData border; - // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_SCROLL - Clay_ScrollRenderData scroll; + // Render command data when commandType == CLAY_RENDER_COMMAND_TYPE_SCISSOR_START|END + Clay_ClipRenderData clip; } Clay_RenderData; // Miscellaneous Structs & Enums --------------------------------- @@ -619,8 +620,8 @@ typedef struct { Clay_Dimensions scrollContainerDimensions; // 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; + // The config that was originally passed to the clip element. + Clay_ClipElementConfig config; // Indicates whether an actual scroll container matched the provided ID or if the default struct was returned. bool found; } Clay_ScrollContainerData; @@ -730,8 +731,8 @@ typedef struct { Clay_FloatingElementConfig floating; // Used to create CUSTOM render commands, usually to render element types not supported by Clay. Clay_CustomElementConfig custom; - // Controls whether an element should clip its contents and allow scrolling rather than expanding to contain them. - Clay_ScrollElementConfig scroll; + // Controls whether an element should clip its contents, as well as providing child x,y offset configuration for scrolling. + Clay_ClipElementConfig clip; // Controls settings related to element borders, and will generate BORDER render commands. Clay_BorderElementConfig border; // A pointer that will be transparently passed through to resulting render commands. @@ -816,6 +817,9 @@ CLAY_DLL_EXPORT void Clay_SetCurrentContext(Clay_Context* context); // - scrollDelta is the amount to scroll this frame on each axis in pixels. // - deltaTime is the time in seconds since the last "frame" (scroll update) CLAY_DLL_EXPORT void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime); +// Returns the internally stored scroll offset for the currently open element. +// Generally intended for use with clip elements to create scrolling containers. +CLAY_DLL_EXPORT Clay_Vector2 Clay_GetScrollOffset(); // Updates the layout dimensions in response to the window or outer container being resized. CLAY_DLL_EXPORT void Clay_SetLayoutDimensions(Clay_Dimensions dimensions); // Called before starting any layout declarations. @@ -1035,7 +1039,7 @@ CLAY__ARRAY_DEFINE(Clay_TextElementConfig, Clay__TextElementConfigArray) CLAY__ARRAY_DEFINE(Clay_ImageElementConfig, Clay__ImageElementConfigArray) CLAY__ARRAY_DEFINE(Clay_FloatingElementConfig, Clay__FloatingElementConfigArray) CLAY__ARRAY_DEFINE(Clay_CustomElementConfig, Clay__CustomElementConfigArray) -CLAY__ARRAY_DEFINE(Clay_ScrollElementConfig, Clay__ScrollElementConfigArray) +CLAY__ARRAY_DEFINE(Clay_ClipElementConfig, Clay__ClipElementConfigArray) CLAY__ARRAY_DEFINE(Clay_BorderElementConfig, Clay__BorderElementConfigArray) CLAY__ARRAY_DEFINE(Clay_String, Clay__StringArray) CLAY__ARRAY_DEFINE(Clay_SharedElementConfig, Clay__SharedElementConfigArray) @@ -1045,7 +1049,7 @@ typedef CLAY_PACKED_ENUM { CLAY__ELEMENT_CONFIG_TYPE_NONE, CLAY__ELEMENT_CONFIG_TYPE_BORDER, CLAY__ELEMENT_CONFIG_TYPE_FLOATING, - CLAY__ELEMENT_CONFIG_TYPE_SCROLL, + CLAY__ELEMENT_CONFIG_TYPE_CLIP, CLAY__ELEMENT_CONFIG_TYPE_IMAGE, CLAY__ELEMENT_CONFIG_TYPE_TEXT, CLAY__ELEMENT_CONFIG_TYPE_CUSTOM, @@ -1057,7 +1061,7 @@ typedef union { Clay_ImageElementConfig *imageElementConfig; Clay_FloatingElementConfig *floatingElementConfig; Clay_CustomElementConfig *customElementConfig; - Clay_ScrollElementConfig *scrollElementConfig; + Clay_ClipElementConfig *clipElementConfig; Clay_BorderElementConfig *borderElementConfig; Clay_SharedElementConfig *sharedElementConfig; } Clay_ElementConfigUnion; @@ -1219,7 +1223,7 @@ struct Clay_Context { Clay__TextElementConfigArray textElementConfigs; Clay__ImageElementConfigArray imageElementConfigs; Clay__FloatingElementConfigArray floatingElementConfigs; - Clay__ScrollElementConfigArray scrollElementConfigs; + Clay__ClipElementConfigArray clipElementConfigs; Clay__CustomElementConfigArray customElementConfigs; Clay__BorderElementConfigArray borderElementConfigs; Clay__SharedElementConfigArray sharedElementConfigs; @@ -1287,7 +1291,7 @@ Clay_TextElementConfig * Clay__StoreTextElementConfig(Clay_TextElementConfig con Clay_ImageElementConfig * Clay__StoreImageElementConfig(Clay_ImageElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_ImageElementConfig_DEFAULT : Clay__ImageElementConfigArray_Add(&Clay_GetCurrentContext()->imageElementConfigs, config); } Clay_FloatingElementConfig * Clay__StoreFloatingElementConfig(Clay_FloatingElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_FloatingElementConfig_DEFAULT : Clay__FloatingElementConfigArray_Add(&Clay_GetCurrentContext()->floatingElementConfigs, config); } Clay_CustomElementConfig * Clay__StoreCustomElementConfig(Clay_CustomElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_CustomElementConfig_DEFAULT : Clay__CustomElementConfigArray_Add(&Clay_GetCurrentContext()->customElementConfigs, config); } -Clay_ScrollElementConfig * Clay__StoreScrollElementConfig(Clay_ScrollElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_ScrollElementConfig_DEFAULT : Clay__ScrollElementConfigArray_Add(&Clay_GetCurrentContext()->scrollElementConfigs, config); } +Clay_ClipElementConfig * Clay__StoreClipElementConfig(Clay_ClipElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_ClipElementConfig_DEFAULT : Clay__ClipElementConfigArray_Add(&Clay_GetCurrentContext()->clipElementConfigs, config); } Clay_BorderElementConfig * Clay__StoreBorderElementConfig(Clay_BorderElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_BorderElementConfig_DEFAULT : Clay__BorderElementConfigArray_Add(&Clay_GetCurrentContext()->borderElementConfigs, config); } Clay_SharedElementConfig * Clay__StoreSharedElementConfig(Clay_SharedElementConfig config) { return Clay_GetCurrentContext()->booleanWarnings.maxElementsExceeded ? &Clay_SharedElementConfig_DEFAULT : Clay__SharedElementConfigArray_Add(&Clay_GetCurrentContext()->sharedElementConfigs, config); } @@ -1759,9 +1763,9 @@ void Clay__CloseElement(void) { bool elementHasScrollVertical = false; for (int32_t i = 0; i < openLayoutElement->elementConfigs.length; i++) { Clay_ElementConfig *config = Clay__ElementConfigArraySlice_Get(&openLayoutElement->elementConfigs, i); - if (config->type == CLAY__ELEMENT_CONFIG_TYPE_SCROLL) { - elementHasScrollHorizontal = config->config.scrollElementConfig->horizontal; - elementHasScrollVertical = config->config.scrollElementConfig->vertical; + if (config->type == CLAY__ELEMENT_CONFIG_TYPE_CLIP) { + elementHasScrollHorizontal = config->config.clipElementConfig->horizontal; + elementHasScrollVertical = config->config.clipElementConfig->vertical; context->openClipElementStack.length--; break; } else if (config->type == CLAY__ELEMENT_CONFIG_TYPE_FLOATING) { @@ -2072,8 +2076,8 @@ void Clay__ConfigureOpenElementPtr(const Clay_ElementDeclaration *declaration) { openLayoutElementId = Clay__GenerateIdForAnonymousElement(openLayoutElement); } - if (declaration->scroll.horizontal | declaration->scroll.vertical) { - Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .scrollElementConfig = Clay__StoreScrollElementConfig(declaration->scroll) }, CLAY__ELEMENT_CONFIG_TYPE_SCROLL); + if (declaration->clip.horizontal | declaration->clip.vertical) { + Clay__AttachElementConfig(CLAY__INIT(Clay_ElementConfigUnion) { .clipElementConfig = Clay__StoreClipElementConfig(declaration->clip) }, CLAY__ELEMENT_CONFIG_TYPE_CLIP); Clay__int32_tArray_Add(&context->openClipElementStack, (int)openLayoutElement->id); // Retrieve or create cached data to track scroll position across frames Clay__ScrollContainerDataInternal *scrollOffset = CLAY__NULL; @@ -2116,7 +2120,7 @@ void Clay__InitializeEphemeralMemory(Clay_Context* context) { context->textElementConfigs = Clay__TextElementConfigArray_Allocate_Arena(maxElementCount, arena); context->imageElementConfigs = Clay__ImageElementConfigArray_Allocate_Arena(maxElementCount, arena); context->floatingElementConfigs = Clay__FloatingElementConfigArray_Allocate_Arena(maxElementCount, arena); - context->scrollElementConfigs = Clay__ScrollElementConfigArray_Allocate_Arena(maxElementCount, arena); + context->clipElementConfigs = Clay__ClipElementConfigArray_Allocate_Arena(maxElementCount, arena); context->customElementConfigs = Clay__CustomElementConfigArray_Allocate_Arena(maxElementCount, arena); context->borderElementConfigs = Clay__BorderElementConfigArray_Allocate_Arena(maxElementCount, arena); context->sharedElementConfigs = Clay__SharedElementConfigArray_Allocate_Arena(maxElementCount, arena); @@ -2255,8 +2259,8 @@ void Clay__SizeContainersAlongAxis(bool xAxis) { float sizeToDistribute = parentSize - parentPadding - innerContentSize; // The content is too large, compress the children as much as possible if (sizeToDistribute < 0) { - // If the parent can scroll in the axis direction in this direction, don't compress children, just leave them alone - Clay_ScrollElementConfig *scrollElementConfig = Clay__FindElementConfigWithType(parent, CLAY__ELEMENT_CONFIG_TYPE_SCROLL).scrollElementConfig; + // If the parent clips content in this axis direction, don't compress children, just leave them alone + Clay_ClipElementConfig *scrollElementConfig = Clay__FindElementConfigWithType(parent, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig; if (scrollElementConfig) { if (((xAxis && scrollElementConfig->horizontal) || (!xAxis && scrollElementConfig->vertical))) { continue; @@ -2357,9 +2361,9 @@ void Clay__SizeContainersAlongAxis(bool xAxis) { float maxSize = parentSize - parentPadding; // If we're laying out the children of a scroll panel, grow containers expand to the size of the inner content, not the outer container - if (Clay__ElementHasConfig(parent, CLAY__ELEMENT_CONFIG_TYPE_SCROLL)) { - Clay_ScrollElementConfig *scrollElementConfig = Clay__FindElementConfigWithType(parent, CLAY__ELEMENT_CONFIG_TYPE_SCROLL).scrollElementConfig; - if (((xAxis && scrollElementConfig->horizontal) || (!xAxis && scrollElementConfig->vertical))) { + if (Clay__ElementHasConfig(parent, CLAY__ELEMENT_CONFIG_TYPE_CLIP)) { + Clay_ClipElementConfig *clipElementConfig = Clay__FindElementConfigWithType(parent, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig; + if (((xAxis && clipElementConfig->horizontal) || (!xAxis && clipElementConfig->vertical))) { maxSize = CLAY__MAX(maxSize, innerContentSize); } } @@ -2632,20 +2636,14 @@ void Clay__CalculateFinalLayout(void) { if (clipHashMapItem) { // Floating elements that are attached to scrolling contents won't be correctly positioned if external scroll handling is enabled, fix here if (context->externalScrollHandlingEnabled) { - Clay_ScrollElementConfig *scrollConfig = Clay__FindElementConfigWithType(clipHashMapItem->layoutElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL).scrollElementConfig; - for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { - Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); - if (mapping->layoutElement == clipHashMapItem->layoutElement) { - root->pointerOffset = mapping->scrollPosition; - if (scrollConfig->horizontal) { - rootPosition.x += mapping->scrollPosition.x; - } - if (scrollConfig->vertical) { - rootPosition.y += mapping->scrollPosition.y; - } - break; - } + Clay_ClipElementConfig *clipConfig = Clay__FindElementConfigWithType(clipHashMapItem->layoutElement, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig; + if (clipConfig->horizontal) { + rootPosition.x += clipConfig->childOffset.x; } + if (clipConfig->vertical) { + rootPosition.y += clipConfig->childOffset.y; + } + break; } Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) { .boundingBox = clipHashMapItem->boundingBox, @@ -2681,8 +2679,8 @@ void Clay__CalculateFinalLayout(void) { Clay__ScrollContainerDataInternal *scrollContainerData = CLAY__NULL; // Apply scroll offsets to container - if (Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL)) { - Clay_ScrollElementConfig *scrollConfig = Clay__FindElementConfigWithType(currentElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL).scrollElementConfig; + if (Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_CLIP)) { + Clay_ClipElementConfig *clipConfig = Clay__FindElementConfigWithType(currentElement, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig; // This linear scan could theoretically be slow under very strange conditions, but I can't imagine a real UI with more than a few 10's of scroll containers for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { @@ -2690,10 +2688,10 @@ void Clay__CalculateFinalLayout(void) { if (mapping->layoutElement == currentElement) { scrollContainerData = mapping; mapping->boundingBox = currentElementBoundingBox; - if (scrollConfig->horizontal) { + if (clipConfig->horizontal) { scrollOffset.x = mapping->scrollPosition.x; } - if (scrollConfig->vertical) { + if (clipConfig->vertical) { scrollOffset.y = mapping->scrollPosition.y; } if (context->externalScrollHandlingEnabled) { @@ -2726,7 +2724,7 @@ void Clay__CalculateFinalLayout(void) { int32_t next = sortedConfigIndexes[i + 1]; Clay__ElementConfigType currentType = Clay__ElementConfigArraySlice_Get(¤tElement->elementConfigs, current)->type; Clay__ElementConfigType nextType = Clay__ElementConfigArraySlice_Get(¤tElement->elementConfigs, next)->type; - if (nextType == CLAY__ELEMENT_CONFIG_TYPE_SCROLL || currentType == CLAY__ELEMENT_CONFIG_TYPE_BORDER) { + if (nextType == CLAY__ELEMENT_CONFIG_TYPE_CLIP || currentType == CLAY__ELEMENT_CONFIG_TYPE_BORDER) { sortedConfigIndexes[i] = next; sortedConfigIndexes[i + 1] = current; } @@ -2762,12 +2760,12 @@ void Clay__CalculateFinalLayout(void) { shouldRender = false; break; } - case CLAY__ELEMENT_CONFIG_TYPE_SCROLL: { + case CLAY__ELEMENT_CONFIG_TYPE_CLIP: { renderCommand.commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_START; renderCommand.renderData = CLAY__INIT(Clay_RenderData) { - .scroll = { - .horizontal = elementConfig->config.scrollElementConfig->horizontal, - .vertical = elementConfig->config.scrollElementConfig->vertical, + .clip = { + .horizontal = elementConfig->config.clipElementConfig->horizontal, + .vertical = elementConfig->config.clipElementConfig->vertical, } }; break; @@ -2910,15 +2908,15 @@ void Clay__CalculateFinalLayout(void) { } else { // DFS is returning upwards backwards - bool closeScrollElement = false; - Clay_ScrollElementConfig *scrollConfig = Clay__FindElementConfigWithType(currentElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL).scrollElementConfig; - if (scrollConfig) { - closeScrollElement = true; + bool closeClipElement = false; + Clay_ClipElementConfig *clipConfig = Clay__FindElementConfigWithType(currentElement, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig; + if (clipConfig) { + closeClipElement = true; for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); if (mapping->layoutElement == currentElement) { - if (scrollConfig->horizontal) { scrollOffset.x = mapping->scrollPosition.x; } - if (scrollConfig->vertical) { scrollOffset.y = mapping->scrollPosition.y; } + if (clipConfig->horizontal) { scrollOffset.x = mapping->scrollPosition.x; } + if (clipConfig->vertical) { scrollOffset.y = mapping->scrollPosition.y; } if (context->externalScrollHandlingEnabled) { scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT; } @@ -2987,7 +2985,7 @@ void Clay__CalculateFinalLayout(void) { } } // This exists because the scissor needs to end _after_ borders between elements - if (closeScrollElement) { + if (closeClipElement) { Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) { .id = Clay__HashNumber(currentElement->id, rootElement->childrenOrTextContent.children.length + 11).id, .commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_END, @@ -3075,7 +3073,7 @@ Clay__DebugElementConfigTypeLabelConfig Clay__DebugGetElementConfigTypeLabel(Cla case CLAY__ELEMENT_CONFIG_TYPE_TEXT: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Text"), {105,210,231,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_SCROLL: 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} }; case CLAY__ELEMENT_CONFIG_TYPE_BORDER: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) {CLAY_STRING("Border"), {108, 91, 123, 255} }; case CLAY__ELEMENT_CONFIG_TYPE_CUSTOM: return CLAY__INIT(Clay__DebugElementConfigTypeLabelConfig) { CLAY_STRING("Custom"), {11,72,107,255} }; default: break; @@ -3382,7 +3380,7 @@ void Clay__RenderDebugView(void) { } } CLAY({ .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(1)} }, .backgroundColor = CLAY__DEBUGVIEW_COLOR_3 } ) {} - CLAY({ .id = scrollId, .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)} }, .scroll = { .horizontal = true, .vertical = true } }) { + CLAY({ .id = scrollId, .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)} }, .clip = { .horizontal = true, .vertical = true, .childOffset = Clay_GetScrollOffset() } }) { CLAY({ .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_GROW(0)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }, .backgroundColor = ((initialElementsLength + initialRootsLength) & 1) == 0 ? CLAY__DEBUGVIEW_COLOR_2 : CLAY__DEBUGVIEW_COLOR_1 }) { Clay_ElementId panelContentsId = Clay__HashString(CLAY_STRING("Clay__DebugViewPaneOuter"), 0, 0); // Element list @@ -3413,7 +3411,7 @@ void Clay__RenderDebugView(void) { CLAY({ .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(300)}, .layoutDirection = CLAY_TOP_TO_BOTTOM }, .backgroundColor = CLAY__DEBUGVIEW_COLOR_2 , - .scroll = { .vertical = true }, + .clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() }, .border = { .color = CLAY__DEBUGVIEW_COLOR_3, .width = { .betweenChildren = 1 } } }) { CLAY({ .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT + 8)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, CLAY__DEBUGVIEW_OUTER_PADDING, 0, 0 }, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} } }) { @@ -3569,15 +3567,15 @@ void Clay__RenderDebugView(void) { } break; } - case CLAY__ELEMENT_CONFIG_TYPE_SCROLL: { - Clay_ScrollElementConfig *scrollConfig = elementConfig->config.scrollElementConfig; + case CLAY__ELEMENT_CONFIG_TYPE_CLIP: { + Clay_ClipElementConfig *clipConfig = elementConfig->config.clipElementConfig; CLAY({ .layout = { .padding = attributeConfigPadding, .childGap = 8, .layoutDirection = CLAY_TOP_TO_BOTTOM } }) { // .vertical CLAY_TEXT(CLAY_STRING("Vertical"), infoTitleConfig); - CLAY_TEXT(scrollConfig->vertical ? CLAY_STRING("true") : CLAY_STRING("false") , infoTextConfig); + CLAY_TEXT(clipConfig->vertical ? CLAY_STRING("true") : CLAY_STRING("false") , infoTextConfig); // .horizontal CLAY_TEXT(CLAY_STRING("Horizontal"), infoTitleConfig); - CLAY_TEXT(scrollConfig->horizontal ? CLAY_STRING("true") : CLAY_STRING("false") , infoTextConfig); + CLAY_TEXT(clipConfig->horizontal ? CLAY_STRING("true") : CLAY_STRING("false") , infoTextConfig); } break; } @@ -3639,7 +3637,7 @@ void Clay__RenderDebugView(void) { } } } else { - CLAY({ .id = CLAY_ID("Clay__DebugViewWarningsScrollPane"), .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(300)}, .childGap = 6, .layoutDirection = CLAY_TOP_TO_BOTTOM }, .backgroundColor = CLAY__DEBUGVIEW_COLOR_2, .scroll = { .horizontal = true, .vertical = true } }) { + CLAY({ .id = CLAY_ID("Clay__DebugViewWarningsScrollPane"), .layout = { .sizing = {CLAY_SIZING_GROW(0), CLAY_SIZING_FIXED(300)}, .childGap = 6, .layoutDirection = CLAY_TOP_TO_BOTTOM }, .backgroundColor = CLAY__DEBUGVIEW_COLOR_2, .clip = { .horizontal = true, .vertical = true, .childOffset = Clay_GetScrollOffset() } }) { Clay_TextElementConfig *warningConfig = CLAY_TEXT_CONFIG({ .textColor = CLAY__DEBUGVIEW_COLOR_4, .fontSize = 16, .wrapMode = CLAY_TEXT_WRAP_NONE }); CLAY({ .id = CLAY_ID("Clay__DebugViewWarningItemHeader"), .layout = { .sizing = {.height = CLAY_SIZING_FIXED(CLAY__DEBUGVIEW_ROW_HEIGHT)}, .padding = {CLAY__DEBUGVIEW_OUTER_PADDING, CLAY__DEBUGVIEW_OUTER_PADDING, 0, 0 }, .childGap = 8, .childAlignment = {.y = CLAY_ALIGN_Y_CENTER} } }) { CLAY_TEXT(CLAY_STRING("Warnings"), warningConfig); @@ -3896,6 +3894,27 @@ void Clay_SetCurrentContext(Clay_Context* context) { Clay__currentContext = context; } +CLAY_WASM_EXPORT("Clay_GetScrollOffset") +Clay_Vector2 Clay_GetScrollOffset() { + Clay_Context* context = Clay_GetCurrentContext(); + if (context->booleanWarnings.maxElementsExceeded) { + return CLAY__INIT(Clay_Vector2){}; + } + Clay_LayoutElement *openLayoutElement = Clay__GetOpenLayoutElement(); + // If the element has no id attached at this point, we need to generate one + if (openLayoutElement->id == 0) { + Clay__GenerateIdForAnonymousElement(openLayoutElement); + } + Clay_ClipElementConfig *clipConfig = Clay__FindElementConfigWithType(openLayoutElement, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig; + for (int32_t i = 0; i < context->scrollContainerDatas.length; i++) { + Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i); + if (mapping->layoutElement == openLayoutElement) { + return mapping->scrollPosition; + } + } + return CLAY__INIT(Clay_Vector2){}; +} + CLAY_WASM_EXPORT("Clay_UpdateScrollContainers") void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDelta, float deltaTime) { Clay_Context* context = Clay_GetCurrentContext(); @@ -3960,9 +3979,9 @@ void Clay_UpdateScrollContainers(bool enableDragScrolling, Clay_Vector2 scrollDe if (highestPriorityElementIndex > -1 && highestPriorityScrollData) { Clay_LayoutElement *scrollElement = highestPriorityScrollData->layoutElement; - Clay_ScrollElementConfig *scrollConfig = Clay__FindElementConfigWithType(scrollElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL).scrollElementConfig; - bool canScrollVertically = scrollConfig->vertical && highestPriorityScrollData->contentSize.height > scrollElement->dimensions.height; - bool canScrollHorizontally = scrollConfig->horizontal && highestPriorityScrollData->contentSize.width > scrollElement->dimensions.width; + Clay_ClipElementConfig *clipConfig = Clay__FindElementConfigWithType(scrollElement, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig; + bool canScrollVertically = clipConfig->vertical && highestPriorityScrollData->contentSize.height > scrollElement->dimensions.height; + bool canScrollHorizontally = clipConfig->horizontal && highestPriorityScrollData->contentSize.width > scrollElement->dimensions.width; // Handle wheel scroll if (canScrollVertically) { highestPriorityScrollData->scrollPosition.y = highestPriorityScrollData->scrollPosition.y + scrollDelta.y * 10; @@ -4122,7 +4141,7 @@ Clay_ScrollContainerData Clay_GetScrollContainerData(Clay_ElementId id) { .scrollPosition = &scrollContainerData->scrollPosition, .scrollContainerDimensions = { scrollContainerData->boundingBox.width, scrollContainerData->boundingBox.height }, .contentDimensions = scrollContainerData->contentSize, - .config = *Clay__FindElementConfigWithType(scrollContainerData->layoutElement, CLAY__ELEMENT_CONFIG_TYPE_SCROLL).scrollElementConfig, + .config = *Clay__FindElementConfigWithType(scrollContainerData->layoutElement, CLAY__ELEMENT_CONFIG_TYPE_CLIP).clipElementConfig, .found = true }; } diff --git a/examples/raylib-sidebar-scrolling-container/main.c b/examples/raylib-sidebar-scrolling-container/main.c index 662fa7a..52797a8 100644 --- a/examples/raylib-sidebar-scrolling-container/main.c +++ b/examples/raylib-sidebar-scrolling-container/main.c @@ -65,7 +65,7 @@ Clay_RenderCommandArray CreateLayout(void) { CLAY({.id = CLAY_ID("MainContent"), .layout = { .layoutDirection = CLAY_TOP_TO_BOTTOM, .padding = {16, 16, 16, 16}, .childGap = 16, .sizing = { .width = CLAY_SIZING_GROW(0) } }, .backgroundColor = {200, 200, 255, 255}, - .scroll = { .vertical = true }, + .clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() }, }) { CLAY({ .id = CLAY_ID("FloatingContainer"), @@ -107,7 +107,7 @@ Clay_RenderCommandArray CreateLayout(void) { } CLAY({ .id = CLAY_ID("Blob4Floating2"), .floating = { .attachTo = CLAY_ATTACH_TO_ELEMENT_WITH_ID, .zIndex = 1, .parentId = Clay_GetElementId(CLAY_STRING("SidebarBlob4")).id } }) { - CLAY({ .id = CLAY_ID("ScrollContainer"), .layout = { .sizing = { .height = CLAY_SIZING_FIXED(200) }, .childGap = 2 }, .scroll = { .vertical = true } }) { + CLAY({ .id = CLAY_ID("ScrollContainer"), .layout = { .sizing = { .height = CLAY_SIZING_FIXED(200) }, .childGap = 2 }, .clip = { .vertical = true, .childOffset = Clay_GetScrollOffset() } }) { CLAY({ .id = CLAY_ID("FloatingContainer2"), .floating = { .attachTo = CLAY_ATTACH_TO_PARENT, .zIndex = 1 } }) { CLAY({ .id = CLAY_ID("FloatingContainerInner"), .layout = { .sizing = { .width = CLAY_SIZING_FIXED(300), .height = CLAY_SIZING_FIXED(300) }, .padding = {16, 16, 16, 16} }, .backgroundColor = {140,80, 200, 200} }) { CLAY_TEXT(CLAY_STRING("I'm an inline floating container."), CLAY_TEXT_CONFIG({ .fontSize = 24, .textColor = {255,255,255,255} }));