Files
wnsrc/lua/slib/vgui/cl_slistview.lua
lifestorm 9c918c46e5 Upload
2024-08-04 23:12:27 +03:00

294 lines
9.0 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local PANEL = {}
local font = slib.createFont("Roboto", 15)
local textcolor, maincolor_7, linecol, neutralcolor, margin = slib.getTheme("textcolor"), slib.getTheme("maincolor", 7), Color(24,24,24,160), slib.getTheme("neutralcolor"), slib.getTheme("margin")
function PANEL:Init()
self.Columns = self.Columns or {}
self.Lines = self.Lines or {}
self.columniteration = 0
self.lineiteration = 0
self.assortment = self.assortment or {}
slib.wrapFunction(self, "Dock", nil, function() return self end, true)
slib.wrapFunction(self, "SetSize", nil, function() return self end, true)
slib.wrapFunction(self, "Center", nil, function() return self end, true)
slib.wrapFunction(self, "SetPos", nil, function() return self end, true)
slib.wrapFunction(self, "MakePopup", nil, function() return self end, true)
end
function PANEL:getColumnPos(col)
local result = self.Columns[col]:GetPos()
return select(1, result)
end
function PANEL:getColumnWide(col)
return self.Columns[col]:GetWide()
end
local function differenciate(a, b)
if isfunction(a) then a = a() end
if isfunction(b) then b = b() end
if isnumber(tonumber(a)) and isnumber(tonumber(b)) then return tonumber(a), tonumber(b) end
if !(isstring(a) == isstring(b)) or isbool(a) or isbool(b) then
return tostring(a), tostring(b)
end
return a, b
end
function PANEL:addColumn(name)
if !IsValid(self.topbar) then
self.topbar = vgui.Create("EditablePanel", self)
self.topbar:Dock(TOP)
self.topbar:SetZPos(-32768)
self.topbar:SetTall(slib.getScaledSize(25, "y"))
self.topbar.Paint = function(s,w,h)
surface.SetDrawColor(maincolor_7)
surface.DrawRect(0, 0, w, h)
surface.SetDrawColor(linecol)
surface.DrawRect(0, h - 1, w - 1, 1)
end
end
self.columniteration = self.columniteration + 1
local iteration = self.columniteration
local ignoreWidth = false
if istable(name) then
if name[2] then
ignoreWidth = name[2]
end
name = name[1]
end
self.Columns[iteration] = vgui.Create("DButton", self.topbar)
self.Columns[iteration]:Dock(LEFT)
self.Columns[iteration]:SetWide(self:GetWide() / #self.Columns)
self.Columns[iteration].Width = self:GetWide() / #self.Columns
self.Columns[iteration]:SetText("")
self.Columns[iteration].name = name
self.Columns[iteration].iteration = iteration
self.Columns[iteration].ignoreWidth = ignoreWidth
self.Columns[iteration].DoClick = function()
if self.assortment.iteration == iteration then
self.assortment.ascending = !self.assortment.ascending
else
self.assortment.iteration = iteration
self.assortment.ascending = true
end
local basictable = {}
local cleantable = {}
for i=1,#self.Lines do
local tbl = self.Columns[iteration]["lines"][i]
local sortvalue = istable(tbl) and (tbl.sortvalue or tbl.text) or tbl
table.insert(basictable, sortvalue)
end
if self.assortment.ascending then
table.sort(basictable, function(a, b) a, b = differenciate(a, b) return a > b end)
else
table.sort(basictable, function(a, b) a, b = differenciate(a, b) return a < b end)
end
for i, z in pairs(basictable) do
cleantable[z] = i
end
for i=1,#self.Lines do
local tbl = self.Columns[iteration]["lines"][i]
local final = istable(tbl) and (tbl.sortvalue or tbl.text) or tbl
if !IsValid(self.Lines[i]) then continue end
self.Lines[i]:SetZPos(cleantable[final])
end
end
self.Columns[iteration].Paint = function(s,w,h)
draw.SimpleText(name, font, slib.getTheme("margin"), h * .5, textcolor, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
end
return self
end
function PANEL:addColumns(...)
local args = {...}
for k,v in pairs(args) do
self:addColumn(v)
end
return self
end
function PANEL:addLine(...)
local args = {...}
if !IsValid(self.frame) then
self.frame = vgui.Create("SScrollPanel", self)
self.frame:Dock(FILL)
self.frame:SetTall(slib.getScaledSize(25, "y"))
end
self.lineiteration = self.lineiteration + 1
local iteration = self.lineiteration
for k,v in ipairs(args) do
local display = istable(v) and v[1] or v
local sortingvalue
if istable(v) and v[2] then
sortingvalue = v[2]
end
self.Columns[k]["lines"] = self.Columns[k]["lines"] or {}
self.Columns[k]["lines"][iteration] = self.Columns[k]["lines"][iteration] or {}
self.Columns[k]["lines"][iteration]["text"] = display
if sortingvalue then
self.Columns[k]["lines"][iteration]["sortvalue"] = sortingvalue
end
end
self.Lines[iteration] = vgui.Create("DButton", self)
self.Lines[iteration]:Dock(TOP)
self.Lines[iteration]:SetTall(slib.getScaledSize(25, "y"))
self.Lines[iteration]:SetText("")
self.Lines[iteration].InitDoClick = self.Lines[iteration].DoClick
self.Lines[iteration].Think = function()
self.Lines[iteration]:SetMouseInputEnabled(self.Lines[iteration].DoClick ~= self.Lines[iteration].InitDoClick)
end
self.Lines[iteration].Paint = function(s,w,h)
local wantedcolor = neutralcolor
if !s:IsHovered() then
wantedcolor = table.Copy(wantedcolor)
wantedcolor.a = 0
end
surface.SetDrawColor(slib.lerpColor(s, wantedcolor))
surface.DrawRect(0, 0, w, h)
for i = 1,#self.Columns do
local display = self.Columns[i]["lines"][iteration].text
if isfunction(display) then
display = display()
end
local x,y = self:getColumnPos(i), h * .5
local w = self:getColumnWide(i)
if w < (self:getTextWidth(display, self.Columns[i].maxTxtLen) + margin * 2) then self:resizeColumns() end
if i == 1 then
s.name = display
end
if self.Columns[i].ignoreWidth or self.Columns[i].maxTxtLen then
surface.SetFont(font)
local txt_h = select(2, surface.GetTextSize(display))
local screen_x, screen_y = s:LocalToScreen(0,0)
render.SetScissorRect(screen_x + x, screen_y, screen_x + x + self.Columns[i]:GetWide() - margin, screen_y + h, true)
draw.SimpleText(display, font, x + slib.getTheme("margin"), y, textcolor, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
render.SetScissorRect(0, 0, 0, 0, false)
else
if self.Columns[i].customRender and self.Columns[i].customRender(x, 0, w, h, s) == true then return end
draw.SimpleText(display, font, x + slib.getTheme("margin"), y, textcolor, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER)
end
end
end
self:resizeColumns()
return self, self.Lines[iteration]
end
function PANEL:getTextWidth(txt, max)
txt = tostring(txt)
if max then
txt = string.sub(txt, 1, max)
end
surface.SetFont(font)
return surface.GetTextSize(txt)
end
function PANEL:resizeColumns()
local columnsizes = {}
local fullwidth = self:GetWide()
local spaceleft = 0
for k, v in pairs(self.Columns) do
local ignoreWidth = self.Columns[k].ignoreWidth
surface.SetFont(font)
local longest = self:getTextWidth(self.Columns[k].name)
if ignoreWidth then columnsizes[k] = isstring(ignoreWidth) and self:getTextWidth(ignoreWidth) or longest continue end
if !self.Columns[k]["lines"] then continue end
for i, z in pairs(self.Columns[k]["lines"]) do
local compare = isfunction(z.text) and z.text() or z.text
local width = self:getTextWidth(compare, self.Columns[k].maxTxtLen) + (slib.getTheme("margin") * 10)
if longest < width then longest = width end
end
columnsizes[k] = longest
end
local occupiedspace = 0
for k,v in pairs(columnsizes) do
occupiedspace = occupiedspace + v
end
for k,v in pairs(self.Columns) do
local v = columnsizes[k] or 0
local gapadd = (fullwidth - occupiedspace) / #self.Columns
self.Columns[k]:SetWide(v + gapadd)
end
end
function PANEL:OnSizeChanged()
self:resizeColumns()
end
function PANEL:PaintOver(w,h)
for k,v in pairs(self.Columns) do
if k >= #self.Columns then break end
local x,y = self:getColumnPos(k), h * .5
local w = self:getColumnWide(k)
surface.SetDrawColor(linecol)
surface.DrawRect(x + w - 1, 0, 1, h)
end
end
vgui.Register("SListView", PANEL, "SScrollPanel")