mirror of
https://github.com/airstruck/luigi.git
synced 2026-01-10 08:18:22 +00:00
simplify style system
This commit is contained in:
@@ -85,6 +85,7 @@ Backend.run = function ()
|
||||
end
|
||||
end
|
||||
|
||||
sdl.renderSetClipRect(renderer, nil)
|
||||
sdl.setRenderDrawColor(renderer, 0, 0, 0, 255)
|
||||
sdl.renderClear(renderer)
|
||||
callback.draw()
|
||||
@@ -273,8 +274,6 @@ local stack = {}
|
||||
Backend.pop = function ()
|
||||
local history = stack[#stack]
|
||||
local color = history.color or { 0, 0, 0, 255 }
|
||||
Backend.setColor(history.color or { 0, 0, 0, 255 })
|
||||
Backend.sdl = sdl
|
||||
|
||||
sdl.setRenderDrawColor(renderer,
|
||||
color[1], color[2], color[3], color[4] or 255)
|
||||
|
||||
@@ -36,18 +36,9 @@ local function renderMulti (self, font, text, color, align, limit)
|
||||
local height = #lines * lineHeight
|
||||
color = sdl.Color(color or 0)
|
||||
|
||||
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
|
||||
-- mask values from SDL_ttf.c
|
||||
-- TODO: something with sdl.BYTEORDER == sdl.BIG_ENDIAN ?
|
||||
local r, g, b, a = 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000
|
||||
|
||||
local surface = ffi.gc(
|
||||
sdl.createRGBSurface(sdl.SWSURFACE, limit, height, 32, r, g, b, a),
|
||||
@@ -61,7 +52,7 @@ local function renderMulti (self, font, text, color, align, limit)
|
||||
sdl.freeSurface)
|
||||
if lineSurface ~= nil then
|
||||
sdl.setSurfaceBlendMode(lineSurface, sdl.BLENDMODE_NONE)
|
||||
|
||||
|
||||
local w, h = lineSurface.w, lineSurface.h
|
||||
local top = (index - 1) * lineHeight
|
||||
|
||||
|
||||
@@ -213,12 +213,9 @@ end
|
||||
function Input:handleReshape (layout, width, height)
|
||||
local root = layout.root
|
||||
|
||||
if root.float then
|
||||
root:reshape()
|
||||
else
|
||||
root.width = width
|
||||
root.height = height
|
||||
end
|
||||
root:reshape()
|
||||
root.dimensions.width = width
|
||||
root.dimensions.height = height
|
||||
|
||||
Event.Reshape:emit(layout, { target = layout })
|
||||
end
|
||||
@@ -228,7 +225,7 @@ function Input:handleWheelMove (layout, x, y)
|
||||
local mx, my = Backend.getMousePosition()
|
||||
local widget = layout:getWidgetAt(mx, my)
|
||||
local hit = true
|
||||
|
||||
|
||||
if not widget then
|
||||
hit = nil
|
||||
widget = layout.root
|
||||
|
||||
@@ -13,6 +13,7 @@ function Style:getProperty (object, property, original)
|
||||
local value = rawget(object, property)
|
||||
if value ~= nil then return value end
|
||||
|
||||
local rules = self.rules
|
||||
original = original or object
|
||||
|
||||
for _, lookupName in ipairs(self.lookupNames) do
|
||||
@@ -23,7 +24,8 @@ function Style:getProperty (object, property, original)
|
||||
lookup = { lookup }
|
||||
end
|
||||
for _, lookupValue in ipairs(lookup) do
|
||||
for _, rule in ipairs(self:getRules(original, lookupValue)) do
|
||||
local rule = rules[lookupValue]
|
||||
if rule then
|
||||
local value = self:getProperty(rule, property, original)
|
||||
if value ~= nil then return value end
|
||||
end
|
||||
@@ -32,21 +34,4 @@ function Style:getProperty (object, property, original)
|
||||
end -- lookup names
|
||||
end
|
||||
|
||||
function Style:getRules (object, lookupValue)
|
||||
local rules = self.rules
|
||||
local result = {}
|
||||
|
||||
for _, flag in ipairs { 'pressed', 'focused', 'hovered', 'active' } do
|
||||
if rawget(object, flag) then
|
||||
result[#result + 1] = rules[lookupValue .. '_' .. flag]
|
||||
else
|
||||
result[#result + 1] = rules[lookupValue .. '_not_' .. flag]
|
||||
end
|
||||
end
|
||||
|
||||
result[#result + 1] = rules[lookupValue]
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
return Style
|
||||
|
||||
@@ -1,157 +1,12 @@
|
||||
local RESOURCE = (...):gsub('%.', '/') .. '/'
|
||||
local REL = (...):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 { 0x00, 0x5c, 0x94 }
|
||||
|
||||
return {
|
||||
button = {
|
||||
align = 'center middle',
|
||||
padding = 6,
|
||||
slices = RESOURCE .. 'button.png',
|
||||
minwidth = 24,
|
||||
minheight = 24,
|
||||
focusable = 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,
|
||||
focusable = true,
|
||||
cursor = 'ibeam',
|
||||
highlight = highlight,
|
||||
color = textColor,
|
||||
},
|
||||
text_focused = {
|
||||
slices = RESOURCE .. 'text_focused.png',
|
||||
},
|
||||
check = {
|
||||
focusable = 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 = {
|
||||
focusable = 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',
|
||||
},
|
||||
}
|
||||
|
||||
config.resources = config.resources or RESOURCE
|
||||
config.backColor = config.backColor or { 40, 40, 40 }
|
||||
config.lineColor = config.lineColor or { 60, 60, 60 }
|
||||
config.textColor = config.textColor or { 240, 240, 240 }
|
||||
config.highlight = config.highlight or { 0x00, 0x5c, 0x94 }
|
||||
return require(REL .. 'light')(config)
|
||||
end
|
||||
|
||||
@@ -2,38 +2,74 @@ local RESOURCE = (...):gsub('%.', '/') .. '/'
|
||||
|
||||
return function (config)
|
||||
config = config or {}
|
||||
|
||||
local resources = config.resources or RESOURCE
|
||||
local backColor = config.backColor or { 240, 240, 240 }
|
||||
local lineColor = config.lineColor or { 220, 220, 220 }
|
||||
local textColor = config.textColor or { 0, 0, 0 }
|
||||
local highlight = config.highlight or { 0x19, 0xAE, 0xFF }
|
||||
|
||||
local function getButtonSlices (self)
|
||||
return self.pressed and resources .. 'button_pressed.png'
|
||||
or self.focused and resources .. 'button_focused.png'
|
||||
or self.hovered and resources .. 'button_hovered.png'
|
||||
or resources .. 'button.png'
|
||||
end
|
||||
|
||||
local function getCheckOrRadioIcon (self)
|
||||
local prefix = resources .. self.type
|
||||
if self.pressed then
|
||||
if self.value then
|
||||
return prefix .. '_checked_pressed.png'
|
||||
else
|
||||
return prefix .. '_unchecked_pressed.png'
|
||||
end
|
||||
elseif self.focused then
|
||||
if self.value then
|
||||
return prefix .. '_checked_focused.png'
|
||||
else
|
||||
return prefix .. '_unchecked_focused.png'
|
||||
end
|
||||
else
|
||||
if self.value then
|
||||
return prefix .. '_checked.png'
|
||||
else
|
||||
return prefix .. '_unchecked.png'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function getMenuItemBackground (self)
|
||||
return self.active and highlight
|
||||
end
|
||||
|
||||
local function getSashBackground (self)
|
||||
return self.hovered and highlight or lineColor
|
||||
end
|
||||
|
||||
local function getTextSlices (self)
|
||||
return self.focused and resources .. 'text_focused.png'
|
||||
or resources .. 'text.png'
|
||||
end
|
||||
|
||||
return {
|
||||
button = {
|
||||
align = 'center middle',
|
||||
padding = 6,
|
||||
slices = RESOURCE .. 'button.png',
|
||||
slices = getButtonSlices,
|
||||
minwidth = 24,
|
||||
minheight = 24,
|
||||
focusable = true
|
||||
},
|
||||
button_hovered = {
|
||||
slices = RESOURCE .. 'button_hovered.png'
|
||||
},
|
||||
button_focused = {
|
||||
slices = RESOURCE .. 'button_focused.png',
|
||||
},
|
||||
button_pressed = {
|
||||
slices = RESOURCE .. 'button_pressed.png',
|
||||
focusable = true,
|
||||
color = textColor,
|
||||
},
|
||||
|
||||
['stepper.left'] = {
|
||||
type = 'button',
|
||||
icon = RESOURCE .. 'triangle_left.png',
|
||||
icon = resources .. 'triangle_left.png',
|
||||
},
|
||||
|
||||
['stepper.right'] = {
|
||||
type = 'button',
|
||||
icon = RESOURCE .. 'triangle_right.png',
|
||||
icon = resources .. 'triangle_right.png',
|
||||
},
|
||||
menu = {
|
||||
height = 24,
|
||||
@@ -41,107 +77,72 @@ return function (config)
|
||||
['menu.item'] = {
|
||||
padding = 4,
|
||||
align = 'left middle',
|
||||
color = { 0, 0, 0 }
|
||||
},
|
||||
['menu.item_active'] = {
|
||||
background = highlight,
|
||||
color = textColor,
|
||||
background = getMenuItemBackground,
|
||||
},
|
||||
['menu.expander'] = {
|
||||
icon = RESOURCE .. 'triangle_right.png',
|
||||
icon = resources .. 'triangle_right.png',
|
||||
},
|
||||
submenu = {
|
||||
padding = 10,
|
||||
margin = -10,
|
||||
slices = RESOURCE .. 'submenu.png',
|
||||
slices = resources .. 'submenu.png',
|
||||
color = textColor,
|
||||
},
|
||||
sash = {
|
||||
background = lineColor
|
||||
},
|
||||
sash_hovered = {
|
||||
background = highlight
|
||||
background = getSashBackground
|
||||
},
|
||||
slider = {
|
||||
slices = RESOURCE .. 'button_pressed.png',
|
||||
slices = resources .. 'button_pressed.png',
|
||||
padding = 0,
|
||||
minwidth = 24,
|
||||
minheight = 24
|
||||
},
|
||||
panel = {
|
||||
background = backColor,
|
||||
color = textColor,
|
||||
},
|
||||
progress = {
|
||||
slices = RESOURCE .. 'button_pressed.png',
|
||||
slices = resources .. 'button_pressed.png',
|
||||
padding = 0,
|
||||
minwidth = 24,
|
||||
minheight = 24
|
||||
},
|
||||
['progress.bar'] = {
|
||||
slices = RESOURCE .. 'progress.png',
|
||||
slices = resources .. 'progress.png',
|
||||
padding = 0,
|
||||
minwidth = 12,
|
||||
},
|
||||
slider_hovered = {
|
||||
},
|
||||
stepper = {
|
||||
slices = RESOURCE .. 'button_pressed.png',
|
||||
slices = resources .. 'button_pressed.png',
|
||||
},
|
||||
['stepper.item'] = {
|
||||
align = 'center middle',
|
||||
color = textColor,
|
||||
},
|
||||
status = {
|
||||
type = 'panel',
|
||||
},
|
||||
text = {
|
||||
align = 'left middle',
|
||||
slices = RESOURCE .. 'text.png',
|
||||
slices = getTextSlices,
|
||||
padding = 6,
|
||||
minwidth = 24,
|
||||
minheight = 24,
|
||||
focusable = true,
|
||||
cursor = 'ibeam',
|
||||
highlight = highlight,
|
||||
},
|
||||
text_focused = {
|
||||
slices = RESOURCE .. 'text_focused.png',
|
||||
color = textColor,
|
||||
},
|
||||
check = {
|
||||
focusable = true,
|
||||
},
|
||||
['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',
|
||||
color = textColor,
|
||||
icon = getCheckOrRadioIcon
|
||||
},
|
||||
radio = {
|
||||
focusable = true,
|
||||
},
|
||||
['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',
|
||||
color = textColor,
|
||||
icon = getCheckOrRadioIcon
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@@ -66,8 +66,8 @@ 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 maybeCall(value, self) end
|
||||
value = style and maybeCall(style:getProperty(self, property), self)
|
||||
if value ~= nil and value ~= 'defer' then return value end
|
||||
|
||||
local theme = layout:getTheme()
|
||||
return theme and maybeCall(theme:getProperty(self, property), self)
|
||||
|
||||
@@ -1,5 +1,26 @@
|
||||
--[[--
|
||||
A simple button.
|
||||
A button.
|
||||
|
||||
Buttons have no special behavior beyond that of generic widgets,
|
||||
but themes should give buttons an appropriate appearance.
|
||||
|
||||
@usage
|
||||
-- create a layout containing only a button
|
||||
local layout = Layout {
|
||||
type = 'button',
|
||||
id = 'exampleButton',
|
||||
text = 'Press me',
|
||||
width = 100,
|
||||
height = 32,
|
||||
}
|
||||
|
||||
-- handle Press events
|
||||
layout.exampleButton:onPress(function (event)
|
||||
print 'You pressed the button.'
|
||||
end)
|
||||
|
||||
-- show the layout
|
||||
layout:show()
|
||||
|
||||
@widget button
|
||||
--]]--
|
||||
|
||||
@@ -1,6 +1,14 @@
|
||||
--[[--
|
||||
A check box.
|
||||
|
||||
Check boxes toggle their @{attribute.value|value} attribute between
|
||||
`true` and `false` when pressed.
|
||||
|
||||
Changing the value of a check box causes it to change its appearance to
|
||||
indicate its value. The standard themes use the @{attribute.icon|icon}
|
||||
attribute for this purpose. If a custom icon is provided when using the
|
||||
standard themes, the widget's value should be indicated in some other way.
|
||||
|
||||
@widget check
|
||||
--]]--
|
||||
|
||||
@@ -9,10 +17,5 @@ return function (self)
|
||||
self.value = not self.value
|
||||
end)
|
||||
|
||||
self:onChange(function ()
|
||||
local subtype = self.value and 'check.checked' or 'check.unchecked'
|
||||
self.type = { 'check', subtype }
|
||||
end)
|
||||
|
||||
self.value = not not self.value
|
||||
end
|
||||
|
||||
@@ -1,6 +1,17 @@
|
||||
--[[--
|
||||
A radio button.
|
||||
|
||||
Radio buttons change their @{attribute.value|value} attribute to
|
||||
`true` when pressed. Radio buttons should also have a `group`
|
||||
attribute. When a radio button is pressed, other radio buttons
|
||||
in the same layout with the same `group` attribute change their values
|
||||
to `false`.
|
||||
|
||||
Changing the value of a radio button causes it to change its appearance to
|
||||
indicate its value. The standard themes use the @{attribute.icon|icon}
|
||||
attribute for this purpose. If a custom icon is provided when using the
|
||||
standard themes, the widget's value should be indicated in some other way.
|
||||
|
||||
@widget radio
|
||||
--]]--
|
||||
|
||||
@@ -24,10 +35,5 @@ return function (self)
|
||||
end
|
||||
end)
|
||||
|
||||
self:onChange(function ()
|
||||
local subtype = self.value and 'radio.checked' or 'radio.unchecked'
|
||||
self.type = { 'radio', subtype }
|
||||
end)
|
||||
|
||||
self.value = not not self.value
|
||||
end
|
||||
|
||||
@@ -2,12 +2,24 @@
|
||||
A sash.
|
||||
|
||||
Dragging this widget resizes the widgets adjacent to it.
|
||||
A sash must be adjacent to a widget with a specified size
|
||||
in the same direction as the parent element's `flow`.
|
||||
A sash should be adjacent to a widget with a specified size
|
||||
in the same direction as the parent element's @{attribute.flow|flow}.
|
||||
|
||||
For example, if the parent of the sash is `flow = 'x'`
|
||||
then either or both of the siblings next to the sash
|
||||
must have a specified `width` property.
|
||||
then either or both of the siblings adjacent to the sash
|
||||
should have a specified @{attribute.width|width} attribute.
|
||||
|
||||
@usage
|
||||
-- create a layout containing two widgets separated by a sash
|
||||
local layout = Layout {
|
||||
type = 'panel', flow = 'x',
|
||||
{ text = 'This is the left side', wrap = true, width = 100 },
|
||||
{ type = 'sash' },
|
||||
{ text = 'This is the right side', wrap = true },
|
||||
}
|
||||
|
||||
-- show the layout
|
||||
layout:show()
|
||||
|
||||
@widget sash
|
||||
--]]--
|
||||
|
||||
@@ -1,6 +1,24 @@
|
||||
--[[--
|
||||
A status bar.
|
||||
|
||||
This widget will display the @{attribute.status|status} attribute of the
|
||||
hovered widget. Only one status widget should exist per layout. If multiple
|
||||
status widgets exist in the same layout, only the last one created will
|
||||
display status messages.
|
||||
|
||||
@usage
|
||||
-- create a layout containing some buttons and a status bar
|
||||
local layout = Layout {
|
||||
{ type = 'panel', flow = 'x',
|
||||
{ text = 'Do stuff', status = 'Press to do stuff' },
|
||||
{ text = 'Quit', status = 'Press to quit' },
|
||||
},
|
||||
{ type = 'status', height = 24 },
|
||||
}
|
||||
|
||||
-- show the layout
|
||||
layout:show()
|
||||
|
||||
@widget status
|
||||
--]]--
|
||||
|
||||
|
||||
Reference in New Issue
Block a user