mirror of
https://github.com/airstruck/luigi.git
synced 2025-11-18 12:25:06 +00:00
603 lines
13 KiB
Lua
603 lines
13 KiB
Lua
--[[--
|
|
Widget attributes.
|
|
|
|
This module defines "attributes" (special fields) that are
|
|
recognized by all widgets. Their interpretation may vary
|
|
depending on the `type` of widget. Some widget types may also
|
|
recognize additional attributes.
|
|
|
|
Setting attributes can have side effects. For example, setting
|
|
`height` or `width` causes the parent widget and its descendants
|
|
to recalculate their size and position.
|
|
--]]--
|
|
|
|
local ROOT = (...):gsub('[^.]*$', '')
|
|
|
|
local Shortcut = require(ROOT .. 'shortcut')
|
|
|
|
local Attribute = {}
|
|
|
|
local function cascade (widget, attribute)
|
|
local value = rawget(widget, 'attributes')[attribute]
|
|
if value ~= nil then return value end
|
|
local parent = rawget(widget, 'parent')
|
|
return parent and parent[attribute]
|
|
end
|
|
|
|
--[[--
|
|
Type of widget.
|
|
|
|
Should contain a string identifying the widget's type.
|
|
After the layout is built, may be replaced by an array
|
|
of strings identifying multiple types. This is used
|
|
internally by some widgets to provide information about
|
|
the widget's state to the theme (themes describe the
|
|
appearance of widgets according to their type).
|
|
|
|
If a type is registered with the widget's layout, the registered
|
|
type initializer function will run once when the widget is constructed.
|
|
|
|
@see Widget.register
|
|
|
|
@attrib type
|
|
--]]--
|
|
Attribute.type = {}
|
|
|
|
function Attribute.type.set (widget, value)
|
|
local oldType = widget.attributes.type
|
|
|
|
widget.attributes.type = value
|
|
|
|
if value and not widget.hasType then
|
|
widget.hasType = true
|
|
local Widget = require(ROOT .. 'widget')
|
|
local decorate = Widget.typeDecorators[value]
|
|
|
|
if decorate then
|
|
decorate(widget)
|
|
end
|
|
end
|
|
end
|
|
|
|
--[[--
|
|
Widget identifier.
|
|
|
|
Should contain a unique string identifying the widget, if present.
|
|
|
|
A reference to the widget will be stored in the associated layout
|
|
in a property having the same name as the widget's id.
|
|
|
|
Setting this attribute re-registers the widget with its layout.
|
|
|
|
@attrib id
|
|
--]]--
|
|
Attribute.id = {}
|
|
|
|
function Attribute.id.set (widget, value)
|
|
local layout = widget.layout.master or widget.layout
|
|
local oldValue = widget.attributes.id
|
|
|
|
if oldValue then
|
|
layout[oldValue] = nil
|
|
end
|
|
|
|
if value then
|
|
layout[value] = widget
|
|
end
|
|
|
|
widget.attributes.id = value
|
|
end
|
|
|
|
--[[--
|
|
Widget value.
|
|
|
|
Some widget types expect the value to be of a specific type and
|
|
within a specific range. For example, `slider` and `progress`
|
|
widgets expect a normalized number, `text` widgets expect
|
|
a string, and `check` and `radio` widgets expect a boolean.
|
|
|
|
Setting this attribute bubbles the `Change` event.
|
|
|
|
@attrib value
|
|
--]]--
|
|
Attribute.value = {}
|
|
|
|
function Attribute.value.set (widget, value)
|
|
local oldValue = widget.value
|
|
widget.attributes.value = value
|
|
widget:bubbleEvent('Change', { value = value, oldValue = oldValue })
|
|
end
|
|
|
|
--[[--
|
|
Solidity.
|
|
|
|
Should true or false.
|
|
|
|
@attrib icon
|
|
--]]--
|
|
Attribute.solid = {}
|
|
|
|
function Attribute.solid.set (widget, value)
|
|
widget.attributes.solid = value
|
|
end
|
|
|
|
Attribute.solid.get = cascade
|
|
|
|
--[[--
|
|
Context menu.
|
|
|
|
- This attribute cascades.
|
|
|
|
@attrib context
|
|
--]]--
|
|
Attribute.context = {}
|
|
|
|
function Attribute.context.set (widget, value)
|
|
widget.attributes.context = value
|
|
if not value then return end
|
|
value.isContextMenu = true
|
|
widget.layout:createWidget { type = 'menu', value }
|
|
end
|
|
|
|
Attribute.context.get = cascade
|
|
|
|
--[[--
|
|
Widget style.
|
|
|
|
Should contain a string or array of strings identifying
|
|
style rules to be applied to the widget. When resolving
|
|
any attribute with a `nil` value, these style rules are
|
|
searched for a corresponding attribute.
|
|
|
|
Setting this attribute resets the `Font` and `Text` object
|
|
associated with this widget.
|
|
|
|
Setting this attribute recalculates the size and position
|
|
of the parent widget and its descendants.
|
|
|
|
@attrib style
|
|
--]]--
|
|
Attribute.style = {}
|
|
|
|
function Attribute.style.set (widget, value)
|
|
widget.attributes.style = value
|
|
widget.fontData = nil
|
|
widget.textData = nil
|
|
widget.reshape(widget.parent or widget)
|
|
end
|
|
|
|
--[[--
|
|
Status message.
|
|
|
|
Should contain a string with a short message describing the
|
|
purpose or state of the widget.
|
|
|
|
This message will appear in the last created `status` widget
|
|
in the same layout, or in the master layout if one exists.
|
|
|
|
- This attribute cascades.
|
|
|
|
@attrib status
|
|
--]]--
|
|
Attribute.status = {}
|
|
|
|
Attribute.status.get = cascade
|
|
|
|
--[[--
|
|
Scroll ability.
|
|
|
|
Should contain `true` or `false` (or `nil`).
|
|
|
|
If set to `true`, moving the scroll wheel over the widget will adjust
|
|
its scroll position when the widget's contents overflow its boundary.
|
|
|
|
@attrib scroll
|
|
--]]--
|
|
Attribute.scroll = {}
|
|
|
|
--[[--
|
|
Keyboard Attributes.
|
|
|
|
@section keyboard
|
|
--]]--
|
|
|
|
--[[--
|
|
Focusable.
|
|
|
|
Should contain `true` if the widget can be focused by pressing the tab key.
|
|
|
|
@attrib focusable
|
|
--]]--
|
|
Attribute.focusable = {}
|
|
|
|
--[[--
|
|
Keyboard shortcut.
|
|
|
|
Should contain a string representing a key and optional modifiers,
|
|
separated by dashes; for example `'ctrl-c'` or `'alt-shift-escape'`.
|
|
|
|
Pressing this key combination bubbles a `Press` event on the widget,
|
|
as if it had been pressed with a mouse or touch interface.
|
|
|
|
Setting this attribute re-registers the widget with its layout.
|
|
|
|
@attrib shortcut
|
|
--]]--
|
|
Attribute.shortcut = {}
|
|
|
|
local function setShortcut (layout, shortcut, value)
|
|
local mainKey, modifierFlags = Shortcut.parseKeyCombo(shortcut)
|
|
if mainKey then
|
|
layout.shortcuts[modifierFlags][mainKey] = value
|
|
end
|
|
end
|
|
|
|
function Attribute.shortcut.set (widget, value)
|
|
local layout = widget.layout.master or widget.layout
|
|
local oldValue = widget.attributes.shortcut
|
|
|
|
if oldValue then
|
|
if type(oldValue) == 'table' then
|
|
for _, v in ipairs(oldValue) do
|
|
setShortcut(layout, v, nil)
|
|
end
|
|
else
|
|
setShortcut(layout, oldValue, nil)
|
|
end
|
|
end
|
|
|
|
if value then
|
|
if type(value) == 'table' then
|
|
for _, v in ipairs(value) do
|
|
setShortcut(layout, v, widget)
|
|
end
|
|
else
|
|
setShortcut(layout, value, widget)
|
|
end
|
|
end
|
|
|
|
widget.attributes.shortcut = value
|
|
end
|
|
|
|
--[[--
|
|
Size Attributes.
|
|
|
|
Setting these attributes recalculates the size and position
|
|
of the parent widget and its descendants.
|
|
|
|
@section size
|
|
--]]--
|
|
|
|
--[[--
|
|
Flow axis.
|
|
|
|
Should equal either `'x'` or `'y'`. Defaults to `'y'`.
|
|
|
|
This attribute determines the placement and default dimensions
|
|
of any child widgets.
|
|
|
|
When flow is `'x'`, the `height` of child widgets defaults
|
|
to this widget's height, and each child is placed to the
|
|
right of the previous child. When flow is `'y'`, the `width`
|
|
of child widgets defaults to this widget's width, and each
|
|
child is placed below the previous child.
|
|
|
|
Setting this attribute resets the `Text` object associated
|
|
with this widget.
|
|
|
|
@attrib flow
|
|
--]]--
|
|
Attribute.flow = {}
|
|
|
|
function Attribute.flow.set (widget, value)
|
|
widget.attributes.flow = value
|
|
widget.textData = nil
|
|
widget.reshape(widget.parent or widget)
|
|
end
|
|
|
|
--[[--
|
|
Width.
|
|
|
|
This attribute may not always hold a numeric value.
|
|
To get the calculated width, use `Widget:getWidth`.
|
|
|
|
Setting this attribute when the `wrap` attribute is
|
|
also present resets the `Text` object associated
|
|
with this widget.
|
|
|
|
@attrib width
|
|
--]]--
|
|
Attribute.width = {}
|
|
|
|
function Attribute.width.set (widget, value)
|
|
if value ~= 'auto' then
|
|
value = value and math.max(value, widget.minwidth or 0)
|
|
end
|
|
widget.attributes.width = value
|
|
if widget.wrap then
|
|
widget.textData = nil
|
|
end
|
|
widget.reshape(widget.parent or widget)
|
|
end
|
|
|
|
--[[--
|
|
Height.
|
|
|
|
This attribute may not always hold a numeric value.
|
|
To get the calculated height, use `Widget:getHeight`.
|
|
|
|
@attrib height
|
|
--]]--
|
|
Attribute.height = {}
|
|
|
|
function Attribute.height.set (widget, value)
|
|
if value ~= 'auto' then
|
|
value = value and math.max(value, widget.minheight or 0)
|
|
end
|
|
widget.attributes.height = value
|
|
widget.reshape(widget.parent or widget)
|
|
end
|
|
|
|
--[[--
|
|
Minimum width.
|
|
|
|
@attrib minwidth
|
|
--]]--
|
|
Attribute.minwidth = {}
|
|
|
|
function Attribute.minwidth.set (widget, value)
|
|
local attributes = widget.attributes
|
|
attributes.minwidth = value
|
|
if type(value) == 'number' then
|
|
local current = attributes.width
|
|
if type(current) == 'number' then
|
|
attributes.width = math.max(current, value)
|
|
end
|
|
end
|
|
widget.reshape(widget.parent or widget)
|
|
end
|
|
|
|
--[[--
|
|
Minimum height.
|
|
|
|
@attrib minheight
|
|
--]]--
|
|
Attribute.minheight = {}
|
|
|
|
function Attribute.minheight.set (widget, value)
|
|
local attributes = widget.attributes
|
|
attributes.minheight = value
|
|
if type(value) == 'number' then
|
|
local current = attributes.height
|
|
if type(current) == 'number' then
|
|
attributes.height = math.max(current, value)
|
|
end
|
|
end
|
|
widget.reshape(widget.parent or widget)
|
|
end
|
|
|
|
--[[--
|
|
Font Attributes.
|
|
|
|
Setting these attributes resets the Font and Text
|
|
objects associated with the widget.
|
|
|
|
@section font
|
|
--]]--
|
|
|
|
--[[--
|
|
Font path.
|
|
|
|
Should contain a path to a TrueType font to use for displaying
|
|
this widget's `text`.
|
|
|
|
- This attribute cascades.
|
|
|
|
@attrib font
|
|
--]]--
|
|
Attribute.font = {}
|
|
|
|
local function resetFont (widget)
|
|
rawset(widget, 'fontData', nil)
|
|
rawset(widget, 'textData', nil)
|
|
for _, child in ipairs(widget) do
|
|
resetFont(child)
|
|
end
|
|
local items = widget.items
|
|
if items then
|
|
for _, child in ipairs(items) do
|
|
resetFont(child)
|
|
end
|
|
end
|
|
end
|
|
|
|
function Attribute.font.set (widget, value)
|
|
widget.attributes.font = value
|
|
resetFont(widget)
|
|
end
|
|
|
|
Attribute.font.get = cascade
|
|
|
|
--[[--
|
|
Font size.
|
|
|
|
Should contain a number representing the size of the font, in points.
|
|
Defaults to 12.
|
|
|
|
- This attribute cascades.
|
|
|
|
@attrib size
|
|
--]]--
|
|
Attribute.size = {}
|
|
|
|
function Attribute.size.set (widget, value)
|
|
widget.attributes.size = value
|
|
widget.fontData = nil
|
|
widget.textData = nil
|
|
end
|
|
|
|
Attribute.size.get = cascade
|
|
|
|
--[[--
|
|
Text Attributes.
|
|
|
|
Setting these attributes resets the Text object
|
|
associated with the widget.
|
|
|
|
@section text
|
|
--]]--
|
|
|
|
--[[--
|
|
Text to display.
|
|
|
|
@attrib text
|
|
--]]--
|
|
Attribute.text = {}
|
|
|
|
function Attribute.text.set (widget, value)
|
|
widget.attributes.text = value
|
|
widget.textData = nil
|
|
end
|
|
|
|
--[[--
|
|
Text color.
|
|
|
|
Should contain an array with 3 or 4 values (RGB or RGBA) from 0 to 255.
|
|
|
|
- This attribute cascades.
|
|
|
|
@attrib color
|
|
--]]--
|
|
Attribute.color = {}
|
|
|
|
function Attribute.color.set (widget, value)
|
|
widget.attributes.color = value
|
|
widget.textData = nil
|
|
end
|
|
|
|
Attribute.color.get = cascade
|
|
|
|
--[[--
|
|
Text and icon alignment.
|
|
|
|
Should contain a string defining vertical and horizontal alignment.
|
|
Vertical alignment is defined by either 'top', 'middle', or 'bottom',
|
|
and horizontal alignment is defined by either 'left', 'center', or 'right'.
|
|
|
|
For example, `align = 'top left'`
|
|
|
|
- This attribute cascades.
|
|
|
|
@attrib align
|
|
--]]--
|
|
Attribute.align = {}
|
|
|
|
function Attribute.align.set (widget, value)
|
|
widget.attributes.align = value
|
|
widget.textData = nil
|
|
end
|
|
|
|
Attribute.align.get = cascade
|
|
|
|
--[[--
|
|
Wrap text onto multiple lines.
|
|
|
|
Should contain `true` for multiline text, or `false` or `nil`
|
|
for a single line. Even text containing line breaks will display
|
|
as a single line when this attribute is not set to `true`.
|
|
|
|
- This attribute cascades.
|
|
|
|
@attrib wrap
|
|
--]]--
|
|
Attribute.wrap = {}
|
|
|
|
function Attribute.wrap.set (widget, value)
|
|
widget.attributes.wrap = value
|
|
widget.textData = nil
|
|
end
|
|
|
|
Attribute.wrap.get = cascade
|
|
|
|
--[[--
|
|
Visual Attributes.
|
|
|
|
@section visual
|
|
--]]--
|
|
|
|
--[[--
|
|
Background color.
|
|
|
|
Should contain an array with 3 or 4 values (RGB or RGBA) from 0 to 255.
|
|
|
|
@attrib background
|
|
--]]--
|
|
Attribute.background = {}
|
|
|
|
--[[--
|
|
Outline color.
|
|
|
|
Should contain an array with 3 or 4 values (RGB or RGBA) from 0 to 255.
|
|
|
|
@attrib outline
|
|
--]]--
|
|
Attribute.outline = {}
|
|
|
|
--[[--
|
|
Slice image.
|
|
|
|
Should contain a path to an image with "slices" to display for this widget.
|
|
|
|
@attrib slices
|
|
--]]--
|
|
Attribute.slices = {}
|
|
|
|
--[[--
|
|
Margin size.
|
|
|
|
The margin area occupies space outside of the `outline` and `slices`.
|
|
|
|
@attrib margin
|
|
--]]--
|
|
Attribute.margin = {}
|
|
|
|
function Attribute.margin.set (widget, value)
|
|
widget.attributes.margin = value
|
|
widget.textData = nil
|
|
widget:reshape()
|
|
end
|
|
|
|
--[[--
|
|
Padding size.
|
|
|
|
The padding area occupies space inside the `outline` and `slices`,
|
|
and outside the space where the `icon` and `text` and any
|
|
child widgets appear.
|
|
|
|
@attrib padding
|
|
--]]--
|
|
Attribute.padding = {}
|
|
|
|
function Attribute.padding.set (widget, value)
|
|
widget.attributes.padding = value
|
|
widget.textData = nil
|
|
widget:reshape()
|
|
end
|
|
|
|
--[[--
|
|
Icon path.
|
|
|
|
Should contain a path to an image file.
|
|
|
|
@attrib icon
|
|
--]]--
|
|
Attribute.icon = {}
|
|
|
|
function Attribute.icon.set (widget, value)
|
|
widget.attributes.icon = value
|
|
widget.textData = nil
|
|
end
|
|
|
|
|
|
return Attribute
|