mirror of
https://github.com/airstruck/luigi.git
synced 2026-01-10 08:18:22 +00:00
clean up rendering, allow configurable themes
This commit is contained in:
@@ -17,8 +17,8 @@ local style = {
|
|||||||
margin = 4,
|
margin = 4,
|
||||||
},
|
},
|
||||||
toolButton_not_hovered = {
|
toolButton_not_hovered = {
|
||||||
outline = false,
|
background = false,
|
||||||
bend = 0,
|
outline = { 200, 200, 200 },
|
||||||
},
|
},
|
||||||
statusbar = {
|
statusbar = {
|
||||||
style = 'panel',
|
style = 'panel',
|
||||||
@@ -28,10 +28,9 @@ local style = {
|
|||||||
style = { 'short', 'panel' },
|
style = { 'short', 'panel' },
|
||||||
align = 'left middle',
|
align = 'left middle',
|
||||||
outline = { 200, 200, 200 },
|
outline = { 200, 200, 200 },
|
||||||
height = 80,
|
height = 120,
|
||||||
padding = 8,
|
padding = 8,
|
||||||
background = { 255, 255, 255 },
|
background = { 255, 255, 255 },
|
||||||
bend = 0.2,
|
|
||||||
icon = 'icon/emblem-system.png',
|
icon = 'icon/emblem-system.png',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -47,8 +46,12 @@ local mainForm = { title = "Test window", id = 'mainWindow', type = 'panel',
|
|||||||
},
|
},
|
||||||
{ flow = 'x',
|
{ flow = 'x',
|
||||||
{ id = 'leftSideBox', width = 200,
|
{ id = 'leftSideBox', width = 200,
|
||||||
{ text = 'Hi, I\'m some centered text. ', style = 'listThing',
|
{ text = 'Hi, I\'m centered middle. ', style = 'listThing',
|
||||||
align = 'middle center' },
|
align = 'middle center' },
|
||||||
|
{ text = 'Hi, I\'m centered bottom. ', style = 'listThing',
|
||||||
|
align = 'bottom center' },
|
||||||
|
{ text = 'Hi, I\'m centered top. ', style = 'listThing',
|
||||||
|
align = 'top center' },
|
||||||
{ text = 'A man, a plan, a canal: Panama!', style = 'listThing' },
|
{ text = 'A man, a plan, a canal: Panama!', style = 'listThing' },
|
||||||
},
|
},
|
||||||
{ type = 'sash', width = 4, },
|
{ type = 'sash', width = 4, },
|
||||||
@@ -71,7 +74,7 @@ local mainForm = { title = "Test window", id = 'mainWindow', type = 'panel',
|
|||||||
local layout = Layout(mainForm)
|
local layout = Layout(mainForm)
|
||||||
|
|
||||||
layout:setStyle(style)
|
layout:setStyle(style)
|
||||||
layout:setTheme(require 'luigi.theme.light')
|
layout:setTheme(require 'luigi.theme.light' { highlight = { 150, 255, 150 } })
|
||||||
|
|
||||||
layout.leftSideBox:addChild {
|
layout.leftSideBox:addChild {
|
||||||
text = 'Alright man this is a great song\nwith a really long title...',
|
text = 'Alright man this is a great song\nwith a really long title...',
|
||||||
|
|||||||
@@ -19,10 +19,16 @@ function Layout:constructor (data)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Layout:setStyle (rules)
|
function Layout:setStyle (rules)
|
||||||
|
if type(rules) == 'function' then
|
||||||
|
rules = rules()
|
||||||
|
end
|
||||||
self.style = Style(rules or {}, 'id', 'style')
|
self.style = Style(rules or {}, 'id', 'style')
|
||||||
end
|
end
|
||||||
|
|
||||||
function Layout:setTheme (rules)
|
function Layout:setTheme (rules)
|
||||||
|
if type(rules) == 'function' then
|
||||||
|
rules = rules()
|
||||||
|
end
|
||||||
self.theme = Style(rules or {}, 'type')
|
self.theme = Style(rules or {}, 'type')
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -6,12 +6,22 @@ local Font = require(ROOT .. 'font')
|
|||||||
|
|
||||||
local Renderer = Base:extend()
|
local Renderer = Base:extend()
|
||||||
|
|
||||||
|
local imageCache = {}
|
||||||
|
|
||||||
|
function Renderer:loadImage (path)
|
||||||
|
if not imageCache[path] then
|
||||||
|
imageCache[path] = love.graphics.newImage(path)
|
||||||
|
end
|
||||||
|
|
||||||
|
return imageCache[path]
|
||||||
|
end
|
||||||
|
|
||||||
function Renderer:renderBackground (widget, window)
|
function Renderer:renderBackground (widget, window)
|
||||||
local bg = widget.background
|
local bg = widget.background
|
||||||
if not bg then return end
|
if not bg then return end
|
||||||
local bend = widget.bend
|
local bend = widget.bend
|
||||||
local x1, y1, x2, y2 = widget:getRectangle(true)
|
local x1, y1, x2, y2 = widget:getRectangle(true)
|
||||||
window:fill(x1, y1, x2, y2, bg, bend)
|
window:fill(x1, y1, x2, y2, bg)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Renderer:renderOutline (widget, window)
|
function Renderer:renderOutline (widget, window)
|
||||||
@@ -20,111 +30,147 @@ function Renderer:renderOutline (widget, window)
|
|||||||
window:outline(x1, y1, x2, y2, widget.outline)
|
window:outline(x1, y1, x2, y2, widget.outline)
|
||||||
end
|
end
|
||||||
|
|
||||||
local imageCache = {}
|
-- returns icon coordinates and rectangle with remaining space
|
||||||
|
function Renderer:positionIcon (widget, x1, y1, x2, y2)
|
||||||
local function loadImage (path)
|
if not widget.icon then
|
||||||
if not imageCache[path] then
|
return nil, nil, x1, y1, x2, y2
|
||||||
imageCache[path] = love.graphics.newImage(path)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return imageCache[path]
|
local icon = self:loadImage(widget.icon)
|
||||||
end
|
local iconWidth, iconHeight = icon:getWidth(), icon:getHeight()
|
||||||
|
|
||||||
-- TODO: this function is a monster, fix it somehow
|
|
||||||
function Renderer:renderIconAndText (widget, window)
|
|
||||||
local x1, y1, x2, y2 = widget:getRectangle(true, true)
|
|
||||||
local icon = widget.icon and loadImage(widget.icon)
|
|
||||||
local align = widget.align or ''
|
local align = widget.align or ''
|
||||||
local padding = widget.padding or 0
|
local padding = widget.padding or 0
|
||||||
local text = widget.text
|
local x, y
|
||||||
local x, y, iconWidth, iconHeight
|
|
||||||
|
|
||||||
if icon then
|
-- horizontal alignment
|
||||||
iconWidth, iconHeight = icon:getWidth(), icon:getHeight()
|
if align:find('right') then
|
||||||
-- horizontal alignment
|
x = x2 - iconWidth
|
||||||
if align:find('right') then
|
x2 = x2 - iconWidth - padding
|
||||||
x = x2 - iconWidth
|
elseif align:find('center') then
|
||||||
elseif align:find('center') then
|
x = x1 + (x2 - x1) / 2 - iconWidth / 2
|
||||||
x = x1 + (x2 - x1) / 2 - iconWidth / 2
|
else -- if align:find('left') then
|
||||||
else -- if align:find('left') then
|
x = x1
|
||||||
x = x1
|
x1 = x1 + iconWidth + padding
|
||||||
end
|
|
||||||
|
|
||||||
-- vertical alignment
|
|
||||||
if align:find('bottom') then
|
|
||||||
y = y2 - iconHeight
|
|
||||||
elseif align:find('middle') then
|
|
||||||
y = y1 + (y2 - y1) / 2 - iconHeight / 2
|
|
||||||
else -- if align:find('top') then
|
|
||||||
y = y1
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
if text and align:find('center') then
|
|
||||||
if align:find('bottom') then
|
|
||||||
y = y - textHeight - padding
|
|
||||||
elseif align:find('middle') then
|
|
||||||
y = y - (textHeight + padding) / 2
|
|
||||||
end
|
|
||||||
end
|
|
||||||
--]]
|
|
||||||
|
|
||||||
love.graphics.draw(icon, x, y)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- render text
|
-- vertical alignment
|
||||||
if not text then return end
|
if align:find('bottom') then
|
||||||
|
y = y2 - iconHeight
|
||||||
|
elseif align:find('middle') then
|
||||||
|
y = y1 + (y2 - y1) / 2 - iconHeight / 2
|
||||||
|
else -- if align:find('top') then
|
||||||
|
y = y1
|
||||||
|
end
|
||||||
|
|
||||||
|
return x, y, x1, y1, x2, y2
|
||||||
|
end
|
||||||
|
|
||||||
|
-- returns text coordinates
|
||||||
|
function Renderer:positionText (widget, x1, y1, x2, y2)
|
||||||
|
if not widget.text then
|
||||||
|
return nil, nil, x1, y1, x2, y2
|
||||||
|
end
|
||||||
|
|
||||||
if not widget.fontData then
|
if not widget.fontData then
|
||||||
widget.fontData = Font(widget.font, widget.fontSize, widget.textColor)
|
widget.fontData = Font(widget.font, widget.fontSize, widget.textColor)
|
||||||
end
|
end
|
||||||
|
|
||||||
local font = widget.fontData
|
local font = widget.fontData
|
||||||
|
local align = widget.align or ''
|
||||||
if icon then
|
local padding = widget.padding or 0
|
||||||
if align:find('center') then
|
|
||||||
-- y1 = y1 + iconHeight + padding
|
|
||||||
elseif align:find('right') then
|
|
||||||
x2 = x2 - iconWidth - padding
|
|
||||||
else
|
|
||||||
x1 = x1 + iconWidth + padding
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
font:setWidth(x2 - x1)
|
font:setWidth(x2 - x1)
|
||||||
|
|
||||||
|
-- horizontal alignment
|
||||||
if align:find('right') then
|
if align:find('right') then
|
||||||
font:setAlignment('right')
|
font:setAlignment('right')
|
||||||
elseif align:find('center') then
|
elseif align:find('center') then
|
||||||
font:setAlignment('center')
|
font:setAlignment('center')
|
||||||
elseif align:find('justify') then
|
elseif align:find('justify') then
|
||||||
font:setAlignment('justify')
|
font:setAlignment('justify')
|
||||||
else -- if align:find('left') then
|
else -- if align:find('left') then
|
||||||
font:setAlignment('left')
|
font:setAlignment('left')
|
||||||
end
|
end
|
||||||
|
|
||||||
local textHeight = font:getWrappedHeight(text)
|
local y
|
||||||
|
|
||||||
local x, y
|
|
||||||
|
|
||||||
-- vertical alignment
|
-- vertical alignment
|
||||||
if align:find('bottom') then
|
if align:find('bottom') then
|
||||||
|
local textHeight = font:getWrappedHeight(widget.text)
|
||||||
y = y2 - textHeight
|
y = y2 - textHeight
|
||||||
elseif align:find('middle') then
|
elseif align:find('middle') then
|
||||||
|
local textHeight = font:getWrappedHeight(widget.text)
|
||||||
y = y2 - (y2 - y1) / 2 - textHeight / 2
|
y = y2 - (y2 - y1) / 2 - textHeight / 2
|
||||||
if icon and align:find('center') then
|
|
||||||
y = y1 + (iconHeight + padding) / 2
|
|
||||||
end
|
|
||||||
else -- if align:find('top') then
|
else -- if align:find('top') then
|
||||||
y = y1
|
y = y1
|
||||||
if icon and align:find('center') then
|
end
|
||||||
y = y1 + iconHeight + padding
|
|
||||||
|
return font, x1, y
|
||||||
|
end
|
||||||
|
|
||||||
|
function Renderer:renderIconAndText (widget, window)
|
||||||
|
local x1, y1, x2, y2 = widget:getRectangle(true, true)
|
||||||
|
|
||||||
|
-- if the drawable area has no width or height, don't render
|
||||||
|
if x2 <= x1 or y2 <= y1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.push('all')
|
||||||
|
|
||||||
|
love.graphics.setScissor(x1, y1, x2 - x1, y2 - y1)
|
||||||
|
|
||||||
|
local iconX, iconY, textX, textY, font
|
||||||
|
|
||||||
|
-- calculate position for icon and text based on alignment and padding
|
||||||
|
iconX, iconY, x1, y1, x2, y2 = self:positionIcon(widget, x1, y1, x2, y2)
|
||||||
|
font, textX, textY = self:positionText(widget, x1, y1, x2, y2)
|
||||||
|
|
||||||
|
local icon = widget.icon and self:loadImage(widget.icon)
|
||||||
|
local text = widget.text
|
||||||
|
local align = widget.align or ''
|
||||||
|
local padding = widget.padding or 0
|
||||||
|
|
||||||
|
-- if aligned center, icon displays above the text
|
||||||
|
-- reposition icon and text for proper vertical alignment
|
||||||
|
if icon and text and align:find('center') then
|
||||||
|
local iconHeight = icon:getHeight()
|
||||||
|
local textHeight = font:getWrappedHeight(text)
|
||||||
|
local contentHeight = textHeight + padding + iconHeight
|
||||||
|
local offset = ((y2 - y1) - contentHeight) / 2
|
||||||
|
|
||||||
|
if align:find('middle') then
|
||||||
|
iconY = y1 + offset
|
||||||
|
textY = y1 + offset + padding + iconHeight
|
||||||
|
elseif align:find('top') then
|
||||||
|
iconY = y1
|
||||||
|
textY = y1 + padding + iconHeight
|
||||||
|
else -- if align:find('bottom')
|
||||||
|
textY = y2 - textHeight
|
||||||
|
iconY = textY - padding - iconHeight
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
x = math.floor(x1)
|
-- draw the icon
|
||||||
y = math.floor(y)
|
if icon then
|
||||||
|
iconX, iconY = math.floor(iconX), math.floor(iconY)
|
||||||
|
if widget.tint then
|
||||||
|
love.graphics.setColor(widget.tint)
|
||||||
|
end
|
||||||
|
love.graphics.draw(icon, iconX, iconY)
|
||||||
|
end
|
||||||
|
|
||||||
window:write(x, y, x1, y1, x2, y2, text, font)
|
-- draw the text
|
||||||
|
if text then
|
||||||
|
textX, textY = math.floor(textX), math.floor(textY)
|
||||||
|
love.graphics.setFont(font.font)
|
||||||
|
love.graphics.setColor(font.color)
|
||||||
|
|
||||||
|
local layout = font.layout
|
||||||
|
love.graphics.printf(text, textX, textY, x2 - x1, layout.align)
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.pop()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Renderer:renderChildren (widget)
|
function Renderer:renderChildren (widget)
|
||||||
|
|||||||
@@ -1,39 +1,53 @@
|
|||||||
local backColor = { 240, 240, 240 }
|
return function (config)
|
||||||
local lineColor = { 220, 220, 220 }
|
config = config or {}
|
||||||
local highlightColor = { 220, 220, 240 }
|
|
||||||
|
|
||||||
return {
|
local backColor = config.backColor or { 240, 240, 240 }
|
||||||
panel = {
|
local lineColor = config.lineColor or { 220, 220, 220 }
|
||||||
background = backColor,
|
local white = config.white or { 255, 255, 255 }
|
||||||
padding = 4,
|
local highlight = config.highlight or { 180, 180, 255 }
|
||||||
},
|
|
||||||
button = {
|
return {
|
||||||
type = 'panel',
|
panel = {
|
||||||
align = 'center middle',
|
background = backColor,
|
||||||
outline = lineColor,
|
padding = 4,
|
||||||
bend = 0.1,
|
},
|
||||||
margin = 4,
|
button = {
|
||||||
},
|
type = 'panel',
|
||||||
button_hovered = {
|
align = 'center middle',
|
||||||
bend = 0.2,
|
outline = lineColor,
|
||||||
},
|
bend = 0.1,
|
||||||
button_pressed = {
|
margin = 4,
|
||||||
bend = -0.1,
|
},
|
||||||
},
|
button_hovered = {
|
||||||
text = {
|
background = white,
|
||||||
align = 'left middle',
|
outline = highlight,
|
||||||
background = { 255, 255, 255 },
|
},
|
||||||
outline = lineColor,
|
button_pressed = {
|
||||||
bend = -0.1,
|
background = highlight,
|
||||||
margin = 4,
|
outline = highlight,
|
||||||
padding = 4,
|
},
|
||||||
},
|
text = {
|
||||||
sash = {
|
align = 'left middle',
|
||||||
background = highlightColor
|
background = { 255, 255, 255 },
|
||||||
},
|
outline = lineColor,
|
||||||
slider = {
|
bend = -0.1,
|
||||||
type = 'panel',
|
margin = 4,
|
||||||
outline = lineColor,
|
padding = 4,
|
||||||
bend = 0.1,
|
},
|
||||||
},
|
sash = {
|
||||||
}
|
background = lineColor
|
||||||
|
},
|
||||||
|
sash_hovered = {
|
||||||
|
background = highlight
|
||||||
|
},
|
||||||
|
slider = {
|
||||||
|
type = 'panel',
|
||||||
|
outline = lineColor,
|
||||||
|
background = white,
|
||||||
|
},
|
||||||
|
slider_hovered = {
|
||||||
|
outline = highlight,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
end
|
||||||
|
|||||||
@@ -20,7 +20,6 @@ function Slider:constructor(layout, data)
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
self:onDisplay(function(event)
|
self:onDisplay(function(event)
|
||||||
-- event:yield()
|
|
||||||
local x1, y1, x2, y2 = self:getRectangle(true, true)
|
local x1, y1, x2, y2 = self:getRectangle(true, true)
|
||||||
local padding = self.padding or 0
|
local padding = self.padding or 0
|
||||||
self.layout.window:fill(
|
self.layout.window:fill(
|
||||||
@@ -28,14 +27,14 @@ function Slider:constructor(layout, data)
|
|||||||
y1 + (y2 - y1) / 2 - padding / 2,
|
y1 + (y2 - y1) / 2 - padding / 2,
|
||||||
x2,
|
x2,
|
||||||
y1 + (y2 - y1) / 2 + padding / 2,
|
y1 + (y2 - y1) / 2 + padding / 2,
|
||||||
self.background, -(self.bend or 0)
|
self.outline
|
||||||
)
|
)
|
||||||
self.layout.window:fill(
|
self.layout.window:fill(
|
||||||
x1 + position * (x2 - x1) - padding,
|
x1 + position * (x2 - x1) - padding,
|
||||||
y1 + padding,
|
y1 + padding,
|
||||||
x1 + position * (x2 - x1) + padding,
|
x1 + position * (x2 - x1) + padding,
|
||||||
y2 - padding,
|
y2 - padding,
|
||||||
self.background, self.bend
|
self.background
|
||||||
)
|
)
|
||||||
self.layout.window:outline(
|
self.layout.window:outline(
|
||||||
x1 + position * (x2 - x1) - padding,
|
x1 + position * (x2 - x1) - padding,
|
||||||
|
|||||||
@@ -75,41 +75,28 @@ function Window:hide ()
|
|||||||
self:unhook()
|
self:unhook()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function setColor (color)
|
|
||||||
love.graphics.setColor(color)
|
|
||||||
end
|
|
||||||
|
|
||||||
function Window:fill (x1, y1, x2, y2, color)
|
function Window:fill (x1, y1, x2, y2, color)
|
||||||
setColor(color)
|
love.graphics.push('all')
|
||||||
|
love.graphics.setColor(color)
|
||||||
love.graphics.rectangle('fill', x1, y1, x2 - x1, y2 - y1)
|
love.graphics.rectangle('fill', x1, y1, x2 - x1, y2 - y1)
|
||||||
|
love.graphics.pop()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Window:outline (x1, y1, x2, y2, color)
|
function Window:outline (x1, y1, x2, y2, color)
|
||||||
setColor(color)
|
love.graphics.push('all')
|
||||||
|
love.graphics.setColor(color)
|
||||||
love.graphics.rectangle('line', x1, y1, x2 - x1, y2 - y1)
|
love.graphics.rectangle('line', x1, y1, x2 - x1, y2 - y1)
|
||||||
|
love.graphics.pop()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Window:write (x, y, x1, y1, x2, y2, text, font)
|
function Window:write (x, y, x1, y1, x2, y2, text, font)
|
||||||
|
|
||||||
local width, height = x2 - x1, y2 - y1
|
|
||||||
|
|
||||||
if width < 1 or height < 1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local sx, sy, sw, sh = love.graphics.getScissor()
|
|
||||||
|
|
||||||
love.graphics.setScissor(x1, y1, width, height)
|
|
||||||
local oldFont = love.graphics.getFont()
|
|
||||||
love.graphics.setFont(font.font)
|
|
||||||
|
|
||||||
setColor(font.color)
|
|
||||||
|
|
||||||
local layout = font.layout
|
local layout = font.layout
|
||||||
love.graphics.printf(text, x, y, layout.width or width, layout.align)
|
|
||||||
|
|
||||||
love.graphics.setScissor(sx, sy, sw, sh)
|
love.graphics.push('all')
|
||||||
love.graphics.setFont(oldFont)
|
love.graphics.setFont(font.font)
|
||||||
|
love.graphics.setColor(font.color)
|
||||||
|
love.graphics.printf(text, x, y, layout.width or x2 - x1, layout.align)
|
||||||
|
love.graphics.pop()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Window:update (reshape)
|
function Window:update (reshape)
|
||||||
|
|||||||
Reference in New Issue
Block a user