9-slice image support

This commit is contained in:
airstruck
2015-10-27 01:15:47 -04:00
parent c9414eec48
commit 61c9aacd94
12 changed files with 126 additions and 41 deletions

View File

@@ -14,12 +14,9 @@ local style = {
toolButton = {
align = 'center middle',
width = 48,
margin = 4,
padding = 0,
},
toolButton_not_hovered = {
background = false,
outline = false,
slices = false,
},
toolButton_hovered = {
tint = { 200, 255, 200 },

View File

@@ -22,9 +22,9 @@ function Event:bind (observer, callback)
end
local eventNames = {
'Display', 'Keyboard', 'Motion', 'Mouse', 'Reshape', 'Enter', 'Leave',
'Press', 'PressStart', 'PressDrag', 'PressMove', 'PressLeave', 'PressEnter',
'PressEnd'
'Reshape', 'Display', 'Keyboard', 'TextInput', 'Motion',
'Enter', 'Leave', 'PressEnter', 'PressLeave',
'PressStart', 'PressEnd', 'PressDrag', 'PressMove', 'Press',
}
local weakKeyMeta = { __mode = 'k' }

View File

@@ -37,6 +37,14 @@ function Input:handleKeyboard (key, x, y)
})
end
function Input:handleTextInput (text, x, y)
local widget = self.layout.focusedWidget or self.layout:getWidgetAt(x, y)
self:bubbleEvent('TextInput', widget, {
target = widget,
text = text, x = x, y = y
})
end
function Input:handleMotion (x, y)
local widget = self.layout:getWidgetAt(x, y)
local previousWidget = self.previousMotionWidget

View File

@@ -131,6 +131,9 @@ function Layout:manageInput (input)
self:hook('keypressed', function (key, isRepeat)
return input:handleKeyboard(key, love.mouse.getX(), love.mouse.getY())
end)
self:hook('textinput', function (text)
return input:handleTextInput(text, love.mouse.getX(), love.mouse.getY())
end)
end
-- event binders

View File

@@ -7,6 +7,7 @@ local Font = require(ROOT .. 'font')
local Renderer = Base:extend()
local imageCache = {}
local sliceCache = {}
function Renderer:loadImage (path)
if not imageCache[path] then
@@ -16,7 +17,72 @@ function Renderer:loadImage (path)
return imageCache[path]
end
function Renderer:renderBackground (widget, window)
function Renderer:loadSlices (path)
local slices = sliceCache[path]
if not slices then
slices = {}
sliceCache[path] = slices
local image = self:loadImage(path)
local iw, ih = image:getWidth(), image:getHeight()
local w, h = math.floor(iw / 3), math.floor(ih / 3)
local Quad = love.graphics.newQuad
slices.image = image
slices.width = w
slices.height = h
slices.topLeft = Quad(0, 0, w, h, iw, ih)
slices.topCenter = Quad(w, 0, w, h, iw, ih)
slices.topRight = Quad(iw - w, 0, w, h, iw, ih)
slices.middleLeft = Quad(0, h, w, h, iw, ih)
slices.middleCenter = Quad(w, h, w, h, iw, ih)
slices.middleRight = Quad(iw - w, h, w, h, iw, ih)
slices.bottomLeft = Quad(0, ih - h, w, h, iw, ih)
slices.bottomCenter = Quad(w, ih - h, w, h, iw, ih)
slices.bottomRight = Quad(iw - w, ih - h, w, h, iw, ih)
end
return slices
end
function Renderer:renderSlices (widget)
local path = widget.slices
if not path then return end
local x1, y1, x2, y2 = widget:getRectangle(true)
local slices = self:loadSlices(path)
local batch = love.graphics.newSpriteBatch(slices.image)
local xScale = ((x2 - x1) - slices.width * 2) / slices.width
local yScale = ((y2 - y1) - slices.height * 2) / slices.height
batch:add(slices.middleCenter, x1 + slices.width, y1 + slices.height, 0,
xScale, yScale)
batch:add(slices.topCenter, x1 + slices.width, y1, 0,
xScale, 1)
batch:add(slices.bottomCenter, x1 + slices.width, y2 - slices.height, 0,
xScale, 1)
batch:add(slices.middleLeft, x1, y1 + slices.height, 0,
1, yScale)
batch:add(slices.middleRight, x2 - slices.width, y1 + slices.height, 0,
1, yScale)
batch:add(slices.topLeft, x1, y1)
batch:add(slices.topRight, x2 - slices.width, y1)
batch:add(slices.bottomLeft, x1, y2 - slices.height)
batch:add(slices.bottomRight, x2 - slices.width, y2 - slices.height)
love.graphics.draw(batch)
end
function Renderer:renderBackground (widget)
if not widget.background then return end
local x1, y1, x2, y2 = widget:getRectangle(true)
@@ -26,7 +92,7 @@ function Renderer:renderBackground (widget, window)
love.graphics.pop()
end
function Renderer:renderOutline (widget, window)
function Renderer:renderOutline (widget)
if not widget.outline then return end
local x1, y1, x2, y2 = widget:getRectangle(true)
@@ -114,7 +180,7 @@ function Renderer:positionText (widget, x1, y1, x2, y2)
return font, x1, y
end
function Renderer:renderIconAndText (widget, window)
function Renderer:renderIconAndText (widget)
local x1, y1, x2, y2 = widget:getRectangle(true, true)
-- if the drawable area has no width or height, don't render
@@ -187,10 +253,10 @@ end
function Renderer:render (widget)
Event.Display:emit(widget, {}, function()
local window = widget.layout.window
self:renderBackground(widget, window)
self:renderOutline(widget, window)
self:renderIconAndText(widget, window)
self:renderBackground(widget)
self:renderOutline(widget)
self:renderSlices(widget)
self:renderIconAndText(widget)
return self:renderChildren(widget)
end)
end

View File

@@ -1,3 +1,5 @@
local RESOURCE = (...):gsub('%.', '/') .. '/'
return function (config)
config = config or {}
@@ -13,24 +15,23 @@ return function (config)
button = {
type = 'panel',
align = 'center middle',
outline = lineColor,
bend = 0.1,
margin = 2,
padding = 6,
slices = RESOURCE .. 'button.png',
minimumWidth = 24,
minimumHeight = 24
},
button_hovered = {
background = white,
outline = highlight,
slices = RESOURCE .. 'button_hovered.png'
},
button_pressed = {
background = highlight,
outline = highlight,
slices = RESOURCE .. 'button_pressed.png',
},
text = {
align = 'left middle',
background = { 255, 255, 255 },
outline = lineColor,
margin = 2,
padding = 2,
slices = RESOURCE .. 'text.png',
padding = 6,
minimumWidth = 24,
minimumHeight = 24
},
sash = {
background = lineColor

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 521 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 B

Binary file not shown.

BIN
luigi/theme/light/text.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 505 B

View File

@@ -84,25 +84,32 @@ function Widget:addChild (data)
return child
end
local function clamp (value, min, max)
return value < min and min or value > max and max or value
end
function Widget:calculateDimension (name)
function clamp(value, min, max)
if value < min then
value = min
elseif value > max then
value = max
end
return value
end
if self[name] then
self.dimensions[name] = clamp(self[name], 0, self.layout.root[name])
end
if self.dimensions[name] then
return self.dimensions[name]
end
local parent = self.parent
if not parent then
return self.layout
local min = (name == 'width') and (self.minimumWidth or 0)
or (self.minimumHeight or 0)
local max = self.layout.root[name]
if self[name] then
self.dimensions[name] = clamp(self[name], min, max)
return self.dimensions[name]
end
local parent = self.parent
if not parent then
self.dimensions[name] = max
return self.dimensions[name]
end
local parentDimension = parent:calculateDimension(name)
parentDimension = parentDimension - (parent.margin or 0) * 2
parentDimension = parentDimension - (parent.padding or 0) * 2
@@ -110,7 +117,8 @@ function Widget:calculateDimension (name)
if (parentFlow == 'y' and name == 'width') or
(parentFlow == 'x' and name == 'height')
then
return parentDimension
self.dimensions[name] = clamp(parentDimension, min, max)
return self.dimensions[name]
end
local claimed = 0
local unsized = 1
@@ -127,7 +135,9 @@ function Widget:calculateDimension (name)
end
end
local size = (parentDimension - claimed) / unsized
self.dimensions[name] = clamp(size, 0, self.layout.root[name])
size = clamp(size, min, max)
self.dimensions[name] = size
return size
end