237 lines
5.3 KiB
Lua
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
|