mirror of
https://codeberg.org/1414codeforge/yui.git
synced 2025-06-05 22:19:11 +02:00
[*] General code improvement.
* Rework navigation allowing direct management and triggering for grabkeyboard widgets. * Navigation code now behaves better with deeply nested layouts. * Allow widget hierarchies deeper than 2 (__call() is implemented for every Widget metatable). * Make BASE locals more secure (match '<filename>$' in regexp)
This commit is contained in:
185
layout.lua
185
layout.lua
@ -1,4 +1,4 @@
|
||||
local BASE = (...):gsub('layout', '')
|
||||
local BASE = (...):gsub('layout$', '')
|
||||
|
||||
local Widget = require(BASE..'widget')
|
||||
local core = require(BASE..'core')
|
||||
@ -9,7 +9,9 @@ local isinstance = gear.meta.isinstance
|
||||
local rectunion = gear.rect.union
|
||||
local pointinrect = gear.rect.pointinside
|
||||
|
||||
local Layout = setmetatable({}, Widget)
|
||||
local Layout = setmetatable({
|
||||
__call = function(cls, args) return cls.new(args) end
|
||||
}, Widget)
|
||||
Layout.__index = Layout
|
||||
|
||||
|
||||
@ -113,21 +115,6 @@ function Layout:layoutWidgets()
|
||||
self.h = math.max(rh, 0)
|
||||
end
|
||||
|
||||
function Layout:onPointerInput(px,py, clicked, down)
|
||||
local stack = self.stack
|
||||
|
||||
-- Propagate pointer event from topmost widget to bottom
|
||||
for i = #stack,1,-1 do
|
||||
local widget = stack[i]
|
||||
local x,y,w,h = widget.x,widget.y,widget.w,widget.h
|
||||
|
||||
if pointinrect(px,py, x,y,w,h) then
|
||||
widget:onPointerInput(px,py, clicked, down)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Find layout's child containing the provided widget.
|
||||
local function childof(layout, widget)
|
||||
local parent = widget.parent
|
||||
@ -137,98 +124,27 @@ local function childof(layout, widget)
|
||||
end
|
||||
return widget
|
||||
end
|
||||
local function findfirst(widget)
|
||||
while isinstance(widget, Layout) do
|
||||
-- Find first element accepting focus
|
||||
for i = 1,#widget do
|
||||
if not widget[i].nofocus then
|
||||
widget = widget[i]
|
||||
break
|
||||
end
|
||||
local function scanforward(layout, from)
|
||||
from = from or 1
|
||||
|
||||
for i = from,#layout do
|
||||
local w = layout[i]
|
||||
|
||||
if not w.nofocus then
|
||||
return isinstance(w, Layout) and scanforward(w) or w
|
||||
end
|
||||
end
|
||||
return widget
|
||||
end
|
||||
local function findnext(layout, widget)
|
||||
local child = childof(layout, widget)
|
||||
local function scanbackwards(layout, from)
|
||||
from = from or #layout
|
||||
|
||||
for i,w in ipairs(layout) do
|
||||
if w == child then
|
||||
-- Search to the right, wraparound to the left
|
||||
for j = i+1,#layout do
|
||||
if not layout[j].nofocus then
|
||||
return findfirst(layout[j])
|
||||
end
|
||||
end
|
||||
for j = 1,i-1 do
|
||||
if not layout[j].nofocus then
|
||||
return findfirst(layout[j])
|
||||
end
|
||||
end
|
||||
for i = from,1,-1 do
|
||||
local w = layout[i]
|
||||
|
||||
if not w.nofocus then
|
||||
return isinstance(w, Layout) and scanforward(w) or w
|
||||
end
|
||||
end
|
||||
return widget
|
||||
end
|
||||
local function findprev(layout, widget)
|
||||
local child = childof(layout, widget)
|
||||
|
||||
for i,w in ipairs(layout) do
|
||||
if w == child then
|
||||
-- Search to the left, wraparound to the right
|
||||
for j = i-1,1,-1 do
|
||||
if not layout[j].nofocus then
|
||||
return findfirst(layout[j])
|
||||
end
|
||||
end
|
||||
for j = #layout,i+1,-1 do
|
||||
if not layout[j].nofocus then
|
||||
return findfirst(layout[j])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return widget
|
||||
end
|
||||
|
||||
function Layout:firstFocusableWidget()
|
||||
return findfirst(self)
|
||||
end
|
||||
function Layout:nextFocusableWidget()
|
||||
return findnext(self, self.ui.focused)
|
||||
end
|
||||
function Layout:previousFocusableWidget()
|
||||
return findprev(self, self.ui.focused)
|
||||
end
|
||||
|
||||
function Layout:onActionInput(action)
|
||||
local handled = false
|
||||
|
||||
if action[self.next] then
|
||||
local n = self:nextFocusableWidget()
|
||||
|
||||
n:grabFocus()
|
||||
handled = true
|
||||
end
|
||||
if action[self.prev] then
|
||||
local p = self:previousFocusableWidget()
|
||||
|
||||
p:grabFocus()
|
||||
handled = true
|
||||
end
|
||||
return handled
|
||||
end
|
||||
|
||||
function Layout:update(dt)
|
||||
for _,widget in ipairs(self.stack) do
|
||||
widget:update(dt)
|
||||
end
|
||||
end
|
||||
|
||||
function Layout:draw()
|
||||
-- Draw all children according to their order (topmost last)
|
||||
for _,widget in ipairs(self.stack) do
|
||||
widget:draw()
|
||||
end
|
||||
end
|
||||
|
||||
function Layout.new(args)
|
||||
@ -245,7 +161,70 @@ function Layout.new(args)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- Find first widget in layout accepting focus.
|
||||
function Layout:first()
|
||||
return scanforward(self)
|
||||
end
|
||||
|
||||
--- Find last widget in layout accepting focus.
|
||||
function Layout:last()
|
||||
return scanbackwards(self)
|
||||
end
|
||||
|
||||
--- Find next focusable widget after the provided one.
|
||||
function Layout:after(widget)
|
||||
widget = childof(self, widget)
|
||||
|
||||
for i = 1,#self do
|
||||
if self[i] == widget then
|
||||
-- Search to the right/down
|
||||
return scanforward(self, i+1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Find previous focusable widget before the provided one.
|
||||
function Layout:before(widget)
|
||||
widget = childof(self, widget)
|
||||
|
||||
for i = 1,#self do
|
||||
if self[i] == widget then
|
||||
-- Search to the left/up
|
||||
return scanbackwards(self, i-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Layout:onPointerInput(px,py, clicked, down)
|
||||
local stack = self.stack
|
||||
|
||||
-- Propagate pointer event from topmost widget to bottom
|
||||
for i = #stack,1,-1 do
|
||||
local widget = stack[i]
|
||||
local x,y,w,h = widget.x,widget.y,widget.w,widget.h
|
||||
|
||||
if pointinrect(px,py, x,y,w,h) then
|
||||
widget:onPointerInput(px,py, clicked, down)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Layout:update(dt)
|
||||
for _,widget in ipairs(self.stack) do
|
||||
widget:update(dt)
|
||||
end
|
||||
end
|
||||
|
||||
function Layout:draw()
|
||||
-- Draw all children according to their order (topmost last)
|
||||
for _,widget in ipairs(self.stack) do
|
||||
widget:draw()
|
||||
end
|
||||
end
|
||||
|
||||
return Layout
|
||||
|
Reference in New Issue
Block a user