scrolling fixed for immediate mode
This commit is contained in:
@@ -1458,6 +1458,32 @@ function Element.new(props)
|
|||||||
self._scrollbarDragging = false
|
self._scrollbarDragging = false
|
||||||
self._hoveredScrollbar = nil
|
self._hoveredScrollbar = nil
|
||||||
self._scrollbarDragOffset = 0
|
self._scrollbarDragOffset = 0
|
||||||
|
|
||||||
|
-- Restore scrollbar state from StateManager in immediate mode (must happen before layout)
|
||||||
|
if Element._Context._immediateMode and self._stateId and self._stateId ~= "" then
|
||||||
|
local state = Element._StateManager.getState(self._stateId)
|
||||||
|
if state and state.scrollManager then
|
||||||
|
-- Restore from nested scrollManager state (saved via saveState())
|
||||||
|
self._scrollbarHoveredVertical = state.scrollManager._scrollbarHoveredVertical or false
|
||||||
|
self._scrollbarHoveredHorizontal = state.scrollManager._scrollbarHoveredHorizontal or false
|
||||||
|
self._scrollbarDragging = state.scrollManager._scrollbarDragging or false
|
||||||
|
self._hoveredScrollbar = state.scrollManager._hoveredScrollbar
|
||||||
|
self._scrollbarDragOffset = state.scrollManager._scrollbarDragOffset or 0
|
||||||
|
|
||||||
|
-- Apply to ScrollManager immediately
|
||||||
|
self._scrollManager._scrollbarHoveredVertical = self._scrollbarHoveredVertical
|
||||||
|
self._scrollManager._scrollbarHoveredHorizontal = self._scrollbarHoveredHorizontal
|
||||||
|
self._scrollManager._scrollbarDragging = self._scrollbarDragging
|
||||||
|
self._scrollManager._hoveredScrollbar = self._hoveredScrollbar
|
||||||
|
self._scrollManager._scrollbarDragOffset = self._scrollbarDragOffset
|
||||||
|
|
||||||
|
-- Restore drag start positions for relative movement tracking
|
||||||
|
self._scrollManager._dragStartMouseX = state.scrollManager._dragStartMouseX or 0
|
||||||
|
self._scrollManager._dragStartMouseY = state.scrollManager._dragStartMouseY or 0
|
||||||
|
self._scrollManager._dragStartScrollX = state.scrollManager._dragStartScrollX or 0
|
||||||
|
self._scrollManager._dragStartScrollY = state.scrollManager._dragStartScrollY or 0
|
||||||
|
end
|
||||||
|
end
|
||||||
else
|
else
|
||||||
self._scrollManager = nil
|
self._scrollManager = nil
|
||||||
end
|
end
|
||||||
@@ -2190,12 +2216,13 @@ function Element:update(dt)
|
|||||||
-- Restore scrollbar state from StateManager in immediate mode
|
-- Restore scrollbar state from StateManager in immediate mode
|
||||||
if self._stateId and Element._Context._immediateMode then
|
if self._stateId and Element._Context._immediateMode then
|
||||||
local state = Element._StateManager.getState(self._stateId)
|
local state = Element._StateManager.getState(self._stateId)
|
||||||
if state then
|
if state and state.scrollManager then
|
||||||
self._scrollbarHoveredVertical = state.scrollbarHoveredVertical or false
|
-- Restore from nested scrollManager state (saved via saveState())
|
||||||
self._scrollbarHoveredHorizontal = state.scrollbarHoveredHorizontal or false
|
self._scrollbarHoveredVertical = state.scrollManager._scrollbarHoveredVertical or false
|
||||||
self._scrollbarDragging = state.scrollbarDragging or false
|
self._scrollbarHoveredHorizontal = state.scrollManager._scrollbarHoveredHorizontal or false
|
||||||
self._hoveredScrollbar = state.hoveredScrollbar
|
self._scrollbarDragging = state.scrollManager._scrollbarDragging or false
|
||||||
self._scrollbarDragOffset = state.scrollbarDragOffset or 0
|
self._hoveredScrollbar = state.scrollManager._hoveredScrollbar
|
||||||
|
self._scrollbarDragOffset = state.scrollManager._scrollbarDragOffset or 0
|
||||||
|
|
||||||
if self._scrollManager then
|
if self._scrollManager then
|
||||||
self._scrollManager._scrollbarHoveredVertical = self._scrollbarHoveredVertical
|
self._scrollManager._scrollbarHoveredVertical = self._scrollbarHoveredVertical
|
||||||
@@ -2203,6 +2230,12 @@ function Element:update(dt)
|
|||||||
self._scrollManager._scrollbarDragging = self._scrollbarDragging
|
self._scrollManager._scrollbarDragging = self._scrollbarDragging
|
||||||
self._scrollManager._hoveredScrollbar = self._hoveredScrollbar
|
self._scrollManager._hoveredScrollbar = self._hoveredScrollbar
|
||||||
self._scrollManager._scrollbarDragOffset = self._scrollbarDragOffset
|
self._scrollManager._scrollbarDragOffset = self._scrollbarDragOffset
|
||||||
|
|
||||||
|
-- Restore drag start positions for relative movement tracking
|
||||||
|
self._scrollManager._dragStartMouseX = state.scrollManager._dragStartMouseX or 0
|
||||||
|
self._scrollManager._dragStartMouseY = state.scrollManager._dragStartMouseY or 0
|
||||||
|
self._scrollManager._dragStartScrollX = state.scrollManager._dragStartScrollX or 0
|
||||||
|
self._scrollManager._dragStartScrollY = state.scrollManager._dragStartScrollY or 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -2317,14 +2350,8 @@ function Element:update(dt)
|
|||||||
self:_syncScrollManagerState()
|
self:_syncScrollManagerState()
|
||||||
end
|
end
|
||||||
|
|
||||||
if self._stateId and Element._Context._immediateMode then
|
-- Note: Scrollbar state is saved via saveState() -> ScrollManager:getState() at end of frame
|
||||||
Element._StateManager.updateState(self._stateId, {
|
-- This intermediate save is kept for backward compatibility with hover states
|
||||||
scrollbarHoveredVertical = self._scrollbarHoveredVertical,
|
|
||||||
scrollbarHoveredHorizontal = self._scrollbarHoveredHorizontal,
|
|
||||||
scrollbarDragging = self._scrollbarDragging,
|
|
||||||
hoveredScrollbar = self._hoveredScrollbar,
|
|
||||||
})
|
|
||||||
end
|
|
||||||
|
|
||||||
if self._scrollbarDragging and love.mouse.isDown(1) then
|
if self._scrollbarDragging and love.mouse.isDown(1) then
|
||||||
self:_handleScrollbarDrag(mx, my)
|
self:_handleScrollbarDrag(mx, my)
|
||||||
@@ -2439,9 +2466,7 @@ function Element:update(dt)
|
|||||||
-- Update theme state via ThemeManager
|
-- Update theme state via ThemeManager
|
||||||
local newThemeState = self._themeManager:updateState(isHovering and isActiveElement, anyPressed, self._focused, self.disabled)
|
local newThemeState = self._themeManager:updateState(isHovering and isActiveElement, anyPressed, self._focused, self.disabled)
|
||||||
|
|
||||||
-- Update state (in StateManager if in immediate mode, otherwise locally)
|
|
||||||
if self._stateId and Element._Context._immediateMode then
|
if self._stateId and Element._Context._immediateMode then
|
||||||
-- Update in StateManager for immediate mode
|
|
||||||
local hover = newThemeState == "hover"
|
local hover = newThemeState == "hover"
|
||||||
local pressed = newThemeState == "pressed"
|
local pressed = newThemeState == "pressed"
|
||||||
local focused = newThemeState == "active" or self._focused
|
local focused = newThemeState == "active" or self._focused
|
||||||
@@ -2455,9 +2480,6 @@ function Element:update(dt)
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Always update local state for backward compatibility
|
|
||||||
self._themeState = newThemeState
|
|
||||||
-- Sync theme state with Renderer module
|
|
||||||
if self._renderer then
|
if self._renderer then
|
||||||
self._renderer:setThemeState(newThemeState)
|
self._renderer:setThemeState(newThemeState)
|
||||||
end
|
end
|
||||||
@@ -3177,14 +3199,23 @@ function Element:setProperty(property, value)
|
|||||||
|
|
||||||
-- Properties that affect layout and require invalidation
|
-- Properties that affect layout and require invalidation
|
||||||
local layoutProperties = {
|
local layoutProperties = {
|
||||||
width = true, height = true,
|
width = true,
|
||||||
padding = true, margin = true,
|
height = true,
|
||||||
|
padding = true,
|
||||||
|
margin = true,
|
||||||
gap = true,
|
gap = true,
|
||||||
flexDirection = true, flexWrap = true,
|
flexDirection = true,
|
||||||
justifyContent = true, alignItems = true, alignContent = true,
|
flexWrap = true,
|
||||||
|
justifyContent = true,
|
||||||
|
alignItems = true,
|
||||||
|
alignContent = true,
|
||||||
positioning = true,
|
positioning = true,
|
||||||
gridRows = true, gridColumns = true,
|
gridRows = true,
|
||||||
top = true, right = true, bottom = true, left = true,
|
gridColumns = true,
|
||||||
|
top = true,
|
||||||
|
right = true,
|
||||||
|
bottom = true,
|
||||||
|
left = true,
|
||||||
}
|
}
|
||||||
|
|
||||||
if shouldTransition and transitionConfig then
|
if shouldTransition and transitionConfig then
|
||||||
|
|||||||
@@ -31,7 +31,11 @@
|
|||||||
---@field _scrollbarHoveredHorizontal boolean -- True if mouse is over horizontal scrollbar
|
---@field _scrollbarHoveredHorizontal boolean -- True if mouse is over horizontal scrollbar
|
||||||
---@field _scrollbarDragging boolean -- True if currently dragging a scrollbar
|
---@field _scrollbarDragging boolean -- True if currently dragging a scrollbar
|
||||||
---@field _hoveredScrollbar string? -- "vertical" or "horizontal" when dragging
|
---@field _hoveredScrollbar string? -- "vertical" or "horizontal" when dragging
|
||||||
---@field _scrollbarDragOffset number -- Offset from thumb top when drag started
|
---@field _scrollbarDragOffset number -- DEPRECATED: Offset from thumb top when drag started (kept for compatibility)
|
||||||
|
---@field _dragStartMouseX number -- Mouse X position when drag started
|
||||||
|
---@field _dragStartMouseY number -- Mouse Y position when drag started
|
||||||
|
---@field _dragStartScrollX number -- Scroll X position when drag started
|
||||||
|
---@field _dragStartScrollY number -- Scroll Y position when drag started
|
||||||
---@field _scrollbarPressHandled boolean -- Track if scrollbar press was handled this frame
|
---@field _scrollbarPressHandled boolean -- Track if scrollbar press was handled this frame
|
||||||
---@field _touchScrolling boolean -- True if currently touch scrolling
|
---@field _touchScrolling boolean -- True if currently touch scrolling
|
||||||
---@field _scrollVelocityX number -- Current horizontal scroll velocity (px/s)
|
---@field _scrollVelocityX number -- Current horizontal scroll velocity (px/s)
|
||||||
@@ -112,7 +116,11 @@ function ScrollManager.new(config, deps)
|
|||||||
self._scrollbarHoveredHorizontal = false
|
self._scrollbarHoveredHorizontal = false
|
||||||
self._scrollbarDragging = false
|
self._scrollbarDragging = false
|
||||||
self._hoveredScrollbar = nil -- "vertical" or "horizontal"
|
self._hoveredScrollbar = nil -- "vertical" or "horizontal"
|
||||||
self._scrollbarDragOffset = 0
|
self._scrollbarDragOffset = 0 -- DEPRECATED: kept for backward compatibility
|
||||||
|
self._dragStartMouseX = 0 -- Mouse X position when drag started
|
||||||
|
self._dragStartMouseY = 0 -- Mouse Y position when drag started
|
||||||
|
self._dragStartScrollX = 0 -- Scroll X position when drag started
|
||||||
|
self._dragStartScrollY = 0 -- Scroll Y position when drag started
|
||||||
self._scrollbarPressHandled = false
|
self._scrollbarPressHandled = false
|
||||||
|
|
||||||
-- Touch scrolling state
|
-- Touch scrolling state
|
||||||
@@ -416,26 +424,18 @@ function ScrollManager:handleMousePress(element, mouseX, mouseY, button)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if scrollbar.region == "thumb" then
|
if scrollbar.region == "thumb" then
|
||||||
-- Start dragging thumb
|
-- Start dragging thumb - store start positions for relative movement tracking
|
||||||
self._scrollbarDragging = true
|
self._scrollbarDragging = true
|
||||||
self._hoveredScrollbar = scrollbar.component
|
self._hoveredScrollbar = scrollbar.component
|
||||||
local dims = self:calculateScrollbarDimensions(element)
|
|
||||||
|
|
||||||
if scrollbar.component == "vertical" then
|
-- Store drag start positions for relative movement calculation
|
||||||
local contentY = element.y + element.padding.top
|
self._dragStartMouseX = mouseX
|
||||||
local trackY = contentY + self.scrollbarPadding
|
self._dragStartMouseY = mouseY
|
||||||
local thumbY = trackY + dims.vertical.thumbY
|
self._dragStartScrollX = self._scrollX
|
||||||
self._scrollbarDragOffset = mouseY - thumbY
|
self._dragStartScrollY = self._scrollY
|
||||||
elseif scrollbar.component == "horizontal" then
|
|
||||||
local contentX = element.x + element.padding.left
|
|
||||||
local trackX = contentX + self.scrollbarPadding
|
|
||||||
local thumbX = trackX + dims.horizontal.thumbX
|
|
||||||
self._scrollbarDragOffset = mouseX - thumbX
|
|
||||||
end
|
|
||||||
|
|
||||||
return true -- Event consumed
|
return true -- Event consumed
|
||||||
elseif scrollbar.region == "track" then
|
elseif scrollbar.region == "track" then
|
||||||
-- Click on track - jump to position
|
|
||||||
self:_scrollToTrackPosition(element, mouseX, mouseY, scrollbar.component)
|
self:_scrollToTrackPosition(element, mouseX, mouseY, scrollbar.component)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -456,34 +456,36 @@ function ScrollManager:handleMouseMove(element, mouseX, mouseY)
|
|||||||
local dims = self:calculateScrollbarDimensions(element)
|
local dims = self:calculateScrollbarDimensions(element)
|
||||||
|
|
||||||
if self._hoveredScrollbar == "vertical" then
|
if self._hoveredScrollbar == "vertical" then
|
||||||
local contentY = element.y + element.padding.top
|
|
||||||
local trackY = contentY + self.scrollbarPadding
|
|
||||||
local trackH = dims.vertical.trackHeight
|
local trackH = dims.vertical.trackHeight
|
||||||
local thumbH = dims.vertical.thumbHeight
|
local thumbH = dims.vertical.thumbHeight
|
||||||
|
|
||||||
-- Calculate new thumb position
|
-- Calculate relative mouse movement from drag start
|
||||||
local newThumbY = mouseY - self._scrollbarDragOffset - trackY
|
local mouseDeltaY = mouseY - self._dragStartMouseY
|
||||||
newThumbY = self._utils.clamp(newThumbY, 0, trackH - thumbH)
|
|
||||||
|
|
||||||
-- Convert thumb position to scroll position
|
-- Convert mouse delta to scroll delta
|
||||||
local scrollRatio = (trackH - thumbH) > 0 and (newThumbY / (trackH - thumbH)) or 0
|
-- scrollDelta / maxScroll = thumbDelta / (trackHeight - thumbHeight)
|
||||||
local newScrollY = scrollRatio * self._maxScrollY
|
local scrollableTrackHeight = trackH - thumbH
|
||||||
|
local scrollDelta = scrollableTrackHeight > 0 and (mouseDeltaY / scrollableTrackHeight) * self._maxScrollY or 0
|
||||||
|
|
||||||
|
local newScrollY = self._dragStartScrollY + scrollDelta
|
||||||
|
newScrollY = self._utils.clamp(newScrollY, 0, self._maxScrollY)
|
||||||
|
|
||||||
self:setScroll(nil, newScrollY)
|
self:setScroll(nil, newScrollY)
|
||||||
return true
|
return true
|
||||||
elseif self._hoveredScrollbar == "horizontal" then
|
elseif self._hoveredScrollbar == "horizontal" then
|
||||||
local contentX = element.x + element.padding.left
|
|
||||||
local trackX = contentX + self.scrollbarPadding
|
|
||||||
local trackW = dims.horizontal.trackWidth
|
local trackW = dims.horizontal.trackWidth
|
||||||
local thumbW = dims.horizontal.thumbWidth
|
local thumbW = dims.horizontal.thumbWidth
|
||||||
|
|
||||||
-- Calculate new thumb position
|
-- Calculate relative mouse movement from drag start
|
||||||
local newThumbX = mouseX - self._scrollbarDragOffset - trackX
|
local mouseDeltaX = mouseX - self._dragStartMouseX
|
||||||
newThumbX = self._utils.clamp(newThumbX, 0, trackW - thumbW)
|
|
||||||
|
|
||||||
-- Convert thumb position to scroll position
|
-- Convert mouse delta to scroll delta
|
||||||
local scrollRatio = (trackW - thumbW) > 0 and (newThumbX / (trackW - thumbW)) or 0
|
local scrollableTrackWidth = trackW - thumbW
|
||||||
local newScrollX = scrollRatio * self._maxScrollX
|
local scrollDelta = scrollableTrackWidth > 0 and (mouseDeltaX / scrollableTrackWidth) * self._maxScrollX or 0
|
||||||
|
|
||||||
|
-- Apply delta to starting scroll position
|
||||||
|
local newScrollX = self._dragStartScrollX + scrollDelta
|
||||||
|
newScrollX = self._utils.clamp(newScrollX, 0, self._maxScrollX)
|
||||||
|
|
||||||
self:setScroll(newScrollX, nil)
|
self:setScroll(newScrollX, nil)
|
||||||
return true
|
return true
|
||||||
@@ -646,7 +648,11 @@ function ScrollManager:getState()
|
|||||||
_targetScrollY = self._targetScrollY,
|
_targetScrollY = self._targetScrollY,
|
||||||
_scrollbarDragging = self._scrollbarDragging or false,
|
_scrollbarDragging = self._scrollbarDragging or false,
|
||||||
_hoveredScrollbar = self._hoveredScrollbar,
|
_hoveredScrollbar = self._hoveredScrollbar,
|
||||||
_scrollbarDragOffset = self._scrollbarDragOffset or 0,
|
_scrollbarDragOffset = self._scrollbarDragOffset or 0, -- Deprecated but kept for compatibility
|
||||||
|
_dragStartMouseX = self._dragStartMouseX or 0,
|
||||||
|
_dragStartMouseY = self._dragStartMouseY or 0,
|
||||||
|
_dragStartScrollX = self._dragStartScrollX or 0,
|
||||||
|
_dragStartScrollY = self._dragStartScrollY or 0,
|
||||||
_scrollbarHoveredVertical = self._scrollbarHoveredVertical or false,
|
_scrollbarHoveredVertical = self._scrollbarHoveredVertical or false,
|
||||||
_scrollbarHoveredHorizontal = self._scrollbarHoveredHorizontal or false,
|
_scrollbarHoveredHorizontal = self._scrollbarHoveredHorizontal or false,
|
||||||
scrollBarStyle = self.scrollBarStyle,
|
scrollBarStyle = self.scrollBarStyle,
|
||||||
@@ -695,6 +701,23 @@ function ScrollManager:setState(state)
|
|||||||
self._scrollbarDragOffset = state.scrollbarDragOffset
|
self._scrollbarDragOffset = state.scrollbarDragOffset
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Restore drag start positions for relative movement tracking
|
||||||
|
if state._dragStartMouseX ~= nil then
|
||||||
|
self._dragStartMouseX = state._dragStartMouseX
|
||||||
|
end
|
||||||
|
|
||||||
|
if state._dragStartMouseY ~= nil then
|
||||||
|
self._dragStartMouseY = state._dragStartMouseY
|
||||||
|
end
|
||||||
|
|
||||||
|
if state._dragStartScrollX ~= nil then
|
||||||
|
self._dragStartScrollX = state._dragStartScrollX
|
||||||
|
end
|
||||||
|
|
||||||
|
if state._dragStartScrollY ~= nil then
|
||||||
|
self._dragStartScrollY = state._dragStartScrollY
|
||||||
|
end
|
||||||
|
|
||||||
if state._scrollbarHoveredVertical ~= nil then
|
if state._scrollbarHoveredVertical ~= nil then
|
||||||
self._scrollbarHoveredVertical = state._scrollbarHoveredVertical
|
self._scrollbarHoveredVertical = state._scrollbarHoveredVertical
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -37,6 +37,10 @@ local stateDefaults = {
|
|||||||
scrollbarDragging = false,
|
scrollbarDragging = false,
|
||||||
hoveredScrollbar = nil,
|
hoveredScrollbar = nil,
|
||||||
scrollbarDragOffset = 0,
|
scrollbarDragOffset = 0,
|
||||||
|
dragStartMouseX = 0,
|
||||||
|
dragStartMouseY = 0,
|
||||||
|
dragStartScrollX = 0,
|
||||||
|
dragStartScrollY = 0,
|
||||||
|
|
||||||
-- Scroll position
|
-- Scroll position
|
||||||
scrollX = 0,
|
scrollX = 0,
|
||||||
|
|||||||
Reference in New Issue
Block a user