sortbox.lua
local SortBox = Geyser.Container:new({
name = "SortBoxClass",
autoSort = true,
timerSort = true,
sortInterval = 500,
elastic = false,
maxHeight = 0,
maxWidth = 0,
boxType = "v",
sortFunction = "gaugeValue",
})
local BIGNUMBER = 999999999
SortBox.SortFunctions = {
gaugeValue = function(t, a, b)
local avalue = t[a].value or BIGNUMBER
local bvalue = t[b].value or BIGNUMBER
return avalue < bvalue
end,
reverseGaugeValue = function(t, a, b)
local avalue = t[a].value or BIGNUMBER
local bvalue = t[b].value or BIGNUMBER
return avalue > bvalue
end,
timeLeft = function(t, a, b)
a = t[a]
b = t[b]
local avalue = a.getTime and tonumber(a:getTime("S.mm")) or BIGNUMBER
local bvalue = b.getTime and tonumber(b:getTime("S.mm")) or BIGNUMBER
return avalue < bvalue
end,
reverseTimeLeft = function(t, a, b)
a = t[a]
b = t[b]
local avalue = a.getTime and tonumber(a:getTime("S.mm")) or BIGNUMBER
local bvalue = b.getTime and tonumber(b:getTime("S.mm")) or BIGNUMBER
return avalue > bvalue
end,
name = function(t, a, b)
return t[a].name < t[b].name
end,
reverseName = function(t, a, b)
return t[a].name > t[b].name
end,
message = function(t, a, b)
a = t[a]
b = t[b]
local avalue = a.text and a.text.message or a.message
local bvalue = b.text and b.text.message or b.message
avalue = avalue or ""
bvalue = bvalue or ""
return avalue < bvalue
end,
reverseMessage = function(t, a, b)
a = t[a]
b = t[b]
local avalue = a.text and a.text.message or a.message
local bvalue = b.text and b.text.message or b.message
avalue = avalue or ""
bvalue = bvalue or ""
return avalue > bvalue
end,
}
function SortBox:new(options, container)
options = options or {}
options.type = options.type or "SortBox"
local me = self.parent:new(options, container)
setmetatable(me, self)
self.__index = self
if me.timerSort then
me:enableTimer()
end
me:setBoxType(me.boxType)
return me
end
local function spairs(t, order)
local keys = table.keys(t)
if order then
table.sort(keys, function(a, b)
return order(t, a, b)
end)
end
local i = 0
return function()
i = i + 1
if keys[i] then
return keys[i], t[keys[i]]
end
end
end
function SortBox:add(window, cons)
if self.useAdd2 then
Geyser.add2(self, window, cons)
else
Geyser.add(self, window, cons)
end
if not self.defer_updates then
self:organize()
end
end
function SortBox:remove(window)
Geyser.remove(self, window)
self:organize()
end
function SortBox:organize()
if self:get_width() == 0 then
self:resize("0.9px", nil)
end
if self:get_height() == 0 then
self:resize(nil, "0.9px")
end
if self.boxType == "v" then
self:vorganize()
else
self:horganize()
end
self:handleElastic()
end
function SortBox:horganize()
local window_width = (self:calculate_dynamic_window_size().width / self:get_width()) * 100
local start_x = 0
local sortFunction = (self.autoSort and self.sortFunction) and SortBox.SortFunctions[self.sortFunction] or nil
if sortFunction then
for _, window in spairs(self.windowList, sortFunction) do
start_x = start_x + self:handleWindow(window, start_x, window_width)
end
else
for _, window_name in ipairs(self.windows) do
local window = self.windowList[window_name]
start_x = start_x + self:handleWindow(window, start_x, window_width)
end
end
end
function SortBox:vorganize()
local window_height = (self:calculate_dynamic_window_size().height / self:get_height()) * 100
local start_y = 0
local sortFunction = (self.autoSort and self.sortFunction) and SortBox.SortFunctions[self.sortFunction] or nil
if sortFunction then
for _, window in spairs(self.windowList, sortFunction) do
start_y = start_y + self:handleWindow(window, start_y, window_height)
end
else
for _, window_name in ipairs(self.windows) do
local window = self.windowList[window_name]
start_y = start_y + self:handleWindow(window, start_y, window_height)
end
end
end
function SortBox:handleWindow(window, start, window_dimension)
local width = (window:get_width() / self:get_width()) * 100
local height = (window:get_height() / self:get_height()) * 100
if window.h_policy == Geyser.Fixed or window.v_policy == Geyser.Fixed then
self.contains_fixed = true
end
if self.boxType == "v" then
window:move("0%", start .. "%")
if window.h_policy == Geyser.Dynamic then
width = 100
if window.width ~= width then
window:resize(width .. "%", nil)
end
end
if window.v_policy == Geyser.Dynamic then
height = window_dimension * window.v_stretch_factor
if window.height ~= height then
window:resize(nil, height .. "%")
end
end
return height
else
window:move(start .. "%", "0%")
if window.h_policy == Geyser.Dynamic then
width = window_dimension * window.h_stretch_factor
if window.width ~= width then
window:resize(width .. "%", nil)
end
end
if window.v_policy == Geyser.Dynamic then
height = 100
if window.height ~= height then
window:resize(nil, height .. "%")
end
end
return width
end
end
function SortBox:handleElastic()
if not self.elastic or table.is_empty(self.windows) then
return
end
if self.boxType == "v" then
local contentHeight, canElastic = self:getContentHeight()
if not canElastic then
debugc(string.format("SortBox named %s cannot properly elasticize, as it contains at least one item with a dynamic v_policy", self.name))
return
end
local currentHeight = self:get_height()
local maxHeight = self.maxHeight
if maxHeight > 0 and contentHeight > maxHeight then
contentHeight = maxHeight
end
if contentHeight ~= currentHeight then
self:resize(nil, contentHeight)
end
else
local contentWidth, canElastic = self:getContentWidth()
if not canElastic then
debugc(string.format("SortBox named %s cannot properly elasticize, as it contains at least one item with a dynamic h_policy", self.name))
return
end
local currentWidth = self:get_width()
local maxWidth = self.maxWidth
if maxWidth > 0 and contentWidth > maxWidth then
contentWidth = maxWidth
end
if contentWidth ~= currentWidth then
self:resize(contentWidth, nil)
end
end
end
function SortBox:reposition()
Geyser.Container.reposition(self)
if self.contains_fixed then
self:organize()
end
end
function SortBox:getContentHeight()
if self.boxType ~= "v" then
return self:get_height()
end
local canElastic = true
local contentHeight = 0
for _, window in pairs(self.windowList) do
contentHeight = contentHeight + window:get_height()
if window.v_policy == Geyser.Dynamic then
canElastic = false
end
end
return contentHeight, canElastic
end
function SortBox:getContentWidth()
if self.boxType == "v" then
return self:get_width()
end
local canElastic = true
local contentWidth = 0
for _, window in pairs(self.windowList) do
contentWidth = contentWidth + window:get_width()
if window.h_policy == Geyser.Dynamic then
canElastic = false
end
end
return contentWidth, canElastic
end
function SortBox:enableElastic()
self:setElastic(true)
end
function SortBox:disableElastic()
self:setElastic(false)
end
function SortBox:setElastic(enabled)
self.elastic = enabled and true or false
end
function SortBox:setMaxWidth(maxWidth)
local mwtype = type(maxWidth)
assert(mwtype == "number", string.format("SortBox:setMaxWidth(maxWidth): SortBox: %s maxWidth as number expected, got %s", self.name, mwtype))
assert(maxWidth >= 0, string.format("SortBox:setMaxWidth(maxWidth): SortBox: %s maxWidth must be >= 0, %d", self.name, maxWidth))
self.maxWidth = maxWidth
end
function SortBox:setMaxHeight(maxHeight)
local mhtype = type(maxHeight)
assert(mhtype == "number", string.format("SortBox:setMaxHeight(maxHeight): SortBox: %s maxHeight as number expected, got %s", self.name, mhtype))
assert(maxHeight >= 0, string.format("SortBox:setMaxHeight(maxHeight): SortBox: %s maxHeight must be >= 0, %d", self.name, maxHeight))
self.maxHeight = maxHeight
end
function SortBox:enableTimer()
if self.timerID then
self:disableTimer()
end
self.timerSort = true
self.timerID = tempTimer(self.sortInterval / 1000, function()
self:organize()
end, true)
end
function SortBox:disableTimer()
killTimer(self.timerID)
self.timerID = nil
self.timerSort = false
end
function SortBox:setSortInterval(sortInterval)
local sitype = type(sortInterval)
assert(sitype == "number", string.format("SortBox:setSortInterval(sortInterval): sortInterval as number expected, got %s", sitype))
assert(sortInterval > 0, string.format("SortBox:setSortInterval(sortInterval): sortInterval must be positive"))
self.sortInterval = sortInterval
if self.timerSort then
self:enableTimer()
end
end
function SortBox:enableSort()
self.autoSort = true
self:organize()
end
function SortBox:disableSort()
self.autoSort = false
end
function SortBox:setBoxType(boxType)
boxType = boxType:lower()
if boxType == "h" or boxType == "horizontal" then
self.boxType = "h"
else
self.boxType = "v"
end
end
function SortBox:setSortFunction(functionName)
self.sortFunction = functionName
end
SortBox.parent = Geyser.Container
return SortBox