From a1804fdefbcfc7b1afb68372e350062eeb104d38 Mon Sep 17 00:00:00 2001 From: Michael Freno Date: Sun, 2 Nov 2025 18:48:40 -0500 Subject: [PATCH] elements in scrollable area fixed --- FlexLove.lua | 27 ++++++++++++++++++++++++--- modules/Element.lua | 23 ++++++++++++++++++++++- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/FlexLove.lua b/FlexLove.lua index a904621..05d70bd 100644 --- a/FlexLove.lua +++ b/FlexLove.lua @@ -216,13 +216,20 @@ function Gui.getElementAtPosition(x, y) local candidates = {} local blockingElements = {} - local function collectHits(element) + local function collectHits(element, scrollOffsetX, scrollOffsetY) + scrollOffsetX = scrollOffsetX or 0 + scrollOffsetY = scrollOffsetY or 0 + local bx = element.x local by = element.y local bw = element._borderBoxWidth or (element.width + element.padding.left + element.padding.right) local bh = element._borderBoxHeight or (element.height + element.padding.top + element.padding.bottom) - if x >= bx and x <= bx + bw and y >= by and y <= by + bh then + -- Adjust mouse position by accumulated scroll offset for hit testing + local adjustedX = x + scrollOffsetX + local adjustedY = y + scrollOffsetY + + if adjustedX >= bx and adjustedX <= bx + bw and adjustedY >= by and adjustedY <= by + bh then -- Collect interactive elements (those with callbacks) if element.callback and not element.disabled then table.insert(candidates, element) @@ -234,8 +241,22 @@ function Gui.getElementAtPosition(x, y) table.insert(blockingElements, element) end + -- Check if this element has scrollable overflow + local overflowX = element.overflowX or element.overflow + local overflowY = element.overflowY or element.overflow + local hasScrollableOverflow = (overflowX == "scroll" or overflowX == "auto" or overflowY == "scroll" or overflowY == "auto" or + overflowX == "hidden" or overflowY == "hidden") + + -- Accumulate scroll offset for children if this element has overflow clipping + local childScrollOffsetX = scrollOffsetX + local childScrollOffsetY = scrollOffsetY + if hasScrollableOverflow then + childScrollOffsetX = childScrollOffsetX + (element._scrollX or 0) + childScrollOffsetY = childScrollOffsetY + (element._scrollY or 0) + end + for _, child in ipairs(element.children) do - collectHits(child) + collectHits(child, childScrollOffsetX, childScrollOffsetY) end end end diff --git a/modules/Element.lua b/modules/Element.lua index 0755aed..93ebae5 100644 --- a/modules/Element.lua +++ b/modules/Element.lua @@ -2848,7 +2848,28 @@ function Element:update(dt) local by = self.y local bw = self._borderBoxWidth or (self.width + self.padding.left + self.padding.right) local bh = self._borderBoxHeight or (self.height + self.padding.top + self.padding.bottom) - local isHovering = mx >= bx and mx <= bx + bw and my >= by and my <= by + bh + + -- Account for scroll offsets from parent containers + -- Walk up the parent chain and accumulate scroll offsets + local scrollOffsetX = 0 + local scrollOffsetY = 0 + local current = self.parent + while current do + local overflowX = current.overflowX or current.overflow + local overflowY = current.overflowY or current.overflow + local hasScrollableOverflow = (overflowX == "scroll" or overflowX == "auto" or overflowY == "scroll" or overflowY == "auto" or + overflowX == "hidden" or overflowY == "hidden") + if hasScrollableOverflow then + scrollOffsetX = scrollOffsetX + (current._scrollX or 0) + scrollOffsetY = scrollOffsetY + (current._scrollY or 0) + end + current = current.parent + end + + -- Adjust mouse position by accumulated scroll offset for hit testing + local adjustedMx = mx + scrollOffsetX + local adjustedMy = my + scrollOffsetY + local isHovering = adjustedMx >= bx and adjustedMx <= bx + bw and adjustedMy >= by and adjustedMy <= by + bh -- Check if this is the topmost element at the mouse position (z-index ordering) -- This prevents blocked elements from receiving interactions or visual feedback