mirror of
https://github.com/nicbarker/clay.git
synced 2026-04-11 22:04:15 +00:00
Correct handling of position transitions when dimensions are also transitioning
This commit is contained in:
parent
77b54a2cec
commit
fd815433f6
2 changed files with 368 additions and 344 deletions
668
clay.h
668
clay.h
|
|
@ -577,7 +577,7 @@ typedef enum {
|
|||
} Clay_TransitionState;
|
||||
|
||||
typedef enum {
|
||||
CLAY_TRANSITION_PROPERTY_ALL = 0,
|
||||
CLAY_TRANSITION_PROPERTY_NONE = 0,
|
||||
CLAY_TRANSITION_PROPERTY_X = 1,
|
||||
CLAY_TRANSITION_PROPERTY_Y = 2,
|
||||
CLAY_TRANSITION_PROPERTY_POSITION = CLAY_TRANSITION_PROPERTY_X | CLAY_TRANSITION_PROPERTY_Y,
|
||||
|
|
@ -2163,8 +2163,8 @@ void Clay__ConfigureOpenElementPtr(const Clay_ElementDeclaration *declaration) {
|
|||
scrollOffset->scrollPosition = Clay__QueryScrollOffset(scrollOffset->elementId, context->queryScrollOffsetUserData);
|
||||
}
|
||||
}
|
||||
// Setup data to track transitions across frames
|
||||
if (declaration->transition.handler) {
|
||||
// Retrieve or create cached data to track scroll position across frames
|
||||
Clay__TransitionDataInternal *transitionData = CLAY__NULL;
|
||||
Clay_LayoutElement* parentElement = Clay__GetParentElement();
|
||||
for (int32_t i = 0; i < context->transitionDatas.length; i++) {
|
||||
|
|
@ -2250,7 +2250,7 @@ bool Clay__FloatEqual(float left, float right) {
|
|||
}
|
||||
|
||||
Clay_TransitionProperty Clay__ComputeTransitionTargetChangeProperties(Clay_TransitionProperty propertyMask, Clay_TransitionData *oldTarget, Clay_TransitionData *newTarget, Clay_Vector2 newRelativePosition, Clay_Vector2 oldRelativePosition, bool reparented) {
|
||||
int32_t activeProperties = CLAY_TRANSITION_PROPERTY_ALL;
|
||||
int32_t activeProperties = CLAY_TRANSITION_PROPERTY_NONE;
|
||||
if (propertyMask & CLAY_TRANSITION_PROPERTY_X && (!Clay__FloatEqual(newRelativePosition.x, oldRelativePosition.x) || (reparented && !Clay__FloatEqual(oldTarget->boundingBox.x, newTarget->boundingBox.x)))) {
|
||||
activeProperties |= CLAY_TRANSITION_PROPERTY_X;
|
||||
}
|
||||
|
|
@ -2283,27 +2283,53 @@ Clay_TransitionProperty Clay__ComputeTransitionTargetChangeProperties(Clay_Trans
|
|||
void Clay__ProcessTransition(Clay__TransitionDataInternal* transitionData, Clay_LayoutElement* currentElement, bool targetChanged, Clay_TransitionProperty propertyMask, float deltaTime) {
|
||||
Clay_LayoutElementHashMapItem* mapItem = Clay__GetHashMapItem(currentElement->id);
|
||||
Clay_LayoutElementHashMapItem* parentMapItem = Clay__GetHashMapItem(transitionData->parentId);
|
||||
if (mapItem->appearedThisFrame) {
|
||||
|
||||
if (transitionData->state == CLAY_TRANSITION_STATE_ENTERING) {
|
||||
if (!currentElement->config.transition.enter.setInitialState || (currentElement->config.transition.enter.trigger == CLAY_TRANSITION_ENTER_SKIP_ON_FIRST_PARENT_FRAME && parentMapItem->appearedThisFrame)) {
|
||||
transitionData->initialState = transitionData->targetState;
|
||||
transitionData->currentState = transitionData->targetState;
|
||||
transitionData->state = CLAY_TRANSITION_STATE_IDLE;
|
||||
} else {
|
||||
} else if (mapItem->appearedThisFrame) {
|
||||
Clay_TransitionProperty properties = CLAY__INIT(Clay_TransitionProperty) (currentElement->config.transition.properties & propertyMask);
|
||||
transitionData->initialState = currentElement->config.transition.enter.setInitialState(transitionData->targetState, properties);
|
||||
transitionData->currentState = transitionData->initialState;
|
||||
transitionData->state = CLAY_TRANSITION_STATE_ENTERING;
|
||||
transitionData->activeProperties = CLAY__INIT(Clay_TransitionProperty)(transitionData->activeProperties | properties);
|
||||
}
|
||||
}
|
||||
|
||||
if ((propertyMask & CLAY_TRANSITION_PROPERTY_X) && !(transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_X)) {
|
||||
transitionData->currentState.boundingBox.x = transitionData->targetState.boundingBox.x;
|
||||
}
|
||||
if ((propertyMask & CLAY_TRANSITION_PROPERTY_Y) && !(transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_Y)) {
|
||||
transitionData->currentState.boundingBox.y = transitionData->targetState.boundingBox.y;
|
||||
}
|
||||
if ((propertyMask & CLAY_TRANSITION_PROPERTY_WIDTH) && !(transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_WIDTH)) {
|
||||
transitionData->currentState.boundingBox.width = transitionData->targetState.boundingBox.width;
|
||||
}
|
||||
if ((propertyMask & CLAY_TRANSITION_PROPERTY_HEIGHT) && !(transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_HEIGHT)) {
|
||||
transitionData->currentState.boundingBox.height = transitionData->targetState.boundingBox.height;
|
||||
}
|
||||
if ((propertyMask & CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR) && !(transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR)) {
|
||||
transitionData->currentState.backgroundColor = transitionData->targetState.backgroundColor;
|
||||
}
|
||||
if ((propertyMask & CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR) && !(transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR)) {
|
||||
transitionData->currentState.overlayColor = transitionData->targetState.overlayColor;
|
||||
}
|
||||
if ((propertyMask & CLAY_TRANSITION_PROPERTY_BORDER_COLOR) && !(transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_BORDER_COLOR)) {
|
||||
transitionData->currentState.borderColor = transitionData->targetState.borderColor;
|
||||
}
|
||||
if ((propertyMask & CLAY_TRANSITION_PROPERTY_BORDER_WIDTH) && !(transitionData->activeProperties & CLAY_TRANSITION_PROPERTY_BORDER_WIDTH)) {
|
||||
transitionData->currentState.borderWidth = transitionData->targetState.borderWidth;
|
||||
}
|
||||
|
||||
if (!mapItem->appearedThisFrame && targetChanged && (transitionData->state == CLAY_TRANSITION_STATE_IDLE || transitionData->state == CLAY_TRANSITION_STATE_TRANSITIONING)) {
|
||||
transitionData->elapsedTime = 0;
|
||||
transitionData->initialState = transitionData->currentState;
|
||||
transitionData->state = CLAY_TRANSITION_STATE_TRANSITIONING;
|
||||
}
|
||||
|
||||
if (transitionData->state != CLAY_TRANSITION_STATE_IDLE) {
|
||||
if (transitionData->state == CLAY_TRANSITION_STATE_IDLE) {
|
||||
transitionData->initialState = transitionData->targetState;
|
||||
transitionData->currentState = transitionData->targetState;
|
||||
} else {
|
||||
bool transitionComplete = currentElement->config.transition.handler(CLAY__INIT(Clay_TransitionCallbackArguments) {
|
||||
transitionData->state,
|
||||
transitionData->initialState,
|
||||
|
|
@ -2321,6 +2347,7 @@ void Clay__ProcessTransition(Clay__TransitionDataInternal* transitionData, Clay_
|
|||
} else {
|
||||
transitionData->state = CLAY_TRANSITION_STATE_IDLE;
|
||||
transitionData->activeProperties = CLAY__INIT(Clay_TransitionProperty)(0);
|
||||
transitionData->initialState = transitionData->currentState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2332,7 +2359,7 @@ void Clay__UpdateLayoutTransitionsForElement(Clay_LayoutElement* currentElement,
|
|||
}
|
||||
|
||||
Clay_Context* context = Clay_GetCurrentContext();
|
||||
Clay__TransitionDataInternal *transitionData;
|
||||
Clay__TransitionDataInternal *transitionData = NULL;
|
||||
for (int32_t i = 0; i < context->transitionDatas.length; i++) {
|
||||
if (Clay__TransitionDataInternalArray_Get(&context->transitionDatas, i)->elementThisFrame == currentElement) {
|
||||
transitionData = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, i);
|
||||
|
|
@ -2344,27 +2371,32 @@ void Clay__UpdateLayoutTransitionsForElement(Clay_LayoutElement* currentElement,
|
|||
return;
|
||||
}
|
||||
|
||||
Clay_LayoutElementHashMapItem *mapItem = Clay__GetHashMapItem(transitionData->elementId);
|
||||
Clay_TransitionData oldTargetTransitionData = transitionData->targetState;
|
||||
bool targetChanged;
|
||||
if (width) {
|
||||
transitionData->targetState.boundingBox.width = currentElement->dimensions.width;
|
||||
targetChanged = (currentElement->config.transition.properties & CLAY_TRANSITION_PROPERTY_WIDTH) && !Clay__FloatEqual(oldTargetTransitionData.boundingBox.width, transitionData->targetState.boundingBox.width);
|
||||
if (targetChanged) transitionData->activeProperties = CLAY__INIT(Clay_TransitionProperty) (transitionData->activeProperties | CLAY_TRANSITION_PROPERTY_WIDTH);
|
||||
if (targetChanged && !mapItem->appearedThisFrame) transitionData->activeProperties = CLAY__INIT(Clay_TransitionProperty) (transitionData->activeProperties | CLAY_TRANSITION_PROPERTY_WIDTH);
|
||||
// Clay_String string = Clay_GetCurrentContext()->layoutElementIdStrings.internalArray[currentElement - Clay_GetCurrentContext()->layoutElements.internalArray];
|
||||
// if (targetChanged && !mapItem->appearedThisFrame && string.chars && strcmp(string.chars, "Indent") == 0) {
|
||||
// int x =5 ;
|
||||
// }
|
||||
Clay__ProcessTransition(transitionData, currentElement, targetChanged, CLAY_TRANSITION_PROPERTY_WIDTH, deltaTime);
|
||||
currentElement->dimensions.width = transitionData->currentState.boundingBox.width;
|
||||
} else {
|
||||
transitionData->targetState.boundingBox.height = currentElement->dimensions.height;
|
||||
targetChanged = (currentElement->config.transition.properties & CLAY_TRANSITION_PROPERTY_HEIGHT) && !Clay__FloatEqual(oldTargetTransitionData.boundingBox.height, transitionData->targetState.boundingBox.height);
|
||||
if (targetChanged) transitionData->activeProperties = CLAY__INIT(Clay_TransitionProperty) (transitionData->activeProperties | CLAY_TRANSITION_PROPERTY_HEIGHT);
|
||||
if (targetChanged && !mapItem->appearedThisFrame) transitionData->activeProperties = CLAY__INIT(Clay_TransitionProperty) (transitionData->activeProperties | CLAY_TRANSITION_PROPERTY_HEIGHT);
|
||||
Clay__ProcessTransition(transitionData, currentElement, targetChanged, CLAY_TRANSITION_PROPERTY_HEIGHT, deltaTime);
|
||||
currentElement->dimensions.height = transitionData->currentState.boundingBox.height;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle transitions for non-layout affecting properties, such as position, color
|
||||
Clay_Vector2 Clay__UpdateNonLayoutTransitionsForElement(Clay_LayoutElement* currentElement, Clay_Vector2 targetPosition, float deltaTime) {
|
||||
Clay_Vector2 Clay__UpdateNonLayoutTransitionsForElement(Clay_LayoutElement* currentElement, Clay_Vector2 defaultPosition, Clay_Vector2 targetPosition, float deltaTime) {
|
||||
if (!currentElement->config.transition.handler) {
|
||||
return targetPosition;
|
||||
return defaultPosition;
|
||||
}
|
||||
|
||||
Clay_Context* context = Clay_GetCurrentContext();
|
||||
|
|
@ -2377,7 +2409,7 @@ Clay_Vector2 Clay__UpdateNonLayoutTransitionsForElement(Clay_LayoutElement* curr
|
|||
}
|
||||
|
||||
if (!transitionData) {
|
||||
return targetPosition;
|
||||
return defaultPosition;
|
||||
}
|
||||
|
||||
if (transitionData->state != CLAY_TRANSITION_STATE_EXITING) {
|
||||
|
|
@ -2415,7 +2447,7 @@ Clay_Vector2 Clay__UpdateNonLayoutTransitionsForElement(Clay_LayoutElement* curr
|
|||
currentElement->config.border.color = transitionData->currentState.borderColor;
|
||||
return CLAY__INIT(Clay_Vector2) { transitionData->currentState.boundingBox.x, transitionData->currentState.boundingBox.y };
|
||||
} else {
|
||||
return CLAY__INIT(Clay_Vector2) { targetPosition.x, targetPosition.y };
|
||||
return defaultPosition;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2716,13 +2748,6 @@ bool Clay__ElementIsOffscreen(Clay_BoundingBox *boundingBox) {
|
|||
(boundingBox->y + boundingBox->height < 0);
|
||||
}
|
||||
|
||||
void Clay__UpdateElementWithTransitionData(Clay_BoundingBox *boundingBox, Clay_LayoutElement* layoutElement, Clay_TransitionData* data) {
|
||||
*boundingBox = data->boundingBox;
|
||||
layoutElement->config.backgroundColor = data->backgroundColor;
|
||||
layoutElement->config.overlayColor = data->overlayColor;
|
||||
layoutElement->config.border = CLAY__INIT(Clay_BorderElementConfig) { data->borderColor, data->borderWidth };
|
||||
}
|
||||
|
||||
void Clay__CalculateFinalLayout(float deltaTime) {
|
||||
Clay_Context* context = Clay_GetCurrentContext();
|
||||
|
||||
|
|
@ -2961,229 +2986,8 @@ void Clay__CalculateFinalLayout(float deltaTime) {
|
|||
Clay_LayoutConfig *layoutConfig = ¤tElement->config.layout;
|
||||
Clay_Vector2 scrollOffset = CLAY__DEFAULT_STRUCT;
|
||||
|
||||
// This will only be run a single time for each element in downwards DFS order
|
||||
if (!context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) {
|
||||
context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true;
|
||||
|
||||
Clay_BoundingBox currentElementBoundingBox = { currentElementTreeNode->position.x, currentElementTreeNode->position.y, currentElement->dimensions.width, currentElement->dimensions.height };
|
||||
if (currentElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE) {
|
||||
Clay_FloatingElementConfig *floatingElementConfig = ¤tElement->config.floating;
|
||||
Clay_Dimensions expand = floatingElementConfig->expand;
|
||||
currentElementBoundingBox.x -= expand.width;
|
||||
currentElementBoundingBox.width += expand.width * 2;
|
||||
currentElementBoundingBox.y -= expand.height;
|
||||
currentElementBoundingBox.height += expand.height * 2;
|
||||
}
|
||||
|
||||
Clay__ScrollContainerDataInternal *scrollContainerData = CLAY__NULL;
|
||||
// Apply scroll offsets to container
|
||||
if (currentElement->config.clip.horizontal || currentElement->config.clip.vertical) {
|
||||
// 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++) {
|
||||
Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i);
|
||||
if (mapping->layoutElement == currentElement) {
|
||||
scrollContainerData = mapping;
|
||||
mapping->boundingBox = currentElementBoundingBox;
|
||||
scrollOffset = currentElement->config.clip.childOffset;
|
||||
if (context->externalScrollHandlingEnabled) {
|
||||
scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Clay_LayoutElementHashMapItem *hashMapItem = Clay__GetHashMapItem(currentElement->id);
|
||||
if (hashMapItem) {
|
||||
hashMapItem->boundingBox = currentElementBoundingBox;
|
||||
}
|
||||
|
||||
bool offscreen = Clay__ElementIsOffscreen(¤tElementBoundingBox);
|
||||
|
||||
if (!offscreen) {
|
||||
if (currentElement->isTextElement) {
|
||||
Clay_TextElementConfig *textElementConfig = ¤tElement->textConfig;
|
||||
float naturalLineHeight = currentElement->textElementData.preferredDimensions.height;
|
||||
float finalLineHeight = textElementConfig->lineHeight > 0 ? (float)textElementConfig->lineHeight : naturalLineHeight;
|
||||
float lineHeightOffset = (finalLineHeight - naturalLineHeight) / 2;
|
||||
float yPosition = lineHeightOffset;
|
||||
for (int32_t lineIndex = 0; lineIndex < currentElement->textElementData.wrappedLines.length; ++lineIndex) {
|
||||
Clay__WrappedTextLine *wrappedLine = Clay__WrappedTextLineArraySlice_Get(¤tElement->textElementData.wrappedLines, lineIndex);
|
||||
if (wrappedLine->line.length == 0) {
|
||||
yPosition += finalLineHeight;
|
||||
continue;
|
||||
}
|
||||
float offset = (currentElementBoundingBox.width - wrappedLine->dimensions.width);
|
||||
if (textElementConfig->textAlignment == CLAY_TEXT_ALIGN_LEFT) {
|
||||
offset = 0;
|
||||
}
|
||||
if (textElementConfig->textAlignment == CLAY_TEXT_ALIGN_CENTER) {
|
||||
offset /= 2;
|
||||
}
|
||||
Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
|
||||
.boundingBox = { currentElementBoundingBox.x + offset, currentElementBoundingBox.y + yPosition, wrappedLine->dimensions.width, wrappedLine->dimensions.height },
|
||||
.renderData = { .text = {
|
||||
.stringContents = CLAY__INIT(Clay_StringSlice) { .length = wrappedLine->line.length, .chars = wrappedLine->line.chars, .baseChars = currentElement->textElementData.text.chars },
|
||||
.textColor = textElementConfig->textColor,
|
||||
.fontId = textElementConfig->fontId,
|
||||
.fontSize = textElementConfig->fontSize,
|
||||
.letterSpacing = textElementConfig->letterSpacing,
|
||||
.lineHeight = textElementConfig->lineHeight,
|
||||
}},
|
||||
.userData = textElementConfig->userData,
|
||||
.id = Clay__HashNumber(lineIndex, currentElement->id).id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_TEXT,
|
||||
});
|
||||
yPosition += finalLineHeight;
|
||||
|
||||
if (!context->disableCulling && (currentElementBoundingBox.y + yPosition > context->layoutDimensions.height)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (currentElement->config.overlayColor.a > 0) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.renderData = {
|
||||
.colorOverlay = { .color = currentElement->config.overlayColor }
|
||||
},
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_COLOR_OVERLAY_START,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
if (currentElement->config.image.imageData) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.boundingBox = currentElementBoundingBox,
|
||||
.renderData = {
|
||||
.image = {
|
||||
.backgroundColor = currentElement->config.backgroundColor,
|
||||
.cornerRadius = currentElement->config.cornerRadius,
|
||||
.imageData = currentElement->config.image.imageData,
|
||||
}
|
||||
},
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_IMAGE,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
if (currentElement->config.custom.customData) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.boundingBox = currentElementBoundingBox,
|
||||
.renderData = {
|
||||
.custom = {
|
||||
.backgroundColor = currentElement->config.backgroundColor,
|
||||
.cornerRadius = currentElement->config.cornerRadius,
|
||||
.customData = currentElement->config.custom.customData,
|
||||
}
|
||||
},
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_CUSTOM,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
if (currentElement->config.clip.horizontal || currentElement->config.clip.vertical) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.boundingBox = currentElementBoundingBox,
|
||||
.renderData = {
|
||||
.clip = {
|
||||
.horizontal = currentElement->config.clip.horizontal,
|
||||
.vertical = currentElement->config.clip.vertical,
|
||||
}
|
||||
},
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_START,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
if (currentElement->config.backgroundColor.a > 0) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.boundingBox = currentElementBoundingBox,
|
||||
.renderData = { .rectangle = {
|
||||
.backgroundColor = currentElement->config.backgroundColor,
|
||||
.cornerRadius = currentElement->config.cornerRadius,
|
||||
} },
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Setup initial on-axis alignment
|
||||
if (!currentElementTreeNode->layoutElement->isTextElement) {
|
||||
Clay_Dimensions contentSize = {0,0};
|
||||
if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
|
||||
for (int32_t i = 0; i < currentElement->children.length; ++i) {
|
||||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
|
||||
if (childElement->config.floating.attachTo == CLAY_ATTACH_TO_INLINE) continue;
|
||||
Clay_Dimensions childDimensions = childElement->dimensions;
|
||||
if (childElement->config.transition.handler) {
|
||||
for (int j = 0; j < context->transitionDatas.length; ++j) {
|
||||
Clay__TransitionDataInternal* data = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, j);
|
||||
if (data->elementId == childElement->id && data->state != CLAY_TRANSITION_STATE_IDLE) {
|
||||
childDimensions = CLAY__INIT(Clay_Dimensions) { data->targetState.boundingBox.width, data->targetState.boundingBox.height };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
contentSize.width += childDimensions.width;
|
||||
contentSize.height = CLAY__MAX(contentSize.height, childDimensions.height);
|
||||
}
|
||||
contentSize.width += (float)(CLAY__MAX(currentElement->children.length - 1, 0) * layoutConfig->childGap);
|
||||
float extraSpace = currentElement->dimensions.width - (float)(layoutConfig->padding.left + layoutConfig->padding.right) - contentSize.width;
|
||||
switch (layoutConfig->childAlignment.x) {
|
||||
case CLAY_ALIGN_X_LEFT: extraSpace = 0; break;
|
||||
case CLAY_ALIGN_X_CENTER: extraSpace /= 2; break;
|
||||
default: break;
|
||||
}
|
||||
currentElementTreeNode->nextChildOffset.x += extraSpace;
|
||||
extraSpace = CLAY__MAX(0, extraSpace);
|
||||
} else {
|
||||
for (int32_t i = 0; i < currentElement->children.length; ++i) {
|
||||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
|
||||
if (childElement->config.floating.attachTo == CLAY_ATTACH_TO_INLINE) continue;
|
||||
Clay_Dimensions childDimensions = childElement->dimensions;
|
||||
if (childElement->config.transition.handler) {
|
||||
for (int j = 0; j < context->transitionDatas.length; ++j) {
|
||||
Clay__TransitionDataInternal* data = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, j);
|
||||
if (data->elementId == childElement->id && data->state != CLAY_TRANSITION_STATE_IDLE) {
|
||||
childDimensions = CLAY__INIT(Clay_Dimensions) { data->targetState.boundingBox.width, data->targetState.boundingBox.height };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
contentSize.width = CLAY__MAX(contentSize.width, childDimensions.width);
|
||||
contentSize.height += childDimensions.height;
|
||||
}
|
||||
contentSize.height += (float)(CLAY__MAX(currentElement->children.length - 1, 0) * layoutConfig->childGap);
|
||||
float extraSpace = currentElement->dimensions.height - (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) - contentSize.height;
|
||||
switch (layoutConfig->childAlignment.y) {
|
||||
case CLAY_ALIGN_Y_TOP: extraSpace = 0; break;
|
||||
case CLAY_ALIGN_Y_CENTER: extraSpace /= 2; break;
|
||||
default: break;
|
||||
}
|
||||
extraSpace = CLAY__MAX(0, extraSpace);
|
||||
currentElementTreeNode->nextChildOffset.y += extraSpace;
|
||||
}
|
||||
|
||||
if (scrollContainerData) {
|
||||
scrollContainerData->contentSize = CLAY__INIT(Clay_Dimensions) { contentSize.width + (float)(layoutConfig->padding.left + layoutConfig->padding.right), contentSize.height + (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) };
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// DFS is returning back upwards
|
||||
if (context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) {
|
||||
if (currentElement->isTextElement) {
|
||||
dfsBuffer.length--;
|
||||
continue;
|
||||
|
|
@ -3212,9 +3016,9 @@ void Clay__CalculateFinalLayout(float deltaTime) {
|
|||
Clay_RenderCommand renderCommand = {
|
||||
.boundingBox = currentElementBoundingBox,
|
||||
.renderData = { .border = {
|
||||
.color = borderConfig->color,
|
||||
.cornerRadius = currentElement->config.cornerRadius,
|
||||
.width = borderConfig->width
|
||||
.color = borderConfig->color,
|
||||
.cornerRadius = currentElement->config.cornerRadius,
|
||||
.width = borderConfig->width
|
||||
}},
|
||||
.userData = currentElement->config.userData,
|
||||
.id = Clay__HashNumber(currentElement->id, currentElement->children.length).id,
|
||||
|
|
@ -3230,13 +3034,13 @@ void Clay__CalculateFinalLayout(float deltaTime) {
|
|||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
|
||||
if (i > 0) {
|
||||
Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
|
||||
.boundingBox = { currentElementBoundingBox.x + borderOffset.x + scrollOffset.x - halfWidth, currentElementBoundingBox.y + scrollOffset.y, (float)borderConfig->width.betweenChildren, currentElement->dimensions.height },
|
||||
.renderData = { .rectangle = {
|
||||
.backgroundColor = borderConfig->color,
|
||||
} },
|
||||
.userData = currentElement->config.userData,
|
||||
.id = Clay__HashNumber(currentElement->id, currentElement->children.length + 1 + i).id,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
|
||||
.boundingBox = { currentElementBoundingBox.x + borderOffset.x + scrollOffset.x - halfWidth, currentElementBoundingBox.y + scrollOffset.y, (float)borderConfig->width.betweenChildren, currentElement->dimensions.height },
|
||||
.renderData = { .rectangle = {
|
||||
.backgroundColor = borderConfig->color,
|
||||
} },
|
||||
.userData = currentElement->config.userData,
|
||||
.id = Clay__HashNumber(currentElement->id, currentElement->children.length + 1 + i).id,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
|
||||
});
|
||||
}
|
||||
borderOffset.x += (childElement->dimensions.width + (float)layoutConfig->childGap);
|
||||
|
|
@ -3246,13 +3050,13 @@ void Clay__CalculateFinalLayout(float deltaTime) {
|
|||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
|
||||
if (i > 0) {
|
||||
Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
|
||||
.boundingBox = { currentElementBoundingBox.x + scrollOffset.x, currentElementBoundingBox.y + borderOffset.y + scrollOffset.y - halfWidth, currentElement->dimensions.width, (float)borderConfig->width.betweenChildren },
|
||||
.renderData = { .rectangle = {
|
||||
.backgroundColor = borderConfig->color,
|
||||
} },
|
||||
.userData = currentElement->config.userData,
|
||||
.id = Clay__HashNumber(currentElement->id, currentElement->children.length + 1 + i).id,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
|
||||
.boundingBox = { currentElementBoundingBox.x + scrollOffset.x, currentElementBoundingBox.y + borderOffset.y + scrollOffset.y - halfWidth, currentElement->dimensions.width, (float)borderConfig->width.betweenChildren },
|
||||
.renderData = { .rectangle = {
|
||||
.backgroundColor = borderConfig->color,
|
||||
} },
|
||||
.userData = currentElement->config.userData,
|
||||
.id = Clay__HashNumber(currentElement->id, currentElement->children.length + 1 + i).id,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
|
||||
});
|
||||
}
|
||||
borderOffset.y += (childElement->dimensions.height + (float)layoutConfig->childGap);
|
||||
|
|
@ -3262,18 +3066,18 @@ void Clay__CalculateFinalLayout(float deltaTime) {
|
|||
}
|
||||
if (currentElement->config.overlayColor.a > 0) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_COLOR_OVERLAY_END,
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_COLOR_OVERLAY_END,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
// This exists because the scissor needs to end _after_ borders between elements
|
||||
if (closeClipElement) {
|
||||
Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
|
||||
.id = Clay__HashNumber(currentElement->id, rootElement->children.length + 11).id,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_END,
|
||||
.id = Clay__HashNumber(currentElement->id, rootElement->children.length + 11).id,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_END,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -3282,64 +3086,308 @@ void Clay__CalculateFinalLayout(float deltaTime) {
|
|||
continue;
|
||||
}
|
||||
|
||||
// Add children to the DFS buffer
|
||||
if (!currentElement->isTextElement) {
|
||||
dfsBuffer.length += currentElement->children.length;
|
||||
// This will only be run a single time for each element in downwards DFS order
|
||||
context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true;
|
||||
Clay_BoundingBox currentElementBoundingBox = { currentElementTreeNode->position.x, currentElementTreeNode->position.y, currentElement->dimensions.width, currentElement->dimensions.height };
|
||||
if (currentElement->config.floating.attachTo != CLAY_ATTACH_TO_NONE) {
|
||||
Clay_FloatingElementConfig *floatingElementConfig = ¤tElement->config.floating;
|
||||
Clay_Dimensions expand = floatingElementConfig->expand;
|
||||
currentElementBoundingBox.x -= expand.width;
|
||||
currentElementBoundingBox.width += expand.width * 2;
|
||||
currentElementBoundingBox.y -= expand.height;
|
||||
currentElementBoundingBox.height += expand.height * 2;
|
||||
}
|
||||
|
||||
Clay__ScrollContainerDataInternal *scrollContainerData = CLAY__NULL;
|
||||
// Apply scroll offsets to container
|
||||
if (currentElement->config.clip.horizontal || currentElement->config.clip.vertical) {
|
||||
// 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++) {
|
||||
Clay__ScrollContainerDataInternal *mapping = Clay__ScrollContainerDataInternalArray_Get(&context->scrollContainerDatas, i);
|
||||
if (mapping->layoutElement == currentElement) {
|
||||
scrollContainerData = mapping;
|
||||
mapping->boundingBox = currentElementBoundingBox;
|
||||
scrollOffset = currentElement->config.clip.childOffset;
|
||||
if (context->externalScrollHandlingEnabled) {
|
||||
scrollOffset = CLAY__INIT(Clay_Vector2) CLAY__DEFAULT_STRUCT;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool offscreen = Clay__ElementIsOffscreen(¤tElementBoundingBox);
|
||||
|
||||
// Generate render commands for current element
|
||||
if (!offscreen) {
|
||||
if (currentElement->isTextElement) {
|
||||
Clay_TextElementConfig *textElementConfig = ¤tElement->textConfig;
|
||||
float naturalLineHeight = currentElement->textElementData.preferredDimensions.height;
|
||||
float finalLineHeight = textElementConfig->lineHeight > 0 ? (float)textElementConfig->lineHeight : naturalLineHeight;
|
||||
float lineHeightOffset = (finalLineHeight - naturalLineHeight) / 2;
|
||||
float yPosition = lineHeightOffset;
|
||||
for (int32_t lineIndex = 0; lineIndex < currentElement->textElementData.wrappedLines.length; ++lineIndex) {
|
||||
Clay__WrappedTextLine *wrappedLine = Clay__WrappedTextLineArraySlice_Get(¤tElement->textElementData.wrappedLines, lineIndex);
|
||||
if (wrappedLine->line.length == 0) {
|
||||
yPosition += finalLineHeight;
|
||||
continue;
|
||||
}
|
||||
float offset = (currentElementBoundingBox.width - wrappedLine->dimensions.width);
|
||||
if (textElementConfig->textAlignment == CLAY_TEXT_ALIGN_LEFT) {
|
||||
offset = 0;
|
||||
}
|
||||
if (textElementConfig->textAlignment == CLAY_TEXT_ALIGN_CENTER) {
|
||||
offset /= 2;
|
||||
}
|
||||
Clay__AddRenderCommand(CLAY__INIT(Clay_RenderCommand) {
|
||||
.boundingBox = { currentElementBoundingBox.x + offset, currentElementBoundingBox.y + yPosition, wrappedLine->dimensions.width, wrappedLine->dimensions.height },
|
||||
.renderData = { .text = {
|
||||
.stringContents = CLAY__INIT(Clay_StringSlice) { .length = wrappedLine->line.length, .chars = wrappedLine->line.chars, .baseChars = currentElement->textElementData.text.chars },
|
||||
.textColor = textElementConfig->textColor,
|
||||
.fontId = textElementConfig->fontId,
|
||||
.fontSize = textElementConfig->fontSize,
|
||||
.letterSpacing = textElementConfig->letterSpacing,
|
||||
.lineHeight = textElementConfig->lineHeight,
|
||||
}},
|
||||
.userData = textElementConfig->userData,
|
||||
.id = Clay__HashNumber(lineIndex, currentElement->id).id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_TEXT,
|
||||
});
|
||||
yPosition += finalLineHeight;
|
||||
|
||||
if (!context->disableCulling && (currentElementBoundingBox.y + yPosition > context->layoutDimensions.height)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (currentElement->config.overlayColor.a > 0) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.renderData = {
|
||||
.colorOverlay = { .color = currentElement->config.overlayColor }
|
||||
},
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_COLOR_OVERLAY_START,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
if (currentElement->config.image.imageData) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.boundingBox = currentElementBoundingBox,
|
||||
.renderData = {
|
||||
.image = {
|
||||
.backgroundColor = currentElement->config.backgroundColor,
|
||||
.cornerRadius = currentElement->config.cornerRadius,
|
||||
.imageData = currentElement->config.image.imageData,
|
||||
}
|
||||
},
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_IMAGE,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
if (currentElement->config.custom.customData) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.boundingBox = currentElementBoundingBox,
|
||||
.renderData = {
|
||||
.custom = {
|
||||
.backgroundColor = currentElement->config.backgroundColor,
|
||||
.cornerRadius = currentElement->config.cornerRadius,
|
||||
.customData = currentElement->config.custom.customData,
|
||||
}
|
||||
},
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_CUSTOM,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
if (currentElement->config.clip.horizontal || currentElement->config.clip.vertical) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.boundingBox = currentElementBoundingBox,
|
||||
.renderData = {
|
||||
.clip = {
|
||||
.horizontal = currentElement->config.clip.horizontal,
|
||||
.vertical = currentElement->config.clip.vertical,
|
||||
}
|
||||
},
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_SCISSOR_START,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
if (currentElement->config.backgroundColor.a > 0) {
|
||||
Clay_RenderCommand renderCommand = {
|
||||
.boundingBox = currentElementBoundingBox,
|
||||
.renderData = { .rectangle = {
|
||||
.backgroundColor = currentElement->config.backgroundColor,
|
||||
.cornerRadius = currentElement->config.cornerRadius,
|
||||
} },
|
||||
.userData = currentElement->config.userData,
|
||||
.id = currentElement->id,
|
||||
.zIndex = root->zIndex,
|
||||
.commandType = CLAY_RENDER_COMMAND_TYPE_RECTANGLE,
|
||||
};
|
||||
Clay__AddRenderCommand(renderCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Clay_LayoutElementHashMapItem *hashMapItem = Clay__GetHashMapItem(currentElement->id);
|
||||
if (hashMapItem) {
|
||||
hashMapItem->boundingBox = currentElementBoundingBox;
|
||||
}
|
||||
|
||||
if (currentElement->isTextElement) continue;
|
||||
|
||||
// Setup positions for child elements and add to DFS buffer ----------
|
||||
|
||||
// On-axis alignment
|
||||
Clay_Dimensions contentSizeCurrent = {};
|
||||
Clay_Dimensions contentSizeTarget = {};
|
||||
Clay_Vector2 nextChildOffsetTarget = {};
|
||||
if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
|
||||
for (int32_t i = 0; i < currentElement->children.length; ++i) {
|
||||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
|
||||
Clay_Dimensions childDimensions = childElement->dimensions;
|
||||
if (childElement->config.floating.attachTo == CLAY_ATTACH_TO_INLINE) continue;
|
||||
Clay_Dimensions childDimensionsTarget = childElement->dimensions;
|
||||
if (childElement->config.transition.handler) {
|
||||
for (int j = 0; j < context->transitionDatas.length; ++j) {
|
||||
Clay__TransitionDataInternal* data = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, j);
|
||||
if (data->elementId == childElement->id && data->state != CLAY_TRANSITION_STATE_IDLE) {
|
||||
childDimensions = CLAY__INIT(Clay_Dimensions) { data->targetState.boundingBox.width, data->targetState.boundingBox.height };
|
||||
childDimensionsTarget = CLAY__INIT(Clay_Dimensions) { data->targetState.boundingBox.width, data->targetState.boundingBox.height };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Alignment along non layout axis
|
||||
if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
|
||||
currentElementTreeNode->nextChildOffset.y = currentElement->config.layout.padding.top;
|
||||
float whiteSpaceAroundChild = currentElement->dimensions.height - (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) - childDimensions.height;
|
||||
switch (layoutConfig->childAlignment.y) {
|
||||
case CLAY_ALIGN_Y_TOP: break;
|
||||
case CLAY_ALIGN_Y_CENTER: currentElementTreeNode->nextChildOffset.y += whiteSpaceAroundChild / 2; break;
|
||||
case CLAY_ALIGN_Y_BOTTOM: currentElementTreeNode->nextChildOffset.y += whiteSpaceAroundChild; break;
|
||||
}
|
||||
} else {
|
||||
currentElementTreeNode->nextChildOffset.x = currentElement->config.layout.padding.left;
|
||||
float whiteSpaceAroundChild = currentElement->dimensions.width - (float)(layoutConfig->padding.left + layoutConfig->padding.right) - childDimensions.width;
|
||||
switch (layoutConfig->childAlignment.x) {
|
||||
case CLAY_ALIGN_X_LEFT: break;
|
||||
case CLAY_ALIGN_X_CENTER: currentElementTreeNode->nextChildOffset.x += whiteSpaceAroundChild / 2; break;
|
||||
case CLAY_ALIGN_X_RIGHT: currentElementTreeNode->nextChildOffset.x += whiteSpaceAroundChild; break;
|
||||
contentSizeCurrent.width += childElement->dimensions.width;
|
||||
contentSizeCurrent.height = CLAY__MAX(contentSizeCurrent.height, childElement->dimensions.height);
|
||||
contentSizeTarget.width += childDimensionsTarget.width;
|
||||
contentSizeTarget.height = CLAY__MAX(contentSizeCurrent.height, childDimensionsTarget.height);
|
||||
}
|
||||
contentSizeCurrent.width += (float)(CLAY__MAX(currentElement->children.length - 1, 0) * layoutConfig->childGap);
|
||||
contentSizeTarget.width += (float)(CLAY__MAX(currentElement->children.length - 1, 0) * layoutConfig->childGap);
|
||||
float extraSpace = currentElement->dimensions.width - (float)(layoutConfig->padding.left + layoutConfig->padding.right) - contentSizeCurrent.width;
|
||||
float extraSpaceTarget = currentElement->dimensions.width - (float)(layoutConfig->padding.left + layoutConfig->padding.right) - contentSizeTarget.width;
|
||||
switch (layoutConfig->childAlignment.x) {
|
||||
case CLAY_ALIGN_X_LEFT: extraSpace = 0; extraSpaceTarget = 0; break;
|
||||
case CLAY_ALIGN_X_CENTER: extraSpace /= 2; extraSpaceTarget /= 2; break;
|
||||
default: break;
|
||||
}
|
||||
extraSpace = CLAY__MAX(0, extraSpace);
|
||||
nextChildOffsetTarget.x = currentElementTreeNode->nextChildOffset.x + extraSpaceTarget;
|
||||
currentElementTreeNode->nextChildOffset.x += extraSpace;
|
||||
} else {
|
||||
for (int32_t i = 0; i < currentElement->children.length; ++i) {
|
||||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
|
||||
if (childElement->config.floating.attachTo == CLAY_ATTACH_TO_INLINE) continue;
|
||||
Clay_Dimensions childDimensionsTarget = childElement->dimensions;
|
||||
if (childElement->config.transition.handler) {
|
||||
for (int j = 0; j < context->transitionDatas.length; ++j) {
|
||||
Clay__TransitionDataInternal* data = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, j);
|
||||
if (data->elementId == childElement->id && data->state != CLAY_TRANSITION_STATE_IDLE) {
|
||||
childDimensionsTarget = CLAY__INIT(Clay_Dimensions) { data->targetState.boundingBox.width, data->targetState.boundingBox.height };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
contentSizeCurrent.width = CLAY__MAX(contentSizeCurrent.width, childElement->dimensions.width);
|
||||
contentSizeCurrent.height += childElement->dimensions.height;
|
||||
contentSizeTarget.width = CLAY__MAX(contentSizeTarget.width, childDimensionsTarget.width);
|
||||
contentSizeTarget.height += childDimensionsTarget.height;
|
||||
}
|
||||
contentSizeCurrent.height += (float)(CLAY__MAX(currentElement->children.length - 1, 0) * layoutConfig->childGap);
|
||||
contentSizeTarget.height += (float)(CLAY__MAX(currentElement->children.length - 1, 0) * layoutConfig->childGap);
|
||||
float extraSpace = currentElement->dimensions.height - (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) - contentSizeCurrent.height;
|
||||
float extraSpaceTarget = currentElement->dimensions.height - (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) - contentSizeTarget.height;
|
||||
switch (layoutConfig->childAlignment.y) {
|
||||
case CLAY_ALIGN_Y_TOP: extraSpace = 0; extraSpaceTarget = 0; break;
|
||||
case CLAY_ALIGN_Y_CENTER: extraSpace /= 2; extraSpaceTarget /= 2; break;
|
||||
default: break;
|
||||
}
|
||||
extraSpace = CLAY__MAX(0, extraSpace);
|
||||
nextChildOffsetTarget.y = currentElementTreeNode->nextChildOffset.y + extraSpaceTarget;
|
||||
currentElementTreeNode->nextChildOffset.y += extraSpace;
|
||||
}
|
||||
|
||||
Clay_Vector2 childPosition = {
|
||||
currentElementTreeNode->position.x + currentElementTreeNode->nextChildOffset.x + scrollOffset.x,
|
||||
currentElementTreeNode->position.y + currentElementTreeNode->nextChildOffset.y + scrollOffset.y,
|
||||
};
|
||||
if (scrollContainerData) {
|
||||
scrollContainerData->contentSize = CLAY__INIT(Clay_Dimensions) {contentSizeCurrent.width + (float)(layoutConfig->padding.left + layoutConfig->padding.right), contentSizeCurrent.height + (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) };
|
||||
}
|
||||
|
||||
childPosition = Clay__UpdateNonLayoutTransitionsForElement(childElement, childPosition, deltaTime);
|
||||
// DFS buffer elements need to be added in reverse because stack traversal happens backwards
|
||||
uint32_t newNodeIndex = dfsBuffer.length - 1 - i;
|
||||
dfsBuffer.internalArray[newNodeIndex] = CLAY__INIT(Clay__LayoutElementTreeNode) {
|
||||
.layoutElement = childElement,
|
||||
.position = { childPosition.x, childPosition.y },
|
||||
.nextChildOffset = { .x = (float)childElement->config.layout.padding.left, .y = (float)childElement->config.layout.padding.top },
|
||||
};
|
||||
context->treeNodeVisited.internalArray[newNodeIndex] = false;
|
||||
|
||||
// Update parent offsets
|
||||
if (childElement->config.floating.attachTo != CLAY_ATTACH_TO_INLINE) {
|
||||
if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
|
||||
currentElementTreeNode->nextChildOffset.x += childDimensions.width + (float)layoutConfig->childGap;
|
||||
} else {
|
||||
currentElementTreeNode->nextChildOffset.y += childDimensions.height + (float)layoutConfig->childGap;
|
||||
// Add children to the DFS buffer
|
||||
dfsBuffer.length += currentElement->children.length;
|
||||
for (int32_t i = 0; i < currentElement->children.length; ++i) {
|
||||
Clay_LayoutElement *childElement = Clay_LayoutElementArray_Get(&context->layoutElements, currentElement->children.elements[i]);
|
||||
Clay_Dimensions childDimensionsTarget = childElement->dimensions;
|
||||
if (childElement->config.transition.handler) {
|
||||
for (int j = 0; j < context->transitionDatas.length; ++j) {
|
||||
Clay__TransitionDataInternal* data = Clay__TransitionDataInternalArray_Get(&context->transitionDatas, j);
|
||||
if (data->elementId == childElement->id && data->state != CLAY_TRANSITION_STATE_IDLE) {
|
||||
childDimensionsTarget = CLAY__INIT(Clay_Dimensions) { data->targetState.boundingBox.width, data->targetState.boundingBox.height };
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Alignment along non layout axis
|
||||
if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
|
||||
currentElementTreeNode->nextChildOffset.y = currentElement->config.layout.padding.top;
|
||||
nextChildOffsetTarget.y = currentElement->config.layout.padding.top;
|
||||
float whiteSpaceAroundChild = currentElement->dimensions.height - (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) - childElement->dimensions.height;
|
||||
float whiteSpaceAroundChildTarget = currentElement->dimensions.height - (float)(layoutConfig->padding.top + layoutConfig->padding.bottom) - childDimensionsTarget.height;
|
||||
switch (layoutConfig->childAlignment.y) {
|
||||
case CLAY_ALIGN_Y_TOP: break;
|
||||
case CLAY_ALIGN_Y_CENTER: currentElementTreeNode->nextChildOffset.y += whiteSpaceAroundChild / 2; nextChildOffsetTarget.y += whiteSpaceAroundChildTarget / 2; break;
|
||||
case CLAY_ALIGN_Y_BOTTOM: currentElementTreeNode->nextChildOffset.y += whiteSpaceAroundChild; nextChildOffsetTarget.y += whiteSpaceAroundChildTarget; break;
|
||||
}
|
||||
} else {
|
||||
currentElementTreeNode->nextChildOffset.x = currentElement->config.layout.padding.left;
|
||||
nextChildOffsetTarget.x = currentElement->config.layout.padding.left;
|
||||
float whiteSpaceAroundChild = currentElement->dimensions.width - (float)(layoutConfig->padding.left + layoutConfig->padding.right) - childElement->dimensions.width;
|
||||
float whiteSpaceAroundChildTarget = currentElement->dimensions.width - (float)(layoutConfig->padding.left + layoutConfig->padding.right) - childDimensionsTarget.width;
|
||||
switch (layoutConfig->childAlignment.x) {
|
||||
case CLAY_ALIGN_X_LEFT: break;
|
||||
case CLAY_ALIGN_X_CENTER: currentElementTreeNode->nextChildOffset.x += whiteSpaceAroundChild / 2; nextChildOffsetTarget.x += whiteSpaceAroundChildTarget / 2; break;
|
||||
case CLAY_ALIGN_X_RIGHT: currentElementTreeNode->nextChildOffset.x += whiteSpaceAroundChild; nextChildOffsetTarget.x += whiteSpaceAroundChildTarget; break;
|
||||
}
|
||||
}
|
||||
|
||||
Clay_Vector2 childPosition = {
|
||||
currentElementTreeNode->position.x + currentElementTreeNode->nextChildOffset.x + scrollOffset.x,
|
||||
currentElementTreeNode->position.y + currentElementTreeNode->nextChildOffset.y + scrollOffset.y,
|
||||
};
|
||||
|
||||
Clay_Vector2 childPositionTarget = {
|
||||
currentElementTreeNode->position.x + nextChildOffsetTarget.x + scrollOffset.x,
|
||||
currentElementTreeNode->position.y + nextChildOffsetTarget.y + scrollOffset.y,
|
||||
};
|
||||
|
||||
childPosition = Clay__UpdateNonLayoutTransitionsForElement(childElement, childPosition, childPositionTarget, deltaTime);
|
||||
// DFS buffer elements need to be added in reverse because stack traversal happens backwards
|
||||
uint32_t newNodeIndex = dfsBuffer.length - 1 - i;
|
||||
dfsBuffer.internalArray[newNodeIndex] = CLAY__INIT(Clay__LayoutElementTreeNode) {
|
||||
.layoutElement = childElement,
|
||||
.position = { childPosition.x, childPosition.y },
|
||||
.nextChildOffset = { .x = (float)childElement->config.layout.padding.left, .y = (float)childElement->config.layout.padding.top },
|
||||
};
|
||||
context->treeNodeVisited.internalArray[newNodeIndex] = false;
|
||||
|
||||
// Update parent offsets
|
||||
if (childElement->config.floating.attachTo != CLAY_ATTACH_TO_INLINE) {
|
||||
if (layoutConfig->layoutDirection == CLAY_LEFT_TO_RIGHT) {
|
||||
currentElementTreeNode->nextChildOffset.x += childElement->dimensions.width + (float)layoutConfig->childGap;
|
||||
nextChildOffsetTarget.x += childDimensionsTarget.width + (float)layoutConfig->childGap;
|
||||
} else {
|
||||
currentElementTreeNode->nextChildOffset.y += childElement->dimensions.height + (float)layoutConfig->childGap;
|
||||
nextChildOffsetTarget.y += childDimensionsTarget.height + (float)layoutConfig->childGap;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -74,58 +74,43 @@ bool Clay_EaseOut(Clay_TransitionCallbackArguments arguments) {
|
|||
float ratio = arguments.elapsedTime / arguments.duration;
|
||||
if (ratio < 1) {
|
||||
float lerpAmount = (1 - powf(1 - ratio, 3.0f));
|
||||
bool allProperties = arguments.properties == CLAY_TRANSITION_PROPERTY_ALL;
|
||||
if (allProperties || arguments.properties & CLAY_TRANSITION_PROPERTY_X) {
|
||||
if (arguments.properties & CLAY_TRANSITION_PROPERTY_X) {
|
||||
arguments.current->boundingBox.x = Lerp(arguments.initial.boundingBox.x, arguments.target.boundingBox.x, lerpAmount);
|
||||
} else {
|
||||
arguments.current->boundingBox.x = arguments.target.boundingBox.x;
|
||||
}
|
||||
if (allProperties || arguments.properties & CLAY_TRANSITION_PROPERTY_Y) {
|
||||
if (arguments.properties & CLAY_TRANSITION_PROPERTY_Y) {
|
||||
arguments.current->boundingBox.y = Lerp(arguments.initial.boundingBox.y, arguments.target.boundingBox.y, lerpAmount);
|
||||
} else {
|
||||
arguments.current->boundingBox.y = arguments.target.boundingBox.y;
|
||||
}
|
||||
if (allProperties || arguments.properties & CLAY_TRANSITION_PROPERTY_WIDTH) {
|
||||
if (arguments.properties & CLAY_TRANSITION_PROPERTY_WIDTH) {
|
||||
arguments.current->boundingBox.width = Lerp(arguments.initial.boundingBox.width, arguments.target.boundingBox.width, lerpAmount);
|
||||
} else {
|
||||
arguments.current->boundingBox.width = arguments.target.boundingBox.width;
|
||||
}
|
||||
if (allProperties || arguments.properties & CLAY_TRANSITION_PROPERTY_HEIGHT) {
|
||||
if (arguments.properties & CLAY_TRANSITION_PROPERTY_HEIGHT) {
|
||||
arguments.current->boundingBox.height = Lerp(arguments.initial.boundingBox.height, arguments.target.boundingBox.height, lerpAmount);
|
||||
} else {
|
||||
arguments.current->boundingBox.height = arguments.target.boundingBox.height;
|
||||
}
|
||||
if (allProperties || arguments.properties & CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR) {
|
||||
if (arguments.properties & CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR) {
|
||||
arguments.current->backgroundColor = CLAY__INIT(Clay_Color) {
|
||||
.r = Lerp(arguments.initial.backgroundColor.r, arguments.target.backgroundColor.r, lerpAmount),
|
||||
.g = Lerp(arguments.initial.backgroundColor.g, arguments.target.backgroundColor.g, lerpAmount),
|
||||
.b = Lerp(arguments.initial.backgroundColor.b, arguments.target.backgroundColor.b, lerpAmount),
|
||||
.a = Lerp(arguments.initial.backgroundColor.a, arguments.target.backgroundColor.a, lerpAmount),
|
||||
};
|
||||
} else {
|
||||
arguments.current->backgroundColor = arguments.target.backgroundColor;
|
||||
}
|
||||
if (allProperties || arguments.properties & CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR) {
|
||||
if (arguments.properties & CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR) {
|
||||
arguments.current->overlayColor = CLAY__INIT(Clay_Color) {
|
||||
.r = Lerp(arguments.initial.overlayColor.r, arguments.target.overlayColor.r, lerpAmount),
|
||||
.g = Lerp(arguments.initial.overlayColor.g, arguments.target.overlayColor.g, lerpAmount),
|
||||
.b = Lerp(arguments.initial.overlayColor.b, arguments.target.overlayColor.b, lerpAmount),
|
||||
.a = Lerp(arguments.initial.overlayColor.a, arguments.target.overlayColor.a, lerpAmount),
|
||||
};
|
||||
} else {
|
||||
arguments.current->overlayColor = arguments.target.overlayColor;
|
||||
}
|
||||
if (allProperties || arguments.properties & CLAY_TRANSITION_PROPERTY_BORDER_COLOR) {
|
||||
if (arguments.properties & CLAY_TRANSITION_PROPERTY_BORDER_COLOR) {
|
||||
arguments.current->borderColor = CLAY__INIT(Clay_Color) {
|
||||
.r = Lerp(arguments.initial.borderColor.r, arguments.target.borderColor.r, lerpAmount),
|
||||
.g = Lerp(arguments.initial.borderColor.g, arguments.target.borderColor.g, lerpAmount),
|
||||
.b = Lerp(arguments.initial.borderColor.b, arguments.target.borderColor.b, lerpAmount),
|
||||
.a = Lerp(arguments.initial.borderColor.a, arguments.target.borderColor.a, lerpAmount),
|
||||
};
|
||||
} else {
|
||||
arguments.current->borderColor = arguments.target.borderColor;
|
||||
}
|
||||
if (allProperties || arguments.properties & CLAY_TRANSITION_PROPERTY_BORDER_WIDTH) {
|
||||
if (arguments.properties & CLAY_TRANSITION_PROPERTY_BORDER_WIDTH) {
|
||||
arguments.current->borderWidth = CLAY__INIT(Clay_BorderWidth) {
|
||||
.left = Lerp(arguments.initial.borderWidth.left, arguments.target.borderWidth.left, lerpAmount),
|
||||
.right = Lerp(arguments.initial.borderWidth.right, arguments.target.borderWidth.right, lerpAmount),
|
||||
|
|
@ -133,16 +118,9 @@ bool Clay_EaseOut(Clay_TransitionCallbackArguments arguments) {
|
|||
.bottom = Lerp(arguments.initial.borderWidth.bottom, arguments.target.borderWidth.bottom, lerpAmount),
|
||||
.betweenChildren = Lerp(arguments.initial.borderWidth.betweenChildren, arguments.target.borderWidth.betweenChildren, lerpAmount),
|
||||
};
|
||||
} else {
|
||||
arguments.current->borderWidth = arguments.target.borderWidth;
|
||||
}
|
||||
return false;
|
||||
} else {
|
||||
arguments.current->boundingBox = arguments.target.boundingBox;
|
||||
arguments.current->backgroundColor = arguments.target.backgroundColor;
|
||||
arguments.current->overlayColor = arguments.target.overlayColor;
|
||||
arguments.current->borderColor = arguments.target.borderColor;
|
||||
arguments.current->borderWidth = arguments.target.borderWidth;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -298,10 +276,8 @@ Clay_RenderCommandArray CreateLayout(void) {
|
|||
.border = { darker, CLAY_BORDER_OUTSIDE(3) },
|
||||
.transition = {
|
||||
.handler = Clay_EaseOut,
|
||||
.duration = 1.f,
|
||||
.properties = CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR
|
||||
| CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR
|
||||
| CLAY_TRANSITION_PROPERTY_WIDTH | CLAY_TRANSITION_PROPERTY_X | CLAY_TRANSITION_PROPERTY_Y,
|
||||
.duration = 0.5f,
|
||||
.properties = CLAY_TRANSITION_PROPERTY_WIDTH | CLAY_TRANSITION_PROPERTY_POSITION | CLAY_TRANSITION_PROPERTY_OVERLAY_COLOR | CLAY_TRANSITION_PROPERTY_BACKGROUND_COLOR,
|
||||
.enter = { .setInitialState = EnterExitSlideUp },
|
||||
.exit = { .setFinalState = EnterExitSlideUp },
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue