simplify style system

This commit is contained in:
airstruck
2015-12-07 04:22:36 -05:00
parent 367535ad33
commit 69703fdce0
41 changed files with 2227 additions and 292 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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
},
}

View File

@@ -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)

View File

@@ -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
--]]--

View File

@@ -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

View File

@@ -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

View File

@@ -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
--]]--

View File

@@ -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
--]]--