mirror of
https://github.com/airstruck/luigi.git
synced 2026-01-10 16:28:23 +00:00
add menus
This commit is contained in:
@@ -144,7 +144,7 @@
|
|||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
|
||||||
<i style="float:right;">Last updated 2015-11-04 15:07:53 </i>
|
<i style="float:right;">Last updated 2015-11-06 00:18:26 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -49,10 +49,16 @@
|
|||||||
<div id="content">
|
<div id="content">
|
||||||
|
|
||||||
<h1>Class <code>Layout</code></h1>
|
<h1>Class <code>Layout</code></h1>
|
||||||
<p>Layout class.</p>
|
<p>A Layout contains a tree of widgets with a single <code>root</code> widget.</p>
|
||||||
<p>
|
<p>Layouts will resize to fit the window unless a <code>top</code> or <code>left</code>
|
||||||
|
property is found in the root widget.</p>
|
||||||
|
|
||||||
</p>
|
<p>Layouts are drawn in the order that they were shown, so the
|
||||||
|
most recently shown layout shown will always appear on top.</p>
|
||||||
|
|
||||||
|
<p>Other events are sent to layouts in the opposite direction,
|
||||||
|
and are trapped by the first layout that can handle the event
|
||||||
|
(for example, the topmost layer that is focused or hovered).</p>
|
||||||
|
|
||||||
|
|
||||||
<h2><a href="#Functions">Functions</a></h2>
|
<h2><a href="#Functions">Functions</a></h2>
|
||||||
@@ -289,7 +295,7 @@ found, and focuses that widget.
|
|||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
|
||||||
<i style="float:right;">Last updated 2015-11-04 15:07:53 </i>
|
<i style="float:right;">Last updated 2015-11-06 00:18:26 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -611,7 +611,7 @@ on the parent widget.
|
|||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
|
||||||
<i style="float:right;">Last updated 2015-11-04 15:07:53 </i>
|
<i style="float:right;">Last updated 2015-11-06 00:18:26 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -52,7 +52,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="name" nowrap><a href="classes/Layout.html">Layout</a></td>
|
<td class="name" nowrap><a href="classes/Layout.html">Layout</a></td>
|
||||||
<td class="summary">Layout class.</td>
|
<td class="summary">A Layout contains a tree of widgets with a single <code>root</code> widget.</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="name" nowrap><a href="classes/Widget.html">Widget</a></td>
|
<td class="name" nowrap><a href="classes/Widget.html">Widget</a></td>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
</div> <!-- id="main" -->
|
</div> <!-- id="main" -->
|
||||||
<div id="about">
|
<div id="about">
|
||||||
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
|
<i>generated by <a href="http://github.com/stevedonovan/LDoc">LDoc 1.4.3</a></i>
|
||||||
<i style="float:right;">Last updated 2015-11-04 15:07:53 </i>
|
<i style="float:right;">Last updated 2015-11-06 00:18:26 </i>
|
||||||
</div> <!-- id="about" -->
|
</div> <!-- id="about" -->
|
||||||
</div> <!-- id="container" -->
|
</div> <!-- id="container" -->
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
local Layout = require 'luigi.layout'
|
local Layout = require 'luigi.layout'
|
||||||
|
|
||||||
local style = {
|
local style = {
|
||||||
mainWindow = {
|
|
||||||
width = 600,
|
|
||||||
height = 400,
|
|
||||||
},
|
|
||||||
short = {
|
short = {
|
||||||
height = 48,
|
height = 48,
|
||||||
},
|
},
|
||||||
@@ -36,7 +32,33 @@ local style = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
local mainForm = { title = "Test window", id = 'mainWindow', type = 'panel',
|
local mainForm = { id = 'mainWindow', type = 'panel',
|
||||||
|
{ type = 'menu', id = 'menubar', flow = 'x',
|
||||||
|
{ text = 'File', id = 'menuFile',
|
||||||
|
{ text = 'Save', id = 'menuFileSave', },
|
||||||
|
{ text = 'Quit' },
|
||||||
|
},
|
||||||
|
{ text = 'Edit',
|
||||||
|
{ text = 'Cut' },
|
||||||
|
{ text = 'Copy' },
|
||||||
|
{ text = 'Paste' },
|
||||||
|
{ type = 'slider' },
|
||||||
|
},
|
||||||
|
{ text = 'View',
|
||||||
|
{ text = 'Theme',
|
||||||
|
{ text = 'Light' },
|
||||||
|
{ text = 'Dark' },
|
||||||
|
},
|
||||||
|
{ text = 'Style',
|
||||||
|
{ text = 'Default' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{ text = 'Help',
|
||||||
|
{ text = 'About Luigi', icon = 'icon/16px/Book.png', key = 'backspace', },
|
||||||
|
{ text = 'About Luigi Demo', icon = 'icon/16px/Book Red.png' },
|
||||||
|
{ text = 'Licenses' },
|
||||||
|
},
|
||||||
|
},
|
||||||
{ type = 'panel', id = 'toolbar', flow = 'x',
|
{ type = 'panel', id = 'toolbar', flow = 'x',
|
||||||
{ type = 'button', id = 'newButton', style = 'toolButton', key = 'z',
|
{ type = 'button', id = 'newButton', style = 'toolButton', key = 'z',
|
||||||
icon = 'icon/32px/Blueprint.png' },
|
icon = 'icon/32px/Blueprint.png' },
|
||||||
@@ -97,7 +119,8 @@ end)
|
|||||||
|
|
||||||
layout:onMove(function (event)
|
layout:onMove(function (event)
|
||||||
local w = event.target
|
local w = event.target
|
||||||
layout.statusbar.text = (w.id or '(unnamed)') .. ' ' ..
|
layout.statusbar.text = (w.type or '(generic) ') ..
|
||||||
|
(w.id or '(unnamed)') .. ' ' ..
|
||||||
w:getX() .. ', ' .. w:getY() .. ' | ' ..
|
w:getX() .. ', ' .. w:getY() .. ' | ' ..
|
||||||
w:getWidth() .. 'x' .. w:getHeight()
|
w:getWidth() .. 'x' .. w:getHeight()
|
||||||
end)
|
end)
|
||||||
@@ -107,6 +130,14 @@ layout.newButton:onMove(function (event)
|
|||||||
return false
|
return false
|
||||||
end)
|
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)
|
layout.newButton:onPress(function (event)
|
||||||
print('creating a new thing!')
|
print('creating a new thing!')
|
||||||
end)
|
end)
|
||||||
@@ -114,6 +145,11 @@ end)
|
|||||||
layout.aButton:onPress(function (event)
|
layout.aButton:onPress(function (event)
|
||||||
layout.aButton.font = nil
|
layout.aButton.font = nil
|
||||||
layout.aButton.width = layout.aButton.width + 10
|
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)
|
end)
|
||||||
|
|
||||||
layout.mainCanvas.font = 'font/liberation/LiberationMono-Regular.ttf'
|
layout.mainCanvas.font = 'font/liberation/LiberationMono-Regular.ttf'
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ function Font:setWidth (width)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Font:getLineHeight ()
|
function Font:getLineHeight ()
|
||||||
return self.font:getLineHeight()
|
return self.font:getHeight()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Font:getAscender ()
|
function Font:getAscender ()
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ local function unhook (item)
|
|||||||
item.func = nil
|
item.func = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local function hook (host, key, func)
|
local function hook (host, key, func, atEnd)
|
||||||
if not func then
|
if not func then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -32,17 +32,30 @@ local function hook (host, key, func)
|
|||||||
hooks[host] = {}
|
hooks[host] = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
local next = hooks[host][key]
|
local current = hooks[host][key]
|
||||||
local item = {
|
local item = {
|
||||||
next = next,
|
next = not atEnd and current or nil,
|
||||||
unhook = unhook,
|
unhook = unhook,
|
||||||
host = host,
|
host = host,
|
||||||
key = key,
|
key = key,
|
||||||
func = func,
|
func = func,
|
||||||
}
|
}
|
||||||
|
|
||||||
if next then
|
if atEnd then
|
||||||
next.prev = item
|
if current then
|
||||||
|
while current.next do
|
||||||
|
current = current.next
|
||||||
|
end
|
||||||
|
current.next = item
|
||||||
|
item.prev = current
|
||||||
|
else
|
||||||
|
hooks[host][key] = item
|
||||||
|
end
|
||||||
|
return item
|
||||||
|
end
|
||||||
|
|
||||||
|
if current then
|
||||||
|
current.prev = item
|
||||||
end
|
end
|
||||||
|
|
||||||
hooks[host][key] = item
|
hooks[host][key] = item
|
||||||
@@ -54,7 +67,7 @@ function Hooker.unhook (item)
|
|||||||
return unhook(item)
|
return unhook(item)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Hooker.hook (host, key, func)
|
function Hooker.hook (host, key, func, atEnd)
|
||||||
if not wrapped[host] then
|
if not wrapped[host] then
|
||||||
wrapped[host] = {}
|
wrapped[host] = {}
|
||||||
end
|
end
|
||||||
@@ -68,16 +81,19 @@ function Hooker.hook (host, key, func)
|
|||||||
local item = hooks[host][key]
|
local item = hooks[host][key]
|
||||||
|
|
||||||
while item do
|
while item do
|
||||||
local result = item.func(...)
|
local nextItem = item.next
|
||||||
if result ~= nil then
|
if item.func then
|
||||||
return result
|
local result = item.func(...)
|
||||||
|
if result ~= nil then
|
||||||
|
return result
|
||||||
|
end
|
||||||
end
|
end
|
||||||
item = item.next
|
item = nextItem
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return hook(host, key, func)
|
return hook(host, key, func, atEnd)
|
||||||
end
|
end
|
||||||
|
|
||||||
return Hooker
|
return Hooker
|
||||||
|
|||||||
127
luigi/input.lua
127
luigi/input.lua
@@ -8,62 +8,95 @@ local Input = Base:extend()
|
|||||||
|
|
||||||
local weakValueMeta = { __mode = 'v' }
|
local weakValueMeta = { __mode = 'v' }
|
||||||
|
|
||||||
function Input:constructor (layout)
|
function Input:constructor () --(layout)
|
||||||
self.layout = layout
|
-- layout = layout
|
||||||
self.pressedWidgets = setmetatable({}, weakValueMeta)
|
self.pressedWidgets = setmetatable({}, weakValueMeta)
|
||||||
self.passedWidgets = setmetatable({}, weakValueMeta)
|
self.passedWidgets = setmetatable({}, weakValueMeta)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Input:handleDisplay ()
|
function Input:handleDisplay (layout)
|
||||||
local root = self.layout.root
|
local root = layout.root
|
||||||
if root then Renderer:render(root) end
|
if root then Renderer:render(root) end
|
||||||
Event.Display:emit(self.layout)
|
Event.Display:emit(layout)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Input:handleKeyPress (key, x, y)
|
function Input:handleKeyPress (layout, key, x, y)
|
||||||
local widget = self.layout.focusedWidget or self.layout:getWidgetAt(x, y)
|
local widget = layout.focusedWidget or layout:getWidgetAt(x, y)
|
||||||
|
local hit = true
|
||||||
|
if not widget then
|
||||||
|
hit = nil
|
||||||
|
widget = layout.root
|
||||||
|
end
|
||||||
local result = widget:bubbleEvent('KeyPress', {
|
local result = widget:bubbleEvent('KeyPress', {
|
||||||
|
hit = hit,
|
||||||
key = key, x = x, y = y
|
key = key, x = x, y = y
|
||||||
})
|
})
|
||||||
if result ~= nil then return result end
|
if result ~= nil then return result end
|
||||||
|
return hit
|
||||||
end
|
end
|
||||||
|
|
||||||
function Input:handleKeyRelease (key, x, y)
|
function Input:handleKeyRelease (layout, key, x, y)
|
||||||
local widget = self.layout.focusedWidget or self.layout:getWidgetAt(x, y)
|
local widget = layout.focusedWidget or layout:getWidgetAt(x, y)
|
||||||
|
local hit = true
|
||||||
|
if not widget then
|
||||||
|
hit = nil
|
||||||
|
widget = layout.root
|
||||||
|
end
|
||||||
local result = widget:bubbleEvent('KeyRelease', {
|
local result = widget:bubbleEvent('KeyRelease', {
|
||||||
|
hit = hit,
|
||||||
key = key, x = x, y = y
|
key = key, x = x, y = y
|
||||||
})
|
})
|
||||||
if result ~= nil then return result end
|
if result ~= nil then return result end
|
||||||
|
return hit
|
||||||
end
|
end
|
||||||
|
|
||||||
function Input:handleTextInput (text, x, y)
|
function Input:handleTextInput (layout, text, x, y)
|
||||||
local widget = self.layout.focusedWidget or self.layout:getWidgetAt(x, y)
|
local widget = layout.focusedWidget or layout:getWidgetAt(x, y)
|
||||||
|
local hit = true
|
||||||
|
if not widget then
|
||||||
|
hit = nil
|
||||||
|
widget = layout.root
|
||||||
|
end
|
||||||
widget:bubbleEvent('TextInput', {
|
widget:bubbleEvent('TextInput', {
|
||||||
|
hit = hit,
|
||||||
text = text, x = x, y = y
|
text = text, x = x, y = y
|
||||||
})
|
})
|
||||||
|
return hit
|
||||||
end
|
end
|
||||||
|
|
||||||
function Input:handleMove (x, y)
|
function Input:handleMove (layout, x, y)
|
||||||
local widget = self.layout:getWidgetAt(x, y)
|
local widget = layout:getWidgetAt(x, y)
|
||||||
|
local hit = true
|
||||||
|
if not widget then
|
||||||
|
hit = nil
|
||||||
|
widget = layout.root
|
||||||
|
end
|
||||||
local previousWidget = self.previousMoveWidget
|
local previousWidget = self.previousMoveWidget
|
||||||
if not widget.hovered then
|
if widget ~= previousWidget then
|
||||||
if previousWidget then
|
if previousWidget then
|
||||||
previousWidget.hovered = nil
|
for ancestor in previousWidget:eachAncestor(true) do
|
||||||
|
ancestor.hovered = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for ancestor in widget:eachAncestor(true) do
|
||||||
|
ancestor.hovered = true
|
||||||
end
|
end
|
||||||
widget.hovered = true
|
|
||||||
end
|
end
|
||||||
widget:bubbleEvent('Move', {
|
widget:bubbleEvent('Move', {
|
||||||
|
hit = hit,
|
||||||
oldTarget = previousWidget,
|
oldTarget = previousWidget,
|
||||||
x = x, y = y
|
x = x, y = y
|
||||||
})
|
})
|
||||||
if widget ~= previousWidget then
|
if widget ~= previousWidget then
|
||||||
if previousWidget then
|
if previousWidget then
|
||||||
previousWidget:bubbleEvent('Leave', {
|
previousWidget:bubbleEvent('Leave', {
|
||||||
|
hit = hit,
|
||||||
newTarget = widget,
|
newTarget = widget,
|
||||||
x = x, y = y
|
x = x, y = y
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
widget:bubbleEvent('Enter', {
|
widget:bubbleEvent('Enter', {
|
||||||
|
hit = hit,
|
||||||
oldTarget = previousWidget,
|
oldTarget = previousWidget,
|
||||||
x = x, y = y
|
x = x, y = y
|
||||||
})
|
})
|
||||||
@@ -74,21 +107,29 @@ function Input:handleMove (x, y)
|
|||||||
end
|
end
|
||||||
self.previousMoveWidget = widget
|
self.previousMoveWidget = widget
|
||||||
end
|
end
|
||||||
|
return hit
|
||||||
end
|
end
|
||||||
|
|
||||||
function Input:handlePressedMove (x, y)
|
function Input:handlePressedMove (layout, x, y)
|
||||||
local widget = self.layout:getWidgetAt(x, y)
|
local widget = layout:getWidgetAt(x, y)
|
||||||
|
local hit = true
|
||||||
|
if not widget then
|
||||||
|
hit = nil
|
||||||
|
widget = layout.root
|
||||||
|
end
|
||||||
for button = 1, 3 do
|
for button = 1, 3 do
|
||||||
local originWidget = self.pressedWidgets[button]
|
local originWidget = self.pressedWidgets[button]
|
||||||
local passedWidget = self.passedWidgets[button]
|
local passedWidget = self.passedWidgets[button]
|
||||||
if originWidget then
|
if originWidget then
|
||||||
originWidget:bubbleEvent('PressDrag', {
|
originWidget:bubbleEvent('PressDrag', {
|
||||||
|
hit = hit,
|
||||||
newTarget = widget,
|
newTarget = widget,
|
||||||
button = button,
|
button = button,
|
||||||
x = x, y = y
|
x = x, y = y
|
||||||
})
|
})
|
||||||
if (widget == passedWidget) then
|
if (widget == passedWidget) then
|
||||||
widget:bubbleEvent('PressMove', {
|
widget:bubbleEvent('PressMove', {
|
||||||
|
hit = hit,
|
||||||
origin = originWidget,
|
origin = originWidget,
|
||||||
button = button,
|
button = button,
|
||||||
x = x, y = y
|
x = x, y = y
|
||||||
@@ -97,6 +138,7 @@ function Input:handlePressedMove (x, y)
|
|||||||
originWidget.pressed = (widget == originWidget) or nil
|
originWidget.pressed = (widget == originWidget) or nil
|
||||||
if passedWidget then
|
if passedWidget then
|
||||||
passedWidget:bubbleEvent('PressLeave', {
|
passedWidget:bubbleEvent('PressLeave', {
|
||||||
|
hit = hit,
|
||||||
newTarget = widget,
|
newTarget = widget,
|
||||||
origin = originWidget,
|
origin = originWidget,
|
||||||
button = button,
|
button = button,
|
||||||
@@ -104,42 +146,58 @@ function Input:handlePressedMove (x, y)
|
|||||||
})
|
})
|
||||||
end
|
end
|
||||||
widget:bubbleEvent('PressEnter', {
|
widget:bubbleEvent('PressEnter', {
|
||||||
oldTarget = passedWidget,
|
hit = hit,
|
||||||
origin = originWidget,
|
oldTarget = passedWidget,
|
||||||
button = button,
|
origin = originWidget,
|
||||||
x = x, y = y
|
button = button,
|
||||||
})
|
x = x, y = y
|
||||||
|
})
|
||||||
self.passedWidgets[button] = widget
|
self.passedWidgets[button] = widget
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
return hit
|
||||||
end
|
end
|
||||||
|
|
||||||
function Input:handlePressStart (button, x, y, widget, accelerator)
|
function Input:handlePressStart (layout, button, x, y, widget, accelerator)
|
||||||
local widget = widget or self.layout:getWidgetAt(x, y)
|
local widget = widget or layout:getWidgetAt(x, y)
|
||||||
|
local hit = true
|
||||||
|
if not widget then
|
||||||
|
hit = nil
|
||||||
|
widget = layout.root
|
||||||
|
end
|
||||||
widget.pressed = true
|
widget.pressed = true
|
||||||
self.pressedWidgets[button] = widget
|
self.pressedWidgets[button] = widget
|
||||||
self.passedWidgets[button] = widget
|
self.passedWidgets[button] = widget
|
||||||
widget:focus()
|
widget:focus()
|
||||||
widget:bubbleEvent('PressStart', {
|
widget:bubbleEvent('PressStart', {
|
||||||
|
hit = hit,
|
||||||
button = button,
|
button = button,
|
||||||
accelerator = accelerator,
|
accelerator = accelerator,
|
||||||
x = x, y = y
|
x = x, y = y
|
||||||
})
|
})
|
||||||
|
return hit
|
||||||
end
|
end
|
||||||
|
|
||||||
function Input:handlePressEnd (button, x, y, widget, accelerator)
|
function Input:handlePressEnd (layout, button, x, y, widget, accelerator)
|
||||||
local widget = widget or self.layout:getWidgetAt(x, y)
|
local widget = widget or layout:getWidgetAt(x, y)
|
||||||
|
local hit = true
|
||||||
|
if not widget then
|
||||||
|
hit = nil
|
||||||
|
widget = layout.root
|
||||||
|
end
|
||||||
local originWidget = self.pressedWidgets[button]
|
local originWidget = self.pressedWidgets[button]
|
||||||
if not originWidget then return end
|
if not originWidget then return end
|
||||||
originWidget.pressed = nil
|
originWidget.pressed = nil
|
||||||
widget:bubbleEvent('PressEnd', {
|
widget:bubbleEvent('PressEnd', {
|
||||||
|
hit = hit,
|
||||||
origin = originWidget,
|
origin = originWidget,
|
||||||
accelerator = accelerator,
|
accelerator = accelerator,
|
||||||
button = button, x = x, y = y
|
button = button, x = x, y = y
|
||||||
})
|
})
|
||||||
if (widget == originWidget) then
|
if (widget == originWidget) then
|
||||||
widget:bubbleEvent('Press', {
|
widget:bubbleEvent('Press', {
|
||||||
|
hit = hit,
|
||||||
button = button,
|
button = button,
|
||||||
accelerator = accelerator,
|
accelerator = accelerator,
|
||||||
x = x, y = y
|
x = x, y = y
|
||||||
@@ -147,13 +205,24 @@ function Input:handlePressEnd (button, x, y, widget, accelerator)
|
|||||||
end
|
end
|
||||||
self.pressedWidgets[button] = nil
|
self.pressedWidgets[button] = nil
|
||||||
self.passedWidgets[button] = nil
|
self.passedWidgets[button] = nil
|
||||||
|
return hit
|
||||||
end
|
end
|
||||||
|
|
||||||
function Input:handleReshape (width, height)
|
function Input:handleReshape (layout, width, height)
|
||||||
local root = self.layout.root
|
local root = layout.root
|
||||||
|
|
||||||
|
Event.Reshape:emit(layout, {
|
||||||
|
target = layout
|
||||||
|
})
|
||||||
|
|
||||||
|
if root.float then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
root.width = width
|
root.width = width
|
||||||
root.height = height
|
root.height = height
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Input.default = Input()
|
||||||
|
|
||||||
return Input
|
return Input
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
--[[--
|
--[[--
|
||||||
Layout class.
|
A Layout contains a tree of widgets with a single `root` widget.
|
||||||
|
|
||||||
|
Layouts will resize to fit the window unless a `top` or `left`
|
||||||
|
property is found in the root widget.
|
||||||
|
|
||||||
|
Layouts are drawn in the order that they were shown, so the
|
||||||
|
most recently shown layout shown will always appear on top.
|
||||||
|
|
||||||
|
Other events are sent to layouts in the opposite direction,
|
||||||
|
and are trapped by the first layout that can handle the event
|
||||||
|
(for example, the topmost layer that is focused or hovered).
|
||||||
|
|
||||||
@classmod Layout
|
@classmod Layout
|
||||||
--]]--
|
--]]--
|
||||||
@@ -15,6 +25,8 @@ local Hooker = require(ROOT .. 'hooker')
|
|||||||
|
|
||||||
local Layout = Base:extend()
|
local Layout = Base:extend()
|
||||||
|
|
||||||
|
Layout.isLayout = true
|
||||||
|
|
||||||
--[[--
|
--[[--
|
||||||
Layout constructor.
|
Layout constructor.
|
||||||
|
|
||||||
@@ -32,8 +44,7 @@ function Layout:constructor (data)
|
|||||||
self:setStyle()
|
self:setStyle()
|
||||||
self:setTheme(require(ROOT .. 'theme.light'))
|
self:setTheme(require(ROOT .. 'theme.light'))
|
||||||
|
|
||||||
self.isMousePressed = false
|
self.isShown = false
|
||||||
self.isManagingInput = false
|
|
||||||
self.hooks = {}
|
self.hooks = {}
|
||||||
self.root = data or {}
|
self.root = data or {}
|
||||||
Widget(self, self.root)
|
Widget(self, self.root)
|
||||||
@@ -71,20 +82,17 @@ Show the layout.
|
|||||||
Hooks all appropriate Love events and callbacks.
|
Hooks all appropriate Love events and callbacks.
|
||||||
--]]--
|
--]]--
|
||||||
function Layout:show ()
|
function Layout:show ()
|
||||||
|
if self.isShown then
|
||||||
|
self:unhook() -- return
|
||||||
|
self.isShown = nil
|
||||||
|
end
|
||||||
local root = self.root
|
local root = self.root
|
||||||
local width = root.width
|
|
||||||
local height = root.height
|
|
||||||
local title = root.title
|
|
||||||
if not self.input then
|
if not self.input then
|
||||||
self.input = Input(self)
|
self.input = Input.default -- Input(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
local currentWidth, currentHeight, flags = love.window.getMode()
|
self:manageInput()
|
||||||
love.window.setMode(width or currentWidth, height or currentHeight, flags)
|
|
||||||
if title then
|
|
||||||
love.window.setTitle(title)
|
|
||||||
end
|
|
||||||
self:manageInput(self.input)
|
|
||||||
root:reshape()
|
root:reshape()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -94,10 +102,10 @@ Hide the layout.
|
|||||||
Unhooks Love events and callbacks.
|
Unhooks Love events and callbacks.
|
||||||
--]]--
|
--]]--
|
||||||
function Layout:hide ()
|
function Layout:hide ()
|
||||||
if not self.isManagingInput then
|
if not self.isShown then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self.isManagingInput = false
|
self.isShown = nil
|
||||||
self:unhook()
|
self:unhook()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -163,7 +171,7 @@ function Layout:getWidgetAt (x, y, root)
|
|||||||
if inner then return inner end
|
if inner then return inner end
|
||||||
end
|
end
|
||||||
if widget:isAt(x, y) then return widget end
|
if widget:isAt(x, y) then return widget end
|
||||||
if widget == self.root then return widget end
|
-- if widget == self.root then return widget end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Internal, called from Widget:new
|
-- Internal, called from Widget:new
|
||||||
@@ -233,8 +241,8 @@ end
|
|||||||
|
|
||||||
-- event stuff
|
-- event stuff
|
||||||
|
|
||||||
function Layout:hook (key, method)
|
function Layout:hook (key, method, hookLast)
|
||||||
self.hooks[#self.hooks + 1] = Hooker.hook(love, key, method)
|
self.hooks[#self.hooks + 1] = Hooker.hook(love, key, method, hookLast)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Layout:unhook ()
|
function Layout:unhook ()
|
||||||
@@ -244,7 +252,7 @@ function Layout:unhook ()
|
|||||||
self.hooks = {}
|
self.hooks = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
local getMouseButtonId
|
local getMouseButtonId, isMouseDown
|
||||||
|
|
||||||
if love._version_minor < 10 then
|
if love._version_minor < 10 then
|
||||||
getMouseButtonId = function (value)
|
getMouseButtonId = function (value)
|
||||||
@@ -252,47 +260,56 @@ if love._version_minor < 10 then
|
|||||||
or value == 'r' and 2
|
or value == 'r' and 2
|
||||||
or value == 'm' and 3
|
or value == 'm' and 3
|
||||||
end
|
end
|
||||||
|
isMouseDown = function ()
|
||||||
|
return love.mouse.isDown('l', 'r', 'm')
|
||||||
|
end
|
||||||
else
|
else
|
||||||
getMouseButtonId = function (value)
|
getMouseButtonId = function (value)
|
||||||
return value
|
return value
|
||||||
end
|
end
|
||||||
|
isMouseDown = function ()
|
||||||
|
return love.mouse.isDown(1, 2, 3)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Layout:manageInput (input)
|
function Layout:manageInput ()
|
||||||
if self.isManagingInput then
|
if self.isShown then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
self.isManagingInput = true
|
self.isShown = true
|
||||||
|
|
||||||
|
local input = self.input
|
||||||
|
|
||||||
self:hook('draw', function ()
|
self:hook('draw', function ()
|
||||||
input:handleDisplay()
|
input:handleDisplay(self)
|
||||||
end)
|
end, true)
|
||||||
self:hook('resize', function (width, height)
|
self:hook('resize', function (width, height)
|
||||||
return input:handleReshape(width, height)
|
return input:handleReshape(self, width, height)
|
||||||
end)
|
end)
|
||||||
self:hook('mousepressed', function (x, y, button)
|
self:hook('mousepressed', function (x, y, button)
|
||||||
self.isMousePressed = true
|
return input:handlePressStart(self, getMouseButtonId(button), x, y)
|
||||||
return input:handlePressStart(getMouseButtonId(button), x, y)
|
|
||||||
end)
|
end)
|
||||||
self:hook('mousereleased', function (x, y, button)
|
self:hook('mousereleased', function (x, y, button)
|
||||||
self.isMousePressed = false
|
return input:handlePressEnd(self, getMouseButtonId(button), x, y)
|
||||||
return input:handlePressEnd(getMouseButtonId(button), x, y)
|
|
||||||
end)
|
end)
|
||||||
self:hook('mousemoved', function (x, y, dx, dy)
|
self:hook('mousemoved', function (x, y, dx, dy)
|
||||||
if self.isMousePressed then
|
if isMouseDown() then
|
||||||
return input:handlePressedMove(x, y)
|
return input:handlePressedMove(self, x, y)
|
||||||
else
|
else
|
||||||
return input:handleMove(x, y)
|
return input:handleMove(self, x, y)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
self:hook('keypressed', function (key, isRepeat)
|
self:hook('keypressed', function (key, isRepeat)
|
||||||
return input:handleKeyPress(key, love.mouse.getX(), love.mouse.getY())
|
return input:handleKeyPress(
|
||||||
|
self, key, love.mouse.getX(), love.mouse.getY())
|
||||||
end)
|
end)
|
||||||
self:hook('keyreleased', function (key)
|
self:hook('keyreleased', function (key)
|
||||||
return input:handleKeyRelease(key, love.mouse.getX(), love.mouse.getY())
|
return input:handleKeyRelease(
|
||||||
|
self, key, love.mouse.getX(), love.mouse.getY())
|
||||||
end)
|
end)
|
||||||
self:hook('textinput', function (text)
|
self:hook('textinput', function (text)
|
||||||
return input:handleTextInput(text, love.mouse.getX(), love.mouse.getY())
|
return input:handleTextInput(
|
||||||
|
self, text, love.mouse.getX(), love.mouse.getY())
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,9 @@ function Style:eachName (object)
|
|||||||
end
|
end
|
||||||
return function ()
|
return function ()
|
||||||
if not checkLookupProp() then return end
|
if not checkLookupProp() then return end
|
||||||
local specialName = getSpecialName { 'pressed', 'focused', 'hovered' }
|
local specialName = getSpecialName {
|
||||||
|
'pressed', 'focused', 'hovered', 'active',
|
||||||
|
}
|
||||||
if specialName then return specialName end
|
if specialName then return specialName end
|
||||||
lookupPropIndex = lookupPropIndex + 1
|
lookupPropIndex = lookupPropIndex + 1
|
||||||
return lookupProp[lookupPropIndex]
|
return lookupProp[lookupPropIndex]
|
||||||
|
|||||||
@@ -25,6 +25,21 @@ return function (config)
|
|||||||
button_pressed = {
|
button_pressed = {
|
||||||
slices = RESOURCE .. 'button_pressed.png',
|
slices = RESOURCE .. 'button_pressed.png',
|
||||||
},
|
},
|
||||||
|
menu = {
|
||||||
|
height = 24,
|
||||||
|
},
|
||||||
|
['menu.item'] = {
|
||||||
|
padding = 4,
|
||||||
|
align = 'left middle',
|
||||||
|
},
|
||||||
|
['menu.item_active'] = {
|
||||||
|
background = highlight,
|
||||||
|
},
|
||||||
|
submenu = {
|
||||||
|
padding = 10,
|
||||||
|
margin = -10,
|
||||||
|
slices = RESOURCE .. 'submenu.png',
|
||||||
|
},
|
||||||
sash = {
|
sash = {
|
||||||
background = lineColor
|
background = lineColor
|
||||||
},
|
},
|
||||||
@@ -46,7 +61,7 @@ return function (config)
|
|||||||
minwidth = 24,
|
minwidth = 24,
|
||||||
minheight = 24
|
minheight = 24
|
||||||
},
|
},
|
||||||
progressInner = {
|
['progress.bar'] = {
|
||||||
slices = RESOURCE .. 'progress.png',
|
slices = RESOURCE .. 'progress.png',
|
||||||
padding = 0,
|
padding = 0,
|
||||||
minwidth = 12,
|
minwidth = 12,
|
||||||
|
|||||||
BIN
luigi/theme/light/submenu.png
Normal file
BIN
luigi/theme/light/submenu.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 786 B |
@@ -17,6 +17,8 @@ Widget.isWidget = true
|
|||||||
|
|
||||||
Widget.typeDecorators = {
|
Widget.typeDecorators = {
|
||||||
button = require(ROOT .. 'widget.button'),
|
button = require(ROOT .. 'widget.button'),
|
||||||
|
menu = require(ROOT .. 'widget.menu'),
|
||||||
|
['menu.item'] = require(ROOT .. 'widget.menu.item'),
|
||||||
progress = require(ROOT .. 'widget.progress'),
|
progress = require(ROOT .. 'widget.progress'),
|
||||||
sash = require(ROOT .. 'widget.sash'),
|
sash = require(ROOT .. 'widget.sash'),
|
||||||
slider = require(ROOT .. 'widget.slider'),
|
slider = require(ROOT .. 'widget.slider'),
|
||||||
@@ -55,14 +57,14 @@ local function metaNewIndex (self, property, value)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if property == 'width' then
|
if property == 'width' then
|
||||||
value = math.max(value, self.minwidth or 0)
|
value = value and math.max(value, self.minwidth or 0)
|
||||||
self.shadowProperties[property] = value
|
self.shadowProperties[property] = value
|
||||||
Widget.reshape(self.parent or self)
|
Widget.reshape(self.parent or self)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if property == 'height' then
|
if property == 'height' then
|
||||||
value = math.max(value, self.minheight or 0)
|
value = value and math.max(value, self.minheight or 0)
|
||||||
self.shadowProperties[property] = value
|
self.shadowProperties[property] = value
|
||||||
Widget.reshape(self.parent or self)
|
Widget.reshape(self.parent or self)
|
||||||
return
|
return
|
||||||
@@ -89,7 +91,7 @@ A Widget instance.
|
|||||||
local function metaCall (Widget, layout, self)
|
local function metaCall (Widget, layout, self)
|
||||||
self = self or {}
|
self = self or {}
|
||||||
self.layout = layout
|
self.layout = layout
|
||||||
self.children = {}
|
self.children = self.children or {}
|
||||||
self.position = { x = nil, y = nil }
|
self.position = { x = nil, y = nil }
|
||||||
self.dimensions = { width = nil, height = nil }
|
self.dimensions = { width = nil, height = nil }
|
||||||
self.shadowProperties = {}
|
self.shadowProperties = {}
|
||||||
@@ -295,6 +297,7 @@ function Widget:addChild (data)
|
|||||||
|
|
||||||
table.insert(self.children, child)
|
table.insert(self.children, child)
|
||||||
child.parent = self
|
child.parent = self
|
||||||
|
child.layout = self.layout
|
||||||
|
|
||||||
return child
|
return child
|
||||||
end
|
end
|
||||||
@@ -375,8 +378,9 @@ function Widget:calculatePosition (axis)
|
|||||||
end
|
end
|
||||||
local parent = self.parent
|
local parent = self.parent
|
||||||
if not parent then
|
if not parent then
|
||||||
self.position[axis] = 0
|
self.position[axis] = axis == 'x' and (self.left or 0)
|
||||||
return 0
|
or axis == 'y' and (self.top or 0)
|
||||||
|
return self.position[axis]
|
||||||
end
|
end
|
||||||
local parentPos = parent:calculatePosition(axis)
|
local parentPos = parent:calculatePosition(axis)
|
||||||
local p = parentPos
|
local p = parentPos
|
||||||
@@ -555,7 +559,7 @@ function Widget:isAt (x, y)
|
|||||||
checkReshape(self)
|
checkReshape(self)
|
||||||
|
|
||||||
local x1, y1, x2, y2 = self:getRectangle()
|
local x1, y1, x2, y2 = self:getRectangle()
|
||||||
return (x1 < x) and (x2 > x) and (y1 < y) and (y2 > y)
|
return (x1 <= x) and (x2 >= x) and (y1 <= y) and (y2 >= y)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Widget:eachAncestor (includeSelf)
|
function Widget:eachAncestor (includeSelf)
|
||||||
|
|||||||
9
luigi/widget/menu.lua
Normal file
9
luigi/widget/menu.lua
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
return function (self)
|
||||||
|
|
||||||
|
for index, child in ipairs(self) do
|
||||||
|
child.type = child.type or 'menu.item'
|
||||||
|
child.parentMenu = self
|
||||||
|
child.rootMenu = self
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
169
luigi/widget/menu/item.lua
Normal file
169
luigi/widget/menu/item.lua
Normal file
@@ -0,0 +1,169 @@
|
|||||||
|
local ROOT = (...):gsub('[^.]*.[^.]*.[^.]*$', '')
|
||||||
|
|
||||||
|
local Layout
|
||||||
|
|
||||||
|
local show
|
||||||
|
|
||||||
|
local function deactivateSiblings (target)
|
||||||
|
local sibling = target.parent and target.parent.children[1]
|
||||||
|
local wasSiblingOpen
|
||||||
|
|
||||||
|
if not sibling then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
while sibling do
|
||||||
|
local layout = sibling.menuLayout
|
||||||
|
|
||||||
|
sibling.active = nil
|
||||||
|
|
||||||
|
if layout and layout.isShown then
|
||||||
|
wasSiblingOpen = true
|
||||||
|
layout:hide()
|
||||||
|
end
|
||||||
|
|
||||||
|
if sibling.items and sibling.items[1] then
|
||||||
|
deactivateSiblings(sibling.items[1])
|
||||||
|
end
|
||||||
|
|
||||||
|
sibling = sibling:getNextSibling()
|
||||||
|
end
|
||||||
|
|
||||||
|
return wasSiblingOpen
|
||||||
|
end
|
||||||
|
|
||||||
|
local function activate (event, ignoreIfNoneOpen)
|
||||||
|
local target = event.target
|
||||||
|
|
||||||
|
while target.parent
|
||||||
|
and target.parent.type ~= 'menu' and target.parent.type ~= 'submenu' do
|
||||||
|
target = target.parent
|
||||||
|
if not target then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local wasSiblingOpen = deactivateSiblings(target)
|
||||||
|
local ignore = ignoreIfNoneOpen and not wasSiblingOpen
|
||||||
|
|
||||||
|
if not ignore then
|
||||||
|
show(target)
|
||||||
|
target.active = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
show = function (self)
|
||||||
|
if not self.items or #self.items < 1 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if self.menuLayout then
|
||||||
|
self.menuLayout:show()
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local Layout = Layout or require(ROOT .. 'layout')
|
||||||
|
|
||||||
|
local isSubmenu = self.parentMenu and self.parentMenu.parentMenu
|
||||||
|
|
||||||
|
local x = isSubmenu and self:getWidth() or 0
|
||||||
|
local y = isSubmenu and 0 or self:getHeight()
|
||||||
|
|
||||||
|
local menuLayout = Layout {
|
||||||
|
type = 'submenu',
|
||||||
|
left = self:getX() + x,
|
||||||
|
top = self:getY() + y,
|
||||||
|
width = 0,
|
||||||
|
height = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
local root = menuLayout.root
|
||||||
|
|
||||||
|
local rootPad = root.padding or 0
|
||||||
|
|
||||||
|
local textWidth = 0
|
||||||
|
local keyWidth = 0
|
||||||
|
|
||||||
|
for index, child in ipairs(self.items) do
|
||||||
|
child.type = child.type or 'menu.item'
|
||||||
|
root:addChild(child)
|
||||||
|
local h = child:getHeight()
|
||||||
|
root.height = root:getHeight() + h
|
||||||
|
if child.type == 'menu.item' then
|
||||||
|
local pad = child.padding or 0
|
||||||
|
local tw = child.fontData:getAdvance(child.children[2].text)
|
||||||
|
+ pad * 2 + h
|
||||||
|
local kw = child.fontData:getAdvance(child.children[3].text)
|
||||||
|
+ pad * 2
|
||||||
|
textWidth = math.max(textWidth, tw)
|
||||||
|
keyWidth = math.max(keyWidth, kw)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
root.width = textWidth + keyWidth + rootPad
|
||||||
|
|
||||||
|
menuLayout:onReshape(function (event)
|
||||||
|
menuLayout:hide()
|
||||||
|
deactivateSiblings(self.rootMenu.children[1])
|
||||||
|
end)
|
||||||
|
|
||||||
|
menuLayout:onPressStart(function (event)
|
||||||
|
if not event.hit then
|
||||||
|
menuLayout:hide()
|
||||||
|
deactivateSiblings(self.rootMenu.children[1])
|
||||||
|
end
|
||||||
|
activate(event)
|
||||||
|
end)
|
||||||
|
|
||||||
|
menuLayout:onEnter(activate)
|
||||||
|
|
||||||
|
menuLayout:onPressEnter(activate)
|
||||||
|
|
||||||
|
menuLayout:show()
|
||||||
|
|
||||||
|
self.menuLayout = menuLayout
|
||||||
|
end
|
||||||
|
|
||||||
|
local function extractChild (self, index, child)
|
||||||
|
self[index] = nil
|
||||||
|
self.items[#self.items + 1] = child
|
||||||
|
child.parentMenu = self
|
||||||
|
child.rootMenu = self.rootMenu
|
||||||
|
child.type = child.type or 'menu.item'
|
||||||
|
end
|
||||||
|
|
||||||
|
return function (self)
|
||||||
|
local pad = self.padding or 0
|
||||||
|
local isSubmenu = self.parentMenu and self.parentMenu.parentMenu
|
||||||
|
local text, key, icon = self.text or '', self.key or '', self.icon
|
||||||
|
local textWidth = self.fontData:getAdvance(text) + pad * 2
|
||||||
|
|
||||||
|
self.items = self.items or {}
|
||||||
|
|
||||||
|
for index, child in ipairs(self) do
|
||||||
|
extractChild(self, index, child)
|
||||||
|
end
|
||||||
|
|
||||||
|
if isSubmenu then
|
||||||
|
self.height = self.fontData:getLineHeight() + pad * 2
|
||||||
|
self.flow = 'x'
|
||||||
|
self:addChild({ icon = icon, width = self.height })
|
||||||
|
self:addChild({ text = text, width = textWidth })
|
||||||
|
self:addChild({ text = key, align = 'right', minwidth = self.height })
|
||||||
|
|
||||||
|
self.icon = nil
|
||||||
|
self.text = nil
|
||||||
|
else
|
||||||
|
self.width = textWidth
|
||||||
|
end
|
||||||
|
|
||||||
|
self:onPressStart(activate)
|
||||||
|
|
||||||
|
self:onEnter(function (event)
|
||||||
|
activate(event, true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
self:onPressEnter(function (event)
|
||||||
|
activate(event, true)
|
||||||
|
end)
|
||||||
|
|
||||||
|
end
|
||||||
@@ -3,7 +3,7 @@ return function (self)
|
|||||||
self.flow = 'x' -- TODO: support vertical progress?
|
self.flow = 'x' -- TODO: support vertical progress?
|
||||||
|
|
||||||
local bar = self:addChild {
|
local bar = self:addChild {
|
||||||
type = 'progressInner',
|
type = 'progress.bar',
|
||||||
width = 0,
|
width = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user