Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Core] Clay_GetElementIdsAtPoint #241

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 63 additions & 0 deletions clay.h
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,12 @@ typedef struct {
uintptr_t userData;
} Clay_ErrorHandler;

typedef struct
{
int32_t length;
const Clay_ElementId *results;
} Clay_PointQueryResult;

// Function Forward Declarations ---------------------------------
// Public API functions ---
uint32_t Clay_MinMemorySize(void);
Expand Down Expand Up @@ -540,6 +546,7 @@ void Clay_SetMaxElementCount(int32_t maxElementCount);
int32_t Clay_GetMaxMeasureTextCacheWordCount(void);
void Clay_SetMaxMeasureTextCacheWordCount(int32_t maxMeasureTextCacheWordCount);
void Clay_ResetMeasureTextCache(void);
Clay_PointQueryResult Clay_GetElementIdsAtPoint(Clay_Vector2 point);

// Internal API functions required by macros
void Clay__OpenElement(void);
Expand Down Expand Up @@ -871,6 +878,8 @@ struct Clay_Context {
Clay__boolArray treeNodeVisited;
Clay__charArray dynamicStringData;
Clay__DebugElementDataArray debugElementData;
// Point querying
Clay__ElementIdArray pointQueryIds;
};

Clay_Context* Clay__Context_Allocate_Arena(Clay_Arena *arena) {
Expand Down Expand Up @@ -1536,6 +1545,7 @@ void Clay__InitializePersistentMemory(Clay_Context* context) {
context->measureTextHashMap = Clay__int32_tArray_Allocate_Arena(maxElementCount, arena);
context->measuredWords = Clay__MeasuredWordArray_Allocate_Arena(maxMeasureTextCacheWordCount, arena);
context->pointerOverIds = Clay__ElementIdArray_Allocate_Arena(maxElementCount, arena);
context->pointQueryIds = Clay__ElementIdArray_Allocate_Arena(maxElementCount, arena);
context->debugElementData = Clay__DebugElementDataArray_Allocate_Arena(maxElementCount, arena);
context->arenaResetOffset = arena->nextAllocation;
}
Expand Down Expand Up @@ -3176,6 +3186,59 @@ void Clay_SetPointerState(Clay_Vector2 position, bool isPointerDown) {
}
}

CLAY_WASM_EXPORT("Clay_GetElementIdsAtPoint")
Clay_PointQueryResult Clay_GetElementIdsAtPoint(Clay_Vector2 position) {
Clay_Context* context = Clay_GetCurrentContext();
if (context->booleanWarnings.maxElementsExceeded) {
return CLAY__INIT(Clay_PointQueryResult) { 0, NULL };
}
context->pointQueryIds.length = 0;
Clay__int32_tArray dfsBuffer = context->layoutElementChildrenBuffer;
for (int32_t rootIndex = context->layoutElementTreeRoots.length - 1; rootIndex >= 0; --rootIndex) {
dfsBuffer.length = 0;
Clay__LayoutElementTreeRoot *root = Clay__LayoutElementTreeRootArray_Get(&context->layoutElementTreeRoots, rootIndex);
Clay__int32_tArray_Add(&dfsBuffer, (int32_t)root->layoutElementIndex);
context->treeNodeVisited.internalArray[0] = false;
bool found = false;
while (dfsBuffer.length > 0) {
if (context->treeNodeVisited.internalArray[dfsBuffer.length - 1]) {
dfsBuffer.length--;
continue;
}
context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = true;
Clay_LayoutElement *currentElement = Clay_LayoutElementArray_Get(&context->layoutElements, Clay__int32_tArray_GetValue(&dfsBuffer, (int)dfsBuffer.length - 1));
Clay_LayoutElementHashMapItem *mapItem = Clay__GetHashMapItem(currentElement->id); // TODO think of a way around this, maybe the fact that it's essentially a binary tree limits the cost, but the worst case is not great
Clay_BoundingBox elementBox = mapItem->boundingBox;
elementBox.x -= root->pointerOffset.x;
elementBox.y -= root->pointerOffset.y;
if (mapItem) {
if ((Clay__PointIsInsideRect(position, elementBox))) {
Clay__ElementIdArray_Add(&context->pointQueryIds, mapItem->elementId);
found = true;
}
if (Clay__ElementHasConfig(currentElement, CLAY__ELEMENT_CONFIG_TYPE_TEXT)) {
dfsBuffer.length--;
continue;
}
for (int32_t i = currentElement->childrenOrTextContent.children.length - 1; i >= 0; --i) {
Clay__int32_tArray_Add(&dfsBuffer, currentElement->childrenOrTextContent.children.elements[i]);
context->treeNodeVisited.internalArray[dfsBuffer.length - 1] = false; // TODO needs to be ranged checked
}
} else {
dfsBuffer.length--;
}
}

Clay_LayoutElement *rootElement = Clay_LayoutElementArray_Get(&context->layoutElements, root->layoutElementIndex);
if (found && Clay__ElementHasConfig(rootElement, CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER) &&
Clay__FindElementConfigWithType(rootElement, CLAY__ELEMENT_CONFIG_TYPE_FLOATING_CONTAINER).floatingElementConfig->pointerCaptureMode == CLAY_POINTER_CAPTURE_MODE_CAPTURE) {
break;
}
}

return CLAY__INIT(Clay_PointQueryResult) { context->pointQueryIds.length, context->pointQueryIds.internalArray };
}

CLAY_WASM_EXPORT("Clay_Initialize")
Clay_Context* Clay_Initialize(Clay_Arena arena, Clay_Dimensions layoutDimensions, Clay_ErrorHandler errorHandler) {
Clay_Context *context = Clay__Context_Allocate_Arena(&arena);
Expand Down
Loading