dobrograd-13-06-2022/garrysmod/addons/util-dlib/lua/dlib/vgui/button_layout.lua
Jonny_Bro (Nikita) e4d5311906 first commit
2023-11-16 15:01:19 +05:00

237 lines
5.3 KiB
Lua

-- Copyright (C) 2017-2020 DBotThePony
-- Permission is hereby granted, free of charge, to any person obtaining a copy
-- of this software and associated documentation files (the "Software"), to deal
-- in the Software without restriction, including without limitation the rights
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-- of the Software, and to permit persons to whom the Software is furnished to do so,
-- subject to the following conditions:
-- The above copyright notice and this permission notice shall be included in all copies
-- or substantial portions of the Software.
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
-- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
-- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
-- FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
-- DEALINGS IN THE SOFTWARE.
--[[
@doc
@panel DLib_ButtonLayout
@parent DScrollPanel
@desc
A grid of panels which must expose `:Populate(parent)` method
Can be useful with !p:DLib_PlayerButton
@enddesc
]]
local PANEL = {}
DLib.VGUI.ButtonLayout = PANEL
local function AccessorFunc(PANEL, varName, getset)
PANEL['Get' .. getset] = function(self)
return self[varName]
end
PANEL['Set' .. getset] = function(self, newVal)
local old = self[varName]
self[varName] = newVal
self['On' .. getset .. 'Changes'](self, old, newVal)
end
end
--[[
@docpreprocess
const names = [
'SpacingX',
'SpacingY',
'LayoutSizeX',
'LayoutSizeY'
]
const reply = []
for (const name of names) {
let output = []
output.push(`@fname DLib_ButtonLayout:Get${name}`)
output.push(`@returns`)
output.push(`number`)
reply.push(output)
output = []
output.push(`@fname DLib_ButtonLayout:Set${name}`)
output.push(`@args number value`)
reply.push(output)
output = []
output.push(`@fname DLib_ButtonLayout:On${name}Changes`)
output.push(`@args number oldvalue, number newvalue`)
reply.push(output)
}
return reply
]]
AccessorFunc(PANEL, 'spacingX', 'SpacingX')
AccessorFunc(PANEL, 'spacingY', 'SpacingY')
AccessorFunc(PANEL, 'layoutSizeX', 'LayoutSizeX')
AccessorFunc(PANEL, 'layoutSizeY', 'LayoutSizeY')
function PANEL:Init()
self.layoutSizeX = 128
self.layoutSizeY = 96
self.buttons = {}
self.buttonsPositions = {}
self.spacingX = 4
self.spacingY = 4
self:SetSkin('DLib_Black')
end
function PANEL:SetLayoutSize(x, y)
self.layoutSizeX, self.layoutSizeY = x, y
self:InvalidateLayout()
end
function PANEL:OnSpacingXChanges()
self:InvalidateLayout()
end
function PANEL:OnSpacingYChanges()
self:InvalidateLayout()
end
function PANEL:OnLayoutSizeXChanges()
self:InvalidateLayout()
end
function PANEL:OnLayoutSizeYChanges()
self:InvalidateLayout()
end
--[[
@doc
@fname DLib_ButtonLayout:AddButton
@args Panel button
]]
function PANEL:AddButton(button)
table.insert(self.buttons, button)
button:SetParent(self:GetCanvas())
button:SetSize(self.layoutSizeX, self.layoutSizeY)
button.__dlibIsPopulated = false
self:InvalidateLayout()
end
--[[
@doc
@fname DLib_ButtonLayout:GetVisibleArea
@returns
number: top y
number: bottom y
]]
function PANEL:GetVisibleArea()
local scroll = self:GetVBar():GetScroll()
return scroll - self.layoutSizeY, scroll + self:GetTall()
end
--[[
@doc
@fname DLib_ButtonLayout:GetVisibleButtons
@returns
table: array of Panels
]]
function PANEL:GetVisibleButtons()
local topx, bottomx = self:GetVisibleArea()
local reply = {}
for i, button in ipairs(self.buttonsPositions) do
local x, y = button.x, button.y
if y > topx and y < bottomx then
table.insert(reply, button.button)
end
end
return reply
end
--[[
@doc
@fname DLib_ButtonLayout:Clear
@desc
removes all buttons
@enddesc
]]
function PANEL:Clear()
for i, button in ipairs(self.buttons) do
button:Remove()
end
self.buttons = {}
self.__lastW, self.__lastH = nil, nil
self:InvalidateLayout()
end
--[[
@doc
@fname DLib_ButtonLayout:RebuildButtonsPositions
@args number width, number height
@internal
]]
function PANEL:RebuildButtonsPositions(w, h)
if not w or not h then return end
self.buttonsPositions = {}
local xm, ym = self.layoutSizeX + self.spacingX, self.layoutSizeY + self.spacingY
local line = 0
local row = 0
local limitX = math.max(math.floor(w / xm) - 1, 1)
for i, button in ipairs(self.buttons) do
if row > limitX then
row = 0
line = line + 1
end
local newx, newy = row * xm, line * ym
button:SetPos(newx, newy)
self.buttonsPositions[i] = {
button = button,
x = newx,
y = newy
}
row = row + 1
end
self:GetCanvas():SetSize(w, (line + 1) * ym)
return self.buttonsPositions
end
function PANEL:PerformLayout(width, height)
if width == self.__lastW and height == self.__lastH then return end
self.__lastW, self.__lastH = width, height
DScrollPanel.PerformLayout(self, width, height)
self:RebuildButtonsPositions(self:GetSize())
for i, button in ipairs(self:GetVisibleButtons()) do
if not button.__dlibIsPopulated then
button:Populate(self)
button.__dlibIsPopulated = true
end
end
end
vgui.Register('DLib_ButtonLayout', PANEL, 'DScrollPanel')
return PANEL