Skip to content

Instantly share code, notes, and snippets.

@art-solopov
Created July 14, 2020 21:39
Show Gist options
  • Save art-solopov/e1609143546d3b42467bed9e096ad941 to your computer and use it in GitHub Desktop.
Save art-solopov/e1609143546d3b42467bed9e096ad941 to your computer and use it in GitHub Desktop.
Basics of an UI drawing library
class = require('30log')
inspect = require('inspect')
local ui_draw = {}
local TILE_POSITIONS = {
left = 0, mid = 1, right = -1,
top = 0, mid = 1, bot = -1
}
local UiElement = class(
'UiElement',
{
tileSize = 16, tileStyles = {},
tilePositions = { {'left', 'mid', 'right'}, {'top', 'mid', 'bot'} }
}
)
function getCoord(pos, origin, rightmost, tileSize)
local offset = TILE_POSITIONS[pos]
local coord = offset * tileSize
if offset < 0 then coord = rightmost + coord
else coord = origin + coord end
return coord
end
function UiElement:prepareTiles()
self.tiles = {}
for styleName, coords in pairs(self.tileStyles) do
local originX, originY = coords[1][1], coords[1][2]
local brX, brY = coords[2][1], coords[2][2]
for _i, xPos in ipairs(self.tilePositions[1]) do
for _j, yPos in ipairs(self.tilePositions[2]) do
local tileName = styleName .. "-" .. xPos .. "-" .. yPos
local tileX = getCoord(xPos, originX, brX, self.tileSize)
local tileY = getCoord(yPos, originY, brY, self.tileSize)
print(tileName, tileX, tileY)
local tile = love.graphics.newQuad(
tileX, tileY,
self.tileSize, self.tileSize,
self.texture:getDimensions()
)
self.tiles[tileName] = tile
end
end
end
end
function UiElement:isHover(x, y)
return x > self.x and x < self.x + self.width and
y > self.y and y < self.y + self.height
end
function UiElement:style()
return "default"
end
function UiElement:draw()
-- Override in subclasses
end
local Button = UiElement:extend("Button", {
isPressed = false,
fg = {1, 1, 1},
tileStyles = {
default = { { 0, 0 }, { 190, 48 } },
pressed = { { 0, 49 }, { 190, 94 } }
}
})
function Button:draw()
local xTiles = self.width / self.tileSize
local yTiles = self.height / self.tileSize
local style = self:style()
for i=1,xTiles do
local xtName = ""
if i == 1 then xtName = "left"
elseif i == xTiles then xtName = "right"
else xtName = "mid"
end
for j=1,yTiles do
local ytName = ""
if j == 1 then ytName = "top"
elseif j == yTiles then ytName = "bot"
else ytName = "mid"
end
local tileName = style .. "-" .. xtName .. "-" .. ytName
local tile = self.tiles[tileName]
love.graphics.draw(self.texture, self.tiles[tileName],
self.x + (i - 1) * self.tileSize,
self.y + (j - 1) * self.tileSize)
end
end
love.graphics.setColor(self.fg)
love.graphics.printf(self.label, self.x,
self.y + 0.5 * self.height - 10,
self.width, "center")
end
function Button:onMousePress()
self.isPressed = true
end
function Button:onMouseRelease()
self.isPressed = false
end
function Button:style()
if self.isPressed then return "pressed"
else return self.super:style()
end
end
local btnPressMe = Button()
btnPressMe.x = 600
btnPressMe.y = 200
btnPressMe.width = 160
btnPressMe.height = 48
btnPressMe.label = "Press Me"
btnPressMe.onClick = function() print("Button pressed!") end
local btnQuit = Button()
btnQuit.x = 600
btnQuit.y = 400
btnQuit.width = 160
btnQuit.height = 48
btnQuit.fg = {1, 1, 1}
btnQuit.label = "Quit"
btnQuit.onClick = function() love.event.quit() end
ui_draw.ui = { btnQuit, btnPressMe }
function ui_draw:prepare()
self.canvas = love.graphics.newCanvas()
UiElement.texture = love.graphics.newImage("assets/blueSheet.png")
Button:prepareTiles()
end
function ui_draw:draw_ui()
-- Button test
local i = 0
for name, quad in pairs(Button.tiles) do
y = 50 + i * (Button.tileSize + 3)
love.graphics.setColor(1, 1, 1)
love.graphics.draw(Button.texture, quad, 10, y)
love.graphics.setColor(0, 0, 0)
love.graphics.print(name, 30, y)
i = i + 1
end
love.graphics.setColor(1, 1, 1)
love.graphics.setCanvas(self.canvas)
for _i, element in ipairs(ui_draw.ui) do
element:draw()
end
love.graphics.setCanvas()
love.graphics.draw(self.canvas)
end
function ui_draw:processMousePressed(x, y, button, presses)
for _i, element in ipairs(ui_draw.ui) do
if element:isHover(x, y) then
if button == 1 and element.onMousePress then element:onMousePress() end
break
end
end
end
function ui_draw:processMouseRelease(x, y, button, presses)
for _i, element in ipairs(ui_draw.ui) do
if element:isHover(x, y) then
if button == 1 and element.onMouseRelease then element:onMouseRelease() end
if button == 1 and element.onClick then element:onClick() end
break
end
end
end
function ui_draw:processMouseMove(x, y)
for _i, element in ipairs(self.ui) do
if element:isHover(x, y) then self.currentFocus = element end
break
end
end
return ui_draw
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment