add dark theme

This commit is contained in:
airstruck
2015-12-05 03:53:47 -05:00
parent f03b5c7bd4
commit a2fb4e58c1
38 changed files with 279 additions and 65 deletions

View File

@@ -0,0 +1,12 @@
return { style = 'dialog',
{ style = 'dialogHead', text = 'About LUIGI' },
{ style = 'dialogBody', align = 'left middle', padding = 24, icon = 'logo.png', text = [[
Lovely User Interfaces for Game Inventors
Copyright (c) 2015 airstruck
]] },
{ style = 'dialogFoot',
{}, -- spacer
{ style = 'dialogButton', id = 'closeButton', text = 'Close' }
}
}

View File

@@ -34,7 +34,7 @@ return { id = 'mainWindow', type = 'panel',
icon = 'icon/32px/Harddrive.png' },
},
{ flow = 'x',
{ id = 'leftSideBox', width = 200, minwidth = 64, scroll = true,
{ id = 'leftSideBox', width = 200, minwidth = 64, scroll = true, type = 'panel',
{ 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',
@@ -44,7 +44,7 @@ return { id = 'mainWindow', type = 'panel',
{ text = 'A man, a plan, a canal: Panama!', style = 'listThing' },
},
{ type = 'sash', width = 4, },
{ id = 'mainCanvas' },
{ type = 'panel', id = 'mainCanvas' },
{ type = 'sash', width = 4, },
{ type = 'panel', id = 'rightSideBox', width = 200, minwidth = 64,
{ type = 'panel', text = 'A slider', align = 'bottom', height = 24, padding = 4 },
@@ -61,7 +61,7 @@ return { id = 'mainWindow', type = 'panel',
{ type = 'check', text = 'Check it out', height = 32, padding = 4, id = 'checkBox', },
{ type = 'panel', text = 'Some radio widgets', align = 'bottom', height = 24, padding = 4 },
{ type = 'radio', text = 'One fish', height = 32, padding = 4, },
{ type = 'radio', text = 'Two fish', height = 32, padding = 4, },
{ type = 'radio', text = 'Two fish', height = 32, padding = 4, wrap = true },
{ type = 'radio', text = 'Red fish', height = 32, padding = 4, },
{ type = 'radio', text = 'Blue fish', height = 32, padding = 4, },
},

BIN
example/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

View File

@@ -19,7 +19,7 @@ end)
layout:onMove(function (event)
local w = event.target
layout.statusbar.text = (tostring(w.type)) ..
layout.statusbar.text = (tostring(w.type)) .. ' ' ..
(w.id or '(unnamed)') .. ' ' ..
w:getX() .. ', ' .. w:getY() .. ' | ' ..
w:getWidth() .. 'x' .. w:getHeight()
@@ -30,28 +30,10 @@ layout.newButton:onMove(function (event)
return false
end)
local foo = Layout { float = true, height = 100,
text = 'hello', align = 'center middle', background = {255,0,0}
}
foo:onReshape(function (event)
foo:hide()
end)
layout.newButton:onPress(function (event)
print('creating a new thing!')
end)
layout.aButton:onPress(function (event)
layout.aButton.font = nil
layout.aButton.width = layout.aButton.width + 10
local w = layout.aButton:getWidth()
foo.root.width = w * 2
foo.root.left = layout.aButton:getX() - w
foo.root.top = layout.aButton:getY() - foo.root.height
foo:show()
end)
layout.mainCanvas.font = 'font/DejaVuSansMono.ttf'
layout.mainCanvas.text = [[
@@ -78,12 +60,6 @@ layout.mainCanvas.align = 'top'
layout.mainCanvas.wrap = true
local Backend = require 'luigi.backend'
layout.menuQuit:onPress(function (event) Backend.quit() end)
layout.themeLight:onPress(function (event) Backend.quit() end)
-- license dialog
local licenseDialog = Layout(require 'layout.license')
@@ -98,9 +74,43 @@ layout.license:onPress(function()
licenseDialog:show()
end)
-- about dialog
local aboutDialog = Layout(require 'layout.about')
aboutDialog:setStyle(style)
aboutDialog.closeButton:onPress(function()
aboutDialog:hide()
end)
layout.about:onPress(function()
aboutDialog:show()
end)
-- menu/view/theme
layout.themeLight:onPress(function (event)
local light = require 'luigi.theme.light'
layout:setTheme(light)
licenseDialog:setTheme(light)
aboutDialog:setTheme(light)
end)
layout.themeDark:onPress(function (event)
local dark = require 'luigi.theme.dark'
layout:setTheme(dark)
licenseDialog:setTheme(dark)
aboutDialog:setTheme(dark)
end)
-- menu/file/quit
-- uses Backend for compat with love or ffisdl
local Backend = require 'luigi.backend'
layout.menuQuit:onPress(function (event) Backend.quit() end)
-- show the main layout
layout:show()
Backend.run() -- only needed when using ffisdl backend
-- only needed when using ffisdl backend
Backend.run()

View File

@@ -3,7 +3,7 @@ return {
height = 48,
},
toolbar = {
style = { 'short' },
style = 'short',
},
toolButton = {
align = 'center middle',
@@ -16,19 +16,18 @@ return {
slices = false,
},
statusbar = {
style = 'panel',
align = 'left middle',
},
listThing = {
style = { 'short', 'panel' },
style = 'short',
align = 'left middle',
outline = { 200, 200, 200 },
height = 120,
padding = 8,
background = { 255, 255, 255 },
icon = 'icon/32px/Box.png',
wrap = true,
},
-- dialog styles
dialog = {
type = 'submenu',
width = 600,
@@ -43,7 +42,7 @@ return {
},
dialogBody = {
wrap = true,
margin = 4,
padding = 4,
font = 'font/DejaVuSansMono.ttf',
},
dialogFoot = {

View File

@@ -13,14 +13,13 @@ local Text = require((...) .. '.text')
local IntOut = ffi.typeof 'int[1]'
-- create window and renderer
sdl.setHint(sdl.HINT_VIDEO_ALLOW_SCREENSAVER, '1')
local window = sdl.createWindow('', 0, 0, 800, 600,
sdl.WINDOW_SHOWN + sdl.WINDOW_RESIZABLE)
if window == nil then
io.stderr:write(ffi.string(sdl.getError()))
sdl.quit()
os.exit(1)
error(ffi.string(sdl.getError()))
end
ffi.gc(window, sdl.destroyWindow)
@@ -29,9 +28,7 @@ local renderer = sdl.createRenderer(window, -1,
sdl.RENDERER_ACCELERATED + sdl.RENDERER_PRESENTVSYNC)
if renderer == nil then
io.stderr:write(ffi.string(sdl.getError()))
sdl.quit()
os.exit(1)
error(ffi.string(sdl.getError()))
end
ffi.gc(renderer, sdl.destroyRenderer)
@@ -151,11 +148,13 @@ end
local currentFont = Font()
local lastColor
-- print( text, x, y, r, sx, sy, ox, oy, kx, ky )
Backend.print = function (text, x, y)
if not text or text == '' then return end
local font = currentFont.sdlFont
local color = sdl.Color(currentFont.color or { 0, 0, 0, 255 })
local color = sdl.Color(lastColor or { 0, 0, 0, 255 })
local write = Font.SDL2_ttf.TTF_RenderUTF8_Blended
local surface = write(font, text, color)
@@ -236,8 +235,6 @@ Backend.quit = function ()
os.exit()
end
local lastColor
Backend.setColor = function (color)
lastColor = color
sdl.setRenderDrawColor(renderer,

View File

@@ -210,9 +210,7 @@ function Font:constructor (path, size)
local font = SDL2_ttf.TTF_OpenFont(path, size)
if font == nil then
io.stderr:write(ffi.string(sdl.getError()))
sdl.quit()
os.exit(1)
error(ffi.string(sdl.getError()))
end
fontCache[key] = font

View File

@@ -17,9 +17,19 @@ function Image:constructor (renderer, path)
self.sdlSurface = ffi.gc(
SDL2_image.IMG_Load(path),
sdl.freeSurface)
if self.sdlSurface == nil then
error(ffi.string(sdl.getError()))
end
self.sdlTexture = ffi.gc(
sdl.createTextureFromSurface(renderer, self.sdlSurface),
sdl.destroyTexture)
if self.sdlTexture == nil then
error(ffi.string(sdl.getError()))
end
self.width = self.sdlSurface.w
self.height = self.sdlSurface.h
end

View File

@@ -60,8 +60,7 @@ sdl.atomic_t = ffi.typeof 'SDL_atomic_t'
sdl.version = ffi.typeof 'SDL_version'
if sdl.init(sdl.INIT_VIDEO) ~= 0 then
io.stderr:write(ffi.string(sdl.getError()))
os.exit(1)
error(ffi.string(sdl.getError()))
end
return sdl

View File

@@ -38,14 +38,19 @@ local function renderMulti (self, font, text, color, align, limit)
local r, g, b, a
--[[
if sdl.BYTEORDER == sdl.BIG_ENDIAN then
r, g, b, a = 0xFF000000, 0x00FF0000, 0x0000FF00, 0x000000FF
else
r, g, b, a = 0x000000FF, 0x0000FF00, 0x00FF0000, 0xFF000000
end
--]]
-- values from SDL_ttf.c
r, g, b, a = 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000
local surface = ffi.gc(
sdl.createRGBSurface(0, limit, height, 32, r, g, b, a),
sdl.createRGBSurface(sdl.SWSURFACE, limit, height, 32, r, g, b, a),
sdl.freeSurface)
self.sdlSurface = surface
@@ -55,6 +60,8 @@ local function renderMulti (self, font, text, color, align, limit)
ttf.TTF_RenderUTF8_Blended(font.sdlFont, text, color),
sdl.freeSurface)
if lineSurface ~= nil then
sdl.setSurfaceBlendMode(lineSurface, sdl.BLENDMODE_NONE)
local w, h = lineSurface.w, lineSurface.h
local top = (index - 1) * lineHeight

157
luigi/theme/dark.lua Normal file
View File

@@ -0,0 +1,157 @@
local RESOURCE = (...):gsub('%.', '/') .. '/'
return function (config)
config = config or {}
local backColor = config.backColor or { 40, 40, 40 }
local lineColor = config.lineColor or { 60, 60, 60 }
local textColor = config.textColor or { 240, 240, 240 }
local highlight = config.highlight or { 0xFF, 0x66, 0x00 }
return {
button = {
align = 'center middle',
padding = 6,
slices = RESOURCE .. 'button.png',
minwidth = 24,
minheight = 24,
canFocus = true,
color = textColor,
},
button_hovered = {
slices = RESOURCE .. 'button_hovered.png'
},
button_focused = {
slices = RESOURCE .. 'button_focused.png',
},
button_pressed = {
slices = RESOURCE .. 'button_pressed.png',
},
['stepper.left'] = {
type = 'button',
icon = RESOURCE .. 'triangle_left.png',
},
['stepper.right'] = {
type = 'button',
icon = RESOURCE .. 'triangle_right.png',
},
menu = {
height = 24,
},
['menu.item'] = {
padding = 4,
align = 'left middle',
color = { 0, 0, 0 },
color = textColor,
},
['menu.item_active'] = {
background = highlight,
},
['menu.expander'] = {
icon = RESOURCE .. 'triangle_right.png',
},
submenu = {
padding = 10,
margin = -10,
slices = RESOURCE .. 'submenu.png',
color = textColor,
},
sash = {
background = lineColor
},
sash_hovered = {
background = highlight
},
slider = {
slices = RESOURCE .. 'button_pressed.png',
padding = 0,
minwidth = 24,
minheight = 24
},
panel = {
background = backColor,
color = textColor,
},
progress = {
slices = RESOURCE .. 'button_pressed.png',
padding = 0,
minwidth = 24,
minheight = 24
},
['progress.bar'] = {
slices = RESOURCE .. 'progress.png',
padding = 0,
minwidth = 12,
},
slider_hovered = {
},
stepper = {
slices = RESOURCE .. 'button_pressed.png',
},
['stepper.item'] = {
align = 'center middle',
color = textColor,
},
text = {
align = 'left middle',
slices = RESOURCE .. 'text.png',
padding = 6,
minwidth = 24,
minheight = 24,
canFocus = true,
cursor = 'ibeam',
highlight = highlight,
color = textColor,
},
text_focused = {
slices = RESOURCE .. 'text_focused.png',
},
check = {
canFocus = true,
color = textColor,
},
['check.unchecked'] = {
icon = RESOURCE .. 'check_unchecked.png',
},
['check.checked'] = {
icon = RESOURCE .. 'check_checked.png',
},
['check.unchecked_pressed'] = {
icon = RESOURCE .. 'check_unchecked_pressed.png',
},
['check.checked_pressed'] = {
icon = RESOURCE .. 'check_checked_pressed.png',
},
['check.unchecked_focused'] = {
icon = RESOURCE .. 'check_unchecked_focused.png',
},
['check.checked_focused'] = {
icon = RESOURCE .. 'check_checked_focused.png',
},
radio = {
canFocus = true,
color = textColor,
},
['radio.unchecked'] = {
icon = RESOURCE .. 'radio_unchecked.png',
},
['radio.checked'] = {
icon = RESOURCE .. 'radio_checked.png',
},
['radio.unchecked_pressed'] = {
icon = RESOURCE .. 'radio_unchecked_pressed.png',
},
['radio.checked_pressed'] = {
icon = RESOURCE .. 'radio_checked_pressed.png',
},
['radio.unchecked_focused'] = {
icon = RESOURCE .. 'radio_unchecked_focused.png',
},
['radio.checked_focused'] = {
icon = RESOURCE .. 'radio_checked_focused.png',
},
}
end

BIN
luigi/theme/dark/button.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 561 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 490 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 511 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 271 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 297 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 688 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 595 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 491 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 552 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 451 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 944 B

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 484 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 538 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 786 B

After

Width:  |  Height:  |  Size: 846 B

View File

@@ -45,10 +45,24 @@ function Widget.register (name, decorator)
Widget.typeDecorators[name] = decorator
end
local function maybeCall (something, ...)
if type(something) == 'function' then
return something(...)
end
return something
end
-- look for properties in attributes, Widget, style, and theme
local function metaIndex (self, property)
local value = self.attributes[property]
if value ~= nil then return value end
if value ~= nil then return maybeCall(value, self) end
-- cascading attributes
-- TODO: custom accessors in attribute module?
if property == 'color' or property == 'font' or property == 'size' then
local value = self.parent and self.parent[property]
if value ~= nil then return maybeCall(value, self) end
end
local value = Widget[property]
if value ~= nil then return value end
@@ -56,10 +70,10 @@ local function metaIndex (self, property)
local layout = self.layout
local style = layout:getStyle()
value = style and style:getProperty(self, property)
if value ~= nil and value ~= 'defer' then return value end
if value ~= nil and value ~= 'defer' then return maybeCall(value, self) end
local theme = layout:getTheme()
return theme and theme:getProperty(self, property)
return theme and maybeCall(theme:getProperty(self, property), self)
end
-- setting attributes triggers special behavior

View File

@@ -170,8 +170,16 @@ local function initialize (self)
self.flow = 'x'
self:addChild { icon = icon, width = self.height }
self:addChild { text = text, width = textWidth }
self:addChild { text = key, align = 'middle right',
minwidth = self.height, color = keyColor, type = edgeType }
self:addChild {
type = edgeType,
text = key,
align = 'middle right',
minwidth = self.height,
color = function ()
local c = self.color or { 0, 0, 0 }
return { c[1], c[2], c[3], (c[4] or 256) / 2 }
end
}
self.icon = nil
self.text = nil

View File

@@ -183,8 +183,13 @@ return function (self)
end
self.value = self.value or self.text or ''
self.text = ''
self.highlight = self.highlight or { 0x80, 0x80, 0x80 }
if not self.highlight then
self.highlight = { 0x80, 0x80, 0x80 }
end
self.scrollX = 0
setCaretFromText(self, self.value)
@@ -262,20 +267,18 @@ return function (self)
Backend.setFont(font)
-- draw highlight
Backend.setColor(self.highlight)
Backend.drawRectangle('fill', startX, y, width, height)
if Backend.getTime() % 2 < 1.75 then
Backend.setColor(color)
Backend.drawRectangle('fill', endX, y, 1, height)
if self.focused then
Backend.setColor(self.highlight)
Backend.drawRectangle('fill', startX, y, width, height)
if Backend.getTime() % 2 < 1.75 then
Backend.setColor(color)
Backend.drawRectangle('fill', endX, y, 1, height)
end
end
-- draw text
Backend.setColor(color)
Backend.print(self.value, x - self.scrollX, textTop)
if not self.focused then
Backend.pop()
return
end
Backend.pop()
end)