mirror of
https://github.com/airstruck/luigi.git
synced 2025-11-18 12:25:06 +00:00
9-slice image support
This commit is contained in:
@@ -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 },
|
||||
|
||||
@@ -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' }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
BIN
luigi/theme/light/button.png
Normal file
BIN
luigi/theme/light/button.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 491 B |
BIN
luigi/theme/light/button_hovered.png
Normal file
BIN
luigi/theme/light/button_hovered.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 521 B |
BIN
luigi/theme/light/button_pressed.png
Normal file
BIN
luigi/theme/light/button_pressed.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 534 B |
BIN
luigi/theme/light/light_theme.svgz
Normal file
BIN
luigi/theme/light/light_theme.svgz
Normal file
Binary file not shown.
BIN
luigi/theme/light/text.png
Normal file
BIN
luigi/theme/light/text.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 505 B |
@@ -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
|
||||
|
||||
|
||||
Reference in New Issue
Block a user