add mouse wheel events and scroll attribute

This commit is contained in:
airstruck
2015-12-01 11:15:42 -05:00
parent 44d541bc8f
commit 591bb7507a
9 changed files with 140 additions and 12 deletions

View File

@@ -69,7 +69,7 @@ local mainForm = { id = 'mainWindow', type = 'panel',
icon = 'icon/32px/Harddrive.png' },
},
{ flow = 'x',
{ id = 'leftSideBox', width = 200, minwidth = 64,
{ id = 'leftSideBox', width = 200, minwidth = 64, scroll = true,
{ text = 'Hi, I\'m centered middle. ', style = 'listThing',
align = 'middle center' },
{ text = 'Hi, I\'m right bottom.\nAlso two lines, woopdy woop.Hi, I\'m right bottom.\nAlso two lines, woopdy woop.Hi, I\'m right bottom.\nAlso two lines, woopdy woop.', style = 'listThing',

View File

@@ -122,6 +122,20 @@ function Attribute.style (widget, value)
widget.reshape(widget.parent or widget)
end
--[[--
Scroll ability.
Should contain `true` or `false` (or `nil`).
If set to `true`, moving the scroll wheel over the widget will adjust
its scroll position when the widget's contents overflow its boundary.
@attrib scroll
--]]--
function Attribute.scroll (widget, value)
widget.attributes.scroll = value
end
--[[--
Size Attributes.

View File

@@ -47,6 +47,7 @@ local callback = {
keypressed = function () end,
keyreleased = function () end,
textinput = function () end,
wheelmoved = function () end,
}
Backend.run = function ()
@@ -79,6 +80,9 @@ Backend.run = function ()
callback.keyreleased(key, event.key['repeat'])
elseif event.type == sdl.TEXTINPUT then
callback.textinput(ffi.string(event.text.text))
elseif event.type == sdl.MOUSEWHEEL then
local wheel = event.wheel
callback.wheelmoved(wheel.x, wheel.y)
end
end
@@ -269,8 +273,10 @@ local stack = {}
Backend.pop = function ()
local history = stack[#stack]
Backend.setColor(history.color or { 0, 0, 0, 255 })
Backend.setScissor(history.scissor)
local color = history.color or { 0, 0, 0, 255 }
sdl.setRenderDrawColor(renderer,
color[1], color[2], color[3], color[4] or 255)
sdl.renderSetClipRect(renderer, history.scissor) -- Backend.setScissor(history.scissor)
stack[#stack] = nil
end
@@ -316,6 +322,9 @@ function Backend.show (layout)
hook(layout, 'textinput', function (text)
return input:handleTextInput(layout, text, Backend.getMousePosition())
end)
hook(layout, 'wheelmoved', function (x, y)
return input:handleWheelMove(layout, x, y)
end)
end
return Backend

View File

@@ -115,6 +115,9 @@ function Backend.show (layout)
return input:handleReshape(layout, width, height)
end)
hook(layout, 'mousepressed', function (x, y, button)
if love._version_minor < 10 and button == 'wu' or button == 'wd' then
return input:handleWheelMove(layout, 0, button == 'wu' and 1 or -1)
end
return input:handlePressStart(layout, getMouseButtonId(button), x, y)
end)
hook(layout, 'mousereleased', function (x, y, button)
@@ -136,6 +139,11 @@ function Backend.show (layout)
hook(layout, 'textinput', function (text)
return input:handleTextInput(layout, text, Backend.getMousePosition())
end)
if love._version_minor > 9 then
hook(layout, 'wheelmoved', function (x, y)
return input:handleWheelMove(layout, x, y)
end)
end
end
return Backend

View File

@@ -44,6 +44,7 @@ Event.names = {
'PressMove', -- A pressed cursor moved; targets widget at cursor position.
'Press', -- A pointer button was pressed and released on the same widget.
'Change', -- A widget's value changed.
'WheelMove', -- The scroll wheel on the mouse moved.
}
local weakKeyMeta = { __mode = 'k' }

View File

@@ -213,16 +213,30 @@ end
function Input:handleReshape (layout, width, height)
local root = layout.root
Event.Reshape:emit(layout, {
target = layout
})
Event.Reshape:emit(layout, { target = layout })
if root.float then
return
if not root.float then
root.width = width
root.height = height
end
end
function Input:handleWheelMove (layout, x, y)
local root = layout.root
local mx, my = Backend.getMousePosition()
local widget = layout:getWidgetAt(mx, my)
if not widget then
hit = nil
widget = layout.root
end
root.width = width
root.height = height
widget:bubbleEvent('WheelMove', {
hit = hit,
x = x, y = y
})
return hit
end
Input.default = Input()

View File

@@ -302,6 +302,29 @@ function Layout:addDefaultHandlers ()
acceleratedWidget, event.key)
end
end)
self:onWheelMove(function (event)
for widget in event.target:eachAncestor(true) do
if widget.scroll then
if not widget.scrollY then
widget.scrollY = 0
end
local scrollY = widget.scrollY - event.y * 10
local maxY = widget:getContentHeight() - widget:getHeight()
if scrollY > maxY then
scrollY = maxY
end
if scrollY < 0 then
scrollY = 0
end
if scrollY ~= widget.scrollY then
widget.scrollY = scrollY
widget:reshape()
return false
end
end -- if widget.scroll
end -- ancestor loop
end) -- wheel move
end
Event.injectBinders(Layout)

View File

@@ -196,7 +196,9 @@ function Renderer:renderIconAndText (widget)
Backend.push()
Backend.setScissor(x, y, w, h)
local parentY = widget.parent and widget.parent:getY() or 0
Backend.setScissor(x, math.max(y, parentY), w, h)
-- calculate position for icon and text based on alignment and padding
local iconX, iconY, x1, y1, x2, y2 = self:positionIcon(
@@ -266,11 +268,32 @@ end
function Renderer:render (widget)
Event.PreDisplay:emit(widget, { target = widget }, function()
local x, y, w, h = widget:getRectangle()
-- if the drawable area has no width or height, don't render
if w < 1 or h < 1 then
return
end
Backend.push()
if widget.parent then
local parentY = widget.parent:getY()
Backend.setScissor(x, math.max(y, parentY), w, h)
else
Backend.setScissor()
end
self:renderBackground(widget)
self:renderOutline(widget)
self:renderSlices(widget)
self:renderIconAndText(widget)
Backend.pop()
return self:renderChildren(widget)
end)
Event.Display:emit(widget, { target = widget })
end

View File

@@ -358,13 +358,17 @@ function Widget:calculatePosition (axis)
return self.position[axis]
end
local parent = self.parent
local scroll = 0
if not parent then
self.position[axis] = axis == 'x' and (self.left or 0)
or axis == 'y' and (self.top or 0)
return self.position[axis]
elseif parent then
scroll = axis == 'x' and (parent.scrollX or 0)
or axis == 'y' and (parent.scrollY or 0)
end
local parentPos = parent:calculatePosition(axis)
local p = parentPos
local p = parentPos - scroll
p = p + (parent.margin or 0)
p = p + (parent.padding or 0)
local parentFlow = parent.flow or 'y'
@@ -422,6 +426,38 @@ function Widget:getHeight ()
return self:calculateDimension('height')
end
--[[--
Get the content width.
Gets the combined width of the widget's children.
@treturn number
The content width.
--]]--
function Widget:getContentWidth ()
local width = 0
for _, child in ipairs(self) do
width = width + child:getWidth()
end
return width
end
--[[--
Get the content height.
Gets the combined height of the widget's children.
@treturn number
The content height.
--]]--
function Widget:getContentHeight ()
local height = 0
for _, child in ipairs(self) do
height = height + child:getHeight()
end
return height
end
--[[--
Get x/y/width/height values describing a rectangle within the widget.