Skip to content

Commit

Permalink
GetElementAtPoint() now ignores events handled by the documents root …
Browse files Browse the repository at this point in the history
…(body) to allow lower indexed docs to receive events.

This fixes issue libRocket#288. Might need more settings/flags to allow either the old and new behavior.
Also factored out the recursive routine in a separate method to increase readability.
  • Loading branch information
rickyviking committed Mar 7, 2017
1 parent 40f43b9 commit 4003b67
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 72 deletions.
4 changes: 3 additions & 1 deletion Include/Rocket/Core/Context.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,9 @@ class ROCKETCORE_API Context : public ScriptInterface
// @param[in] ignore_element If set, this element and its descendents will be ignored.
// @param[in] element Used internally.
// @return The element under the point, or NULL if nothing is.
Element* GetElementAtPoint(const Vector2f& point, const Element* ignore_element = NULL, Element* element = NULL);
Element* GetElementAtPoint(const Vector2f& point, const Element* ignore_element = NULL);

Element* GetElementAtPointRecursive(const Vector2f& point, const Element* ignore_element = NULL, Element* element = NULL);

// Creates the drag clone from the given element. The old drag clone will be released if
// necessary.
Expand Down
155 changes: 84 additions & 71 deletions Source/Core/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1038,83 +1038,96 @@ void Context::UpdateHoverChain(const Dictionary& parameters, const Dictionary& d
hover_chain.swap(new_hover_chain);
}

// Returns the youngest descendent of the given element which is under the given point in screen coodinates.
Element* Context::GetElementAtPoint(const Vector2f& point, const Element* ignore_element, Element* element)
{
// Update the layout on all documents prior to this call.
for (int i = 0; i < GetNumDocuments(); ++i)
GetDocument(i)->UpdateLayout();

if (element == NULL)
{
if (ignore_element == root)
return NULL;

element = root;
}

// Check if any documents have modal focus; if so, only check down than document.
if (element == root)
{
if (focus)
{
ElementDocument* focus_document = focus->GetOwnerDocument();
if (focus_document != NULL &&
focus_document->IsModal())
{
element = focus_document;
}
}
}

// Check any elements within our stacking context. We want to return the lowest-down element
// that is under the cursor.
if (element->local_stacking_context)
{
if (element->stacking_context_dirty)
element->BuildLocalStackingContext();

for (int i = (int) element->stacking_context.size() - 1; i >= 0; --i)
{
if (ignore_element != NULL)
{
Element* element_hierarchy = element->stacking_context[i];
while (element_hierarchy != NULL)
{
if (element_hierarchy == ignore_element)
break;

element_hierarchy = element_hierarchy->GetParentNode();
}
// local recursive method
Element* Context::GetElementAtPointRecursive(const Vector2f& point, const Element* ignore_element, Element* element)
{
// Check any elements within our stacking context. We want to return the lowest-down element
// that is under the cursor.
if (element->local_stacking_context)
{
if (element->stacking_context_dirty)
element->BuildLocalStackingContext();

for (int i = (int)element->stacking_context.size() - 1; i >= 0; --i)
{
if (ignore_element != NULL)
{
Element* element_hierarchy = element->stacking_context[i];
while (element_hierarchy != NULL)
{
if (element_hierarchy == ignore_element)
break;

element_hierarchy = element_hierarchy->GetParentNode();
}

if (element_hierarchy != NULL)
continue;
}

Element* child_element = GetElementAtPointRecursive(point, ignore_element, element->stacking_context[i]);

if (child_element != NULL)
{
// if the element is a document root, keep checking
// TODO should we expose a setting for this?
if (child_element != child_element->GetOwnerDocument())
return child_element;
}
}
}

// Check if the point is actually within this element.
bool within_element = element->IsPointWithinElement(point);
if (within_element)
{
Vector2i clip_origin, clip_dimensions;
if (ElementUtilities::GetClippingRegion(clip_origin, clip_dimensions, element))
{
within_element = point.x >= clip_origin.x &&
point.y >= clip_origin.y &&
point.x <= (clip_origin.x + clip_dimensions.x) &&
point.y <= (clip_origin.y + clip_dimensions.y);
}
}

if (within_element)
return element;

return NULL;
}

if (element_hierarchy != NULL)
continue;
}

Element* child_element = GetElementAtPoint(point, ignore_element, element->stacking_context[i]);
if (child_element != NULL)
return child_element;
}
}

// Check if the point is actually within this element.
bool within_element = element->IsPointWithinElement(point);
if (within_element)
{
Vector2i clip_origin, clip_dimensions;
if (ElementUtilities::GetClippingRegion(clip_origin, clip_dimensions, element))
{
within_element = point.x >= clip_origin.x &&
point.y >= clip_origin.y &&
point.x <= (clip_origin.x + clip_dimensions.x) &&
point.y <= (clip_origin.y + clip_dimensions.y);
}
}
// Returns the youngest descendent of the given element which is under the given point in screen coodinates.
Element* Context::GetElementAtPoint(const Vector2f& point, const Element* ignore_element)
{
// performance check, nothing to do if ignoring from the root
if (ignore_element == root)
return NULL;

if (within_element)
return element;
// Update the layout on all documents prior to this call.
for (int i = 0; i < GetNumDocuments(); ++i)
GetDocument(i)->UpdateLayout();

return NULL;
// element to start the search from:
// root by default
Element* startElement = root;

// BUT if any documents have modal focus; only check down that document.
if (focus)
{
ElementDocument* focus_document = focus->GetOwnerDocument();
if (focus_document != NULL &&
focus_document->IsModal())
{
startElement = focus_document;
}
}

// now check down recursively from the start node
return GetElementAtPointRecursive(point, ignore_element, startElement);
}

// Creates the drag clone from the given element.
Expand Down

0 comments on commit 4003b67

Please sign in to comment.